原创 FM收音机程序

2008-11-2 20:04 3549 5 6 分类: MCU/ 嵌入式

程序开始是参考OURAVR网友的例子成功收到台,由于程序生成的hex文件太大,2051装不下,只是放在博客发表,一直没有时间整理出来。后来深圳市广视美电子有限公司的老姜发了一份SP3767的参考代码给我,通过学习SP3767的代码,发现许多好的思路和方法,结合我自己开始写的程序,修修改改改成了现在的程序。


#include<reg51.H>
#include<math.h>
#include<I2C.c>


sbit KEY_0 = P1^2;    //S3键,自动向上收台
sbit KEY_1 = P1^3;    //S2键,自动向下收台
sbit KEY_2 = P1^4;    //S1键,手动收台
sbit have  = P3^7;    //收台标志,
sbit band  = P3^5;    //边界标志,表示频率到达最小或最大值           
#define max_freq 1080
#define min_freq 875
#define point 0xfe      //小数点


unsigned char code led_7[10]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09};  //0..9,数码管段码表                  
unsigned char dis_buff[4]={3,5,9,0};     //显示缓冲区,低位在前
unsigned char radio_write_data[5]={0x2d,0x56,0x20,0x11,0x00};       //要写入TEA5767的数据
unsigned char radio_read_data[5];        //TEA5767读出的状态
unsigned int default_pll=0x2d56;     //0x2d56;        //默认存台的pll,95.3MHz
unsigned int  pll;
unsigned long frequency = 935;
unsigned int max_pll=0x339b;            //108MHz时的pll,
unsigned int min_pll=0x9000;            //70MHz时的pll`


void uart_send_byte(unsigned char dat)
{
 SBUF = dat;
 while(TI == 0);             //循环等待
 TI = 0;
}


//由频率计算PLL
void get_pll(void)
{
    unsigned char hlsi;
    unsigned int twpll="0";
    hlsi="radio"_write_data[2]&0x10;
    if (hlsi)
        pll=((frequency * 100000) + 225000) >> 13;    //频率单位:k ;pll=(frequency+225)*4)/32.768
    else
        pll=((frequency * 100000) - 225000) >> 13;    //频率单位:k ;pll=(frequency-225)*4)/32.768
}


//由PLL计算频率
void get_frequency(void)
{
    unsigned char hlsi;
    unsigned int npll="0";
    npll="pll";
    hlsi="radio"_write_data[2]&0x10;
    if (hlsi)
        frequency=((((unsigned long)npll << 13) - 225000) / 100000) + 1;    //频率单位:KHz
    else
        frequency=((((unsigned long)npll << 13) + 225000) / 100000) + 1;    //频率单位:KHz
}


//频率值送显示缓冲区,低位在前
//       高  108.0 低  Mhz
//------------------
//位数:
void frequency_to_disbuff(void)
{
 //unsigned long fre;
 //fre=f/100;
 dis_buff[3]=frequency / 1000;     //第1位,1080/1000=1
 dis_buff[2]=frequency / 100 %10;   //第2位,1080/100=10,10%10=0
 dis_buff[1]=frequency % 100 /10;   //第3位, 1080%100=80,80/10=8
 dis_buff[0]=frequency % 10;       //第4位, 1080%10=0
}


void FM_dis(void)
{
 
 frequency_to_disbuff();
 uart_send_byte(led_7[dis_buff[0]]);
   uart_send_byte(led_7[dis_buff[1]]&point);
 uart_send_byte(led_7[dis_buff[2]]); 
 if(dis_buff[3]==0) 
  uart_send_byte(0xff);
 else
  uart_send_byte(led_7[dis_buff[3]]);   
}


//写5767
void radio_write(void)
{
    unsigned char i;
    iic_start();
    iic_write8bit(0xc0);        //TEA5767写地址
    waitack();
        for(i=0;i<5;i++)
        {
            iic_write8bit(radio_write_data);
            waitack();


        }
    
    iic_stop();    
}


//读TEA5767状态,并转换成频率
void radio_read(void)
{
    unsigned char i;
    unsigned char temp_l,temp_h;
    pll="0";
    iic_start();
    iic_write8bit(0xc1);        //TEA5767读地址
    waitack();
    
        for(i=0;i<5;i++)
        {
            radio_read_data=iic_read8bit();
            iic_ack();
        }
    
    iic_stop();
    temp_l = radio_read_data[1];
    temp_h = radio_read_data[0];
    temp_h &= 0x3f;
    pll="temp"_h * 256 + temp_l;
    get_frequency();
    
}


//手动设置频率,mode=1,+0.1MHz; mode="0:-0".1MHz ,不用考虑TEA5767用于搜台的相关位:SM,SUD
void search()
{
    radio_read();        
    frequency ++;
   
    if(frequency > max_freq)
     {
      frequency = min_freq;
      band = 0;
     }
    else
     band = 1;
          
    get_pll();
    radio_write_data[0]=pll / 256;
    radio_write_data[1]=pll % 256;
    radio_write_data[2]=0x20;
    radio_write_data[3]=0x11;
    radio_write_data[4]=0x00;
    radio_write();
}


//自动搜台,频率增加搜台
void auto_searchup()
{
    radio_read();
   
    if(frequency>max_freq)
     {
      frequency=min_freq;
      band = 0;
     }
    else
     band = 1;
          
    get_pll();
    radio_write_data[2]=0xa0;   
    radio_write_data[0]=pll / 256 + 0x40;
    radio_write_data[1]= pll % 256;    
    radio_write_data[3]=0x11;
    radio_write_data[4]=0x00;
    radio_write();
    radio_read();   
}


//自动搜台,频率减小搜台
void auto_searchdown()
{
    radio_read();
   
    if(frequency<min_freq)
     {
      frequency=max_freq;
      band = 0;
     }
    else
     band = 1; 
    get_pll();
    radio_write_data[2]=0x20;    
    radio_write_data[0]=pll / 256 + 0x40;
    radio_write_data[1]=pll % 256;    
    radio_write_data[3]=0x11;
    radio_write_data[4]=0x00;
    radio_write();
    radio_read();  
}



//ms延时
void delay(unsigned int i)
{
 unsigned char j;
 do{
     j = 163;
  do
  {
   }
  while(j --);
   }
     while(i --);
}


void main()
{
   SCON = 0x00;                //串口初始化,工作方式0, 同步移位寄存器输出方式     
    
  FM_dis();
  delay(10);
  radio_write();
     while(1)
     {       
    radio_read(); 
 P1=0xff;   
        if(radio_read_data[0]&0x80)     //搜台成功标志
         have = 0;        
    else
     have = 1;
 


//向上搜台         
        if(KEY_0 == 0)
        {
            delay(10);
            if(KEY_0 == 0) 
            {
             auto_searchup();
           
           while(KEY_0 == 0)
            {
             FM_dis();
       delay(5);
             
             }
            }    
        }


//向下搜台      
         if(KEY_1==0)
         {
             if(KEY_1 == 0) 
             {
              auto_searchdown();
            
            while(KEY_1 == 0)
            {            
             FM_dis();
       delay(5);
                            
             }
             }   
       
         }


//手动搜台,每次按下增加频率+0.1Mhz
        if(KEY_2==0)
          {
              if(KEY_2 == 0) 
              {
               search();
             
             while(KEY_2 == 0)
              {             
               FM_dis();
         delay(5);
           
               }
              }   
        
          }
     }
}
========================


I2C.c文件


========================


#include <reg51.h>
#include <stdio.h>
#include <intrins.h>


#define NOP()  _nop_() 
 
sbit scl="P1"^0;
sbit sda="P1"^1;


// delay
void iic_delay(void)
{
 NOP();
 NOP();
}


//启动I2C总线的函数,当scl为高电平时使sda产生一个负跳变 
void iic_start() 
{
    sda="1";
    scl="1";
    iic_delay();
    sda="0";
    iic_delay();
    scl="0";
    iic_delay();
}


//终止I2C总线,当scl为高电平时使sda产生一个正跳变
void iic_stop() 
{                
    sda="0";
    scl="1";
    iic_delay();
    sda="1";
    iic_delay();
}


//发送应答信号
void iic_ack() 
{
    sda="0";
    scl="1";
    scl="0";
    sda="1";
}



//等待应答信号
bit waitack(void)
{
        unsigned char errtime="255";//因故障接收方无ACK,超时值为25。
        sda="1";
        iic_delay();
        while(sda)
        {
                errtime--;
                if (!errtime)
                {
                        iic_stop();         
                        return 0;
                }
        }        
        scl="1";
         iic_delay();
        scl="0";
        return 1;
}



//发送一个字节
void iic_write8bit(unsigned char input) 
{
    unsigned char temp;
    for(temp=0;temp<8;temp++) 
    {
        if((input<<temp)&0x80)
            sda="1";
        else
            sda="0";
        scl="1";


        iic_delay();
        scl="0";
    }
}
//读一个字节
unsigned char iic_read8bit() 
{
    unsigned char temp,rbyte=0;
    for(temp=0;temp<8;temp++) 
    {
        scl="1";
        iic_delay();
        if(sda)
            rbyte=(rbyte<<1)+1;
        else
            rbyte="rbyte"<<1;
        scl="0";
    }
    return(rbyte);
}
hex文件和源码在小组的帖子可以下载。


下载地址

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户233077 2009-10-25 23:55

太太感谢了!

用户182458 2008-11-19 22:31

太牛了
相关推荐阅读
用户152563 2008-10-19 23:11
FM收音机初步成功,可以收到台了
今天参考ouravr的几个TEA5767的帖子,修改了他的程序,用在FM板上,可以显示和收到台了。原帖地址:http://www.ouravr.com/bbs/bbs_content.jsp?bbs_...
用户152563 2008-10-10 23:12
EDNChina FM实验板套件LED显示测试程序
        最近在玩《51单片机工程应用实例》小组的FM实验板,昨天收到快递,少了3个74LS164,不过不要紧,星期六去华强北买几片回来,先焊好板子再说。今天刚焊好板子,顺便写了个LED测试程序...
用户152563 2008-08-13 23:07
TCP/IP学习板调通了
星期一收到彩云的包裹,花了1个小时整理8019的管脚,才焊上去,回家用笔记本下程序,发现STC的单片机可以连上,但是不能进入编程模式,郁闷的要死,我用的是USB转的RS-232口。今天有点时间,在公司...
EE直播间
更多
我要评论
1
5
关闭 站长推荐上一条 /3 下一条