zoukankan      html  css  js  c++  java
  • 51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

    先看效果图: 显示 频道CH , 频率 100.0Mhz

     欢迎信息,1602 内置日文平假名, 正好用来显示博主名称。

    焊接前,已经万能面包板上试验成功。

     焊接完成以后,1602 的D0 - D7 接到了 P1 上面,为了布线简单,这里是接反的 P1.0 => D7 .. 实际写入 读取数据时,还需要转换高低位。

     背面走线图

    元件清单:stc89c52,  lcd1602,  tea5767完整版 , at24c04 , DS18B20 (未实现功能,打算后期在加一个 RTC 芯片,和 GPS 做 精准的电子钟)

    下面是一些元件介绍:

    红外一体化接收头,常见有2种。

    lcd1602 显示日文假名字符对应表

    高位 + 低位,组成一个 unsigned char 放入就能显示出来了。

    下面讲源程序:

     main.c 主程序中 初始化了 LCD1602 , TEA5767 , 初始化红外线中断 , 对按键进行扫描。 1 #include <reg52.h>

     2 #include "tea5767.h"
     3 #include "delay.h"
     4 #include "lcd1602.h"
     5 #include "IR.h"
     6 //K1:上一台 K2:下一台 K3:从低向高搜索台
     9 sbit K1 = P2 ^ 1;
    10 sbit K2 = P2 ^ 4;
    11 sbit K3 = P2 ^ 7;
    12 
    13 //当前频道号 从 0 开始
    14 unsigned char ch = 0;
    15 
    16 void main()
    17 {
    18     
    19     //初始化 1602lcd
    20     lcd1602_init();
    21     
    22     //初始化 串口
    23     init_uart();
    24     
    25     //初始化红外遥控接口
    26     init_IR();
    27     
    28     //主函数中扫描按键
    29     while(1)
    30     {
    31         //上一台
    32         if(0 == K1)
    33         {
    34             //去抖动
    35             delayms(100);
    36             if(0 == K1)
    37             {
    38                 set_ch(--ch);
    39             }
    40         }
    41         //下一台
    42         if(0 == K2)
    43         {
    44             //去抖动
    45             delayms(100);
    46             if(0 == K2)
    47             {
    48                 set_ch(++ch);
    49             }
    50         }
    51         //自动搜索
    52         if(0 == K3)
    53         {
    54             //去抖动
    55             delayms(100);
    56             if(0 == K3)
    57             {
    58                 tea5767_tiny_auto_search();
    59             }
    60         }
    61     }
    62 }
    63 
    64 void IR_int() interrupt 0
    65 {
    66     IR_CODE ir_code;
    67     EX0 = 0;//处理过程中 关中断
    68     ir_code = IR_recv();
    69     if(ir_code.ir_code)
    70     {
    73         /**
    74          * custom:0xCC1D code:0x05FA 上一台
    75          * custom:0xCC1D code:0x06F9 下一台
    76          * custom:0xCC1D code:0x01FE 静音
    77          */
    78         //比较机器码
    79         if(ir_code.custom_height == 0xcc && ir_code.custom_lower == 0x1d)
    80         {
    81             //比较功能码
    82             switch(ir_code.ir_code)
    83             {
    84                 case 0x5: set_ch(++ch); break;
    85                 case 0x6: set_ch(--ch); break;
    86                 case 0x1: tea5767_mute(ch); break;
    87             }
    88             //发送到串口,显示出编码,可用于记录编码,做学习型遥控器

    92 send_code(ir_code); 93 } 94 } 95 EX0 = 1;//处理结束后 开中断 96 }

    lcd1602.h

     1 #ifndef __LCD1602__
     2 #define __LCD1602__
     3 #include <reg52.h>
     4 #include "delay.h"
     9 #define DATA P1
    10 sbit RS = P3 ^ 7;//数据 H 命令 L
    11 sbit RW = P3 ^ 4;//读 H 写 L
    12 sbit E  = P3 ^ 3;//高电平 H 使能
    13 
    14 /**19  * E = 1 后需要等一小段时间, 在手册中并没有说明 - 
    20  */
    21 void lcd1602_init();
    22 void lcd1602_clear();
    23 char lcd1602_is_busy();
    24 void lcd1602_write_cmd(unsigned char cmd);
    25 void lcd1602_write_data(unsigned char dat);
    26 void lcd1602_pos(unsigned char pos);
    27 unsigned char lcd1602_reverse(unsigned char dat);
    28 #endif

    lcd1602.c

      1 #include "lcd1602.h"
      2 
      3 void lcd1602_init()
      4 {
      5     //初始化 复位 lcd1602
      6     lcd1602_write_cmd(0x38);//设置显示模式 指令码 00111000 => 0x38
      7     delayms(1);
      8     lcd1602_write_cmd(0x0c);//开显示 不显示光标 不闪烁
      9     delayms(1);
     10     lcd1602_write_cmd(0x06);//光标设置 写字符后指针加一
     11     delayms(1);
     12     lcd1602_write_cmd(0x01);//光标清0 指针清0
     13     delayms(1);
     14     //设置初始位置为 0
     15     lcd1602_pos(0);
     16     //打印欢迎信息 日文假名
     17     /**
     18      * こんにちわ   ねじ
     20      * こ 高4位是 b 低4位是 a 合并就是 0xba
     21      */
     22     lcd1602_write_data(0xba);
     23     lcd1602_write_data(0xdd);
     24     lcd1602_write_data(0xc6);
     25     lcd1602_write_data(0xc1);
     26     lcd1602_write_data(0xca);
     27     lcd1602_pos(13);
     28     lcd1602_write_data(0xc8);
     29     lcd1602_write_data(0xbd);
     30     lcd1602_write_data(0xde);
     31     
     32     //第二行显示 Welcome Radio
     33     lcd1602_pos(40);
     34     lcd1602_write_data('W');
     35     lcd1602_write_data('e');
     36     lcd1602_write_data('l');
     37     lcd1602_write_data('c');
     38     lcd1602_write_data('o');
     39     lcd1602_write_data('m');
     40     lcd1602_write_data('e');    
     41     lcd1602_pos(0x4b);
     42     lcd1602_write_data('R');
     43     lcd1602_write_data('a');
     44     lcd1602_write_data('d');
     45     lcd1602_write_data('i');
     46     lcd1602_write_data('o');
     47 }
     48 
     49 
     50 void lcd1602_clear()
     51 {
     52     lcd1602_write_cmd(0x01);//光标清0 指针清0
     53 }
     54 
     55 void lcd1602_pos(unsigned char pos)
     56 {
     57     //设置指针位置 0x80 | 位置
     58     lcd1602_write_cmd(pos|0x80);
     59 }
     60 
     61 void lcd1602_write_data(unsigned char dat)
     62 {
     63     while(lcd1602_is_busy());
     64     RS = 1;
     65     RW = 0;
     66     E  = 0;
     67     DATA = lcd1602_reverse(dat);
     68     delayms(1);
     69     E = 1;//在E 高向低变化时传输
     70     E = 0;
     71 }
     72 
     73 void lcd1602_write_cmd(unsigned char cmd)
     74 {
     75     while(lcd1602_is_busy());
     76     RS = 0;
     77     RW = 0;
     78     E  = 0;
     79     DATA = lcd1602_reverse(cmd);
     80     delayms(1);
     81     E = 1; //在E 高向低变化时传输
     82     E = 0;
     83 }
     84 
     85 char lcd1602_is_busy()
     86 {
     87     char result;
     88     RS = 0;  //发送的是命令
     89     RW = 1;  //
     90     E  = 1;  //使能
     91     delayms(1);
     92     result = (1<<7 & lcd1602_reverse(DATA));//7bit 1 忙 0 不忙
     93     E = 0;   //取消使能
     94     return result;
     95 }
     96 
     97 
     98 //字符高低位互换
     99 unsigned char lcd1602_reverse(unsigned char dat)
    100 {
    101     unsigned char chr;
    102     chr = (dat>>7 & 1) << 0;
    103     chr |= (dat>>6 & 1) << 1;
    104     chr |= (dat>>5 & 1) << 2;
    105     chr |= (dat>>4 & 1) << 3;
    106     chr |= (dat>>3 & 1) << 4;
    107     chr |= (dat>>2 & 1) << 5;
    108     chr |= (dat>>1 & 1) << 6;
    109     chr |= (dat>>0 & 1) << 7;
    110     return chr;
    111 }

    串口 URAT 

    uart.h

    1 #ifndef __UART__
    2 #define __UART__
    3 #include "IR.h"
    4 void init_uart();
    5 void send_hex(unsigned char);
    6 void send_str(unsigned char *);
    7 void send_code(IR_CODE);
    8 #endif

    uart.c

     1 #include <reg52.h>
     2 #include "uart.h"
     3 void init_uart()
     4 {
     5     //定时器1 溢出决定波特率
     6     EA  = 1;      //总中断开
     7     TMOD |= 1<<5; //定时器1 自动重装模式
     8     TH1 = 0xfd;   //当TL1中溢出时 TH1 的值自动重装进去
     9     TL1 = 0xfd;   //省去一个中断处理函数
    10     TR1 = 1;      //开始计数
    11     SM0 = 0;
    12     SM1 = 1;      //8bit UART 波特率可变
    13 }
    14 
    15 void send_str(unsigned char *str)
    16 {
    17     while(*str)
    18     {
    19         SBUF = *str;
    20         while(! TI);
    21         TI = 0;
    22         str++;
    23     }
    24 }
    25 
    26 void send_hex(unsigned char hex)
    27 {
    28     SBUF = hex;
    29     while(! TI);
    30     TI = 0;
    31 }
    32 
    33 void send_code(IR_CODE ir_code)
    34 {
    35     unsigned char c;
    36     unsigned char *p;
    37     int i,j;
    38     p = (unsigned char *)&ir_code;
    39     send_str("custom:0x");
    40     for(i=0; i<4; i++)
    41     {
    42         if(2 == i)
    43         {
    44             send_str(" code:0x");
    45         }
    46         for(j=1; j>=0; j--)
    47         {
    48             c = (*p>>(4*(j))) & 0xf;
    49             if(0<=c && c<=9)
    50             {
    51                 send_hex('0' + c);
    52             }
    53             else
    54             {
    55                 send_hex('A' + c - 0xa);
    56             }
    57         }
    58         p++;
    59     }
    60     send_str("\r\n");
    61 }

    eeprom.h

     1 #include <reg52.h>
     2 #ifndef __EEPROM__
     3 #define __EEPROM__
     4 /**
     5  * STC90C52 结尾是 90C 
     6  * EEPROM 5K
     7  * SRAM 215字节
     8  * 每个扇区512字节  5K / 512 = 10 个扇区
     9  * 扇区首地址 2000h 结束地址 33ffh
    10  */
    11 
    12 /* FLASH 首地址 */
    13 #define BASE_ADDR 0x2000   //stc89c52 stc89c52rd
    14 //#define BASE_ADDR 0x4000 //stc89c54rd+
    15 
    16 /* 特殊功能寄存器声明 */
    17 sfr ISP_DATA  = 0xe2;  
    18 sfr ISP_ADDRH = 0xe3;    
    19 sfr ISP_ADDRL = 0xe4;
    20 sfr ISP_CMD   = 0xe5;
    21 sfr ISP_TRIG  = 0xe6;     
    22 sfr ISP_CONTR = 0xe7;
    23 
    24 /* 定义命令字节 */
    25 #define CMD_Read    0x01 //字节读数据命令     
    26 #define CMD_Prog    0x02 //字节编程数据命令     
    27 #define CMD_Erase   0x03 //扇区擦除数据命令
    28 #define En_Wait_ISP 1<<7 | 1<<1  //设置等待时间 ,并使能ISP/IAP 11.0592 晶振
    29 
    30 void eeprom_lock_ISP();
    31 void eeprom_erase(unsigned int);
    32 unsigned char eeprom_read(unsigned int);
    33 void eeprom_prog(unsigned int addr, unsigned char dat);
    34 
    35 #endif

    延时

    delay.h

    1 #ifndef __DELAY__
    2 #define __DELAY__
    3 void delayms(int);
    4 void delay700us();
    5 #endif

    delay.c

     1 #include <intrins.h>
     2 #include "delay.h"
     3 void delayms(int ms) //@11.0592MHz
     4 {
     5     unsigned char i, j;
     6     while(ms--)
     7     {
     8         _nop_();
     9         i = 2;
    10         j = 199;
    11         do
    12         {
    13             while (--j);
    14         } 
    15         while (--i);
    16     }
    17 }
    18 
    19 void delay700us() //@11.0592MHz
    20 {
    21     unsigned char i, j;
    22     _nop_();
    23     i = 2;
    24     j = 61;
    25     do
    26     {
    27         while (--j);
    28     } while (--i);
    29 }

    i2c 通信

    i2c.h

     1 #ifndef __I2C__
     2 #define __I2C__
     3 
     4 #include <reg52.h>
     5 
     6 /* 引脚定义 */
     7 sbit I2C_SCL = P3 ^ 5;
     8 sbit I2C_SDA = P3 ^ 6;
     9 
    10 void i2c_start();
    11 void i2c_stop();
    12 void i2c_send(unsigned char dat);
    13 unsigned char i2c_recv();
    14 char i2c_wait_ack();
    15 void i2c_send_ack();
    16 #endif

    i2c.c

     1 #include "i2c.h" 
     2 
     3 void i2c_start()
     4 {
     5     /* SCL SDA 为高电平时 SDA 变为低电平 */
     6     I2C_SCL = 1;
     7     I2C_SDA = 1;
     8     I2C_SDA = 0; 
     9     I2C_SCL = 0; /* 钳住I2C总线,准备发送或接收数据 */
    10 }
    11 
    12 void i2c_stop()
    13 {
    14     /* SCK 高电平期间 SDA 由低变高 */
    15     I2C_SCL = 0;
    16     I2C_SDA = 0;
    17     I2C_SCL = 1;
    18     I2C_SDA = 1;    
    19 }
    20 
    21 void i2c_send(unsigned char dat)
    22 {
    23     char i = 8;
    24     while(i--)
    25     {
    26         I2C_SCL = 0;
    27         if(dat & 0x80)
    28         {
    29             I2C_SDA = 1;
    30         }
    31         else
    32         {
    33             I2C_SDA = 0;
    34         }
    35         I2C_SCL = 1;
    36         dat = dat<<1;
    37     }
    38     //等待ACK回复信号
    39     i2c_wait_ack();
    40 }
    41 
    42 unsigned char i2c_recv()
    43 {
    44     unsigned char dat = 0;
    45     char i = 8;
    46     I2C_SDA = 1;
    47     while(i--)
    48     {
    49         I2C_SCL = 0;
    50         dat<<=1; //这里要有一定延时要求是 > 1.3us 
    51         I2C_SCL = 1;    
    52         if(I2C_SDA)
    53         {
    54             //以下3者结果一样
    55             //dat++;
    56             //dat += 1;
    57             dat |= 1;
    58         }
    59         //dat |= (unsigned char)I2C_SDA;
    60     }
    61     i2c_send_ack();
    62     return dat;
    63 }
    64 
    65 //无响应返回0 
    66 char i2c_wait_ack()
    67 {
    68     unsigned char time_out = 0xff;
    69     I2C_SCL = 0;
    70     I2C_SDA = 1;
    71     I2C_SCL = 1;
    72     
    73     //由 slaver 拉低 SDA 表示回应
    74     while(I2C_SDA)
    75     {
    76         time_out--;
    77         if(0 == time_out)
    78         {
    79             i2c_stop();
    80             return 0;
    81         }
    82     }
    83     return 1;
    84 }
    85 
    86 void i2c_send_ack()
    87 {
    88     //拉低SDA 响应ACK 当SCL 由低电平变高电平时 从机接收
    89     I2C_SCL = 0;
    90     I2C_SDA = 0;
    91     I2C_SCL = 1;
    92     I2C_SCL = 0;
    93 }

    IR 红外接收

    IR.h

     1 #ifndef __IR__
     2 #define __IR__
     3 #include <reg52.h>
     4 #include "delay.h"
     5 #include <string.h>
     6 
     7 //公用
     8 typedef struct {
     9     unsigned char custom_height;
    10     unsigned char custom_lower;
    11     unsigned char ir_code;
    12     unsigned char re_ir_code;
    13 } IR_CODE, *pIR_CODE;
    14 
    15 //接收
    16 sbit IR     = P3 ^ 2;//红外线一体接收头 OUT 
    17 
    18 void init_IR();
    19 IR_CODE IR_recv();
    20 #endif

    IR.c

     1 #include "IR.h"
     2 
     3 void init_IR()
     4 {
     5     //接收
     6     EA  = 1;  //总中断开
     7     EX0 = 1;  //IR 接收头使用外部中断0 来处理
     8     IT0 = 1;  //下降沿触发
     9 }
    10 
    11 //接收
    12 IR_CODE IR_recv()
    13 {
    14     /**
    15      * 数据格式:
    16      * 9ms低电平 4.5ms高电平 头部
    17      * 定制高位  定制低位  数据码  数据反码
    18      * 1: 560us低电平 1680us高电平  0.56ms 1.7ms 
    19      * 0: 560us低电平 560us高电平   0.56ms 0.56ms
    20      */
    21     IR_CODE ir_code;
    22     unsigned char i,k;
    23     unsigned char *ir_char_p;
    24     unsigned char ir_char;
    25     ir_char_p = (unsigned char *)&ir_code;
    26     
    27     //栈分配 IR_CODE 竟然还要手动清0
    28     memset(&ir_code, 0, 4);
    29     
    30     delayms(5); //9ms 内必须是低电平否则就不是头信息
    31     if(0 == IR)
    32     {
    33         while(! IR);//等待4.5ms的高电平
    34         
    35         //检测是否是 2.5ms 重码 
    36         delayms(3);
    37         if(1 == IR)
    38         {
    39             //k 4位编码
    40             for(k=0; k<4; k++)
    41             {
    42                 ir_char = 0x0;
    43                 //i 每一个编码的 8bit
    44                 for(i=0;i<8;i++)
    45                 {
    46                     while(IR);     //等待变为低电平时
    47                     while(! IR);   //等待变为高电平后
    48                     delay700us();  //休眠700us 后读值
    49                     ir_char |= (char)IR << i;//先存低位
    50                     //使用下面指针操作就会失败出现不稳定
    51                     //*ir_char_p |= (char)IR << i;
    52                 }
    53                 *ir_char_p = ir_char;
    54                 ir_char_p++;
    55             }
    56             
    57             //计算反码 code码是否正确
    58             if(ir_code.ir_code != ~(ir_code.re_ir_code))
    59             {
    60                 memset(&ir_code, 0, 4);
    61             }
    62         }
    63     }
    64     return ir_code;
    65 }

    str 处理相关 

    str.h

    1 #ifndef __STR__
    2 #define __STR__
    4 unsigned char num_to_str(unsigned char num);
    5 #endif

    str.c

     1 #include "str.h"
     2 
     3 unsigned char num_to_str(unsigned char num)
     4 {
     5     unsigned char chr;
     6     //asc2 表 0 在前面
     7     if(0<= num && 9>= num)
     8     {
     9         chr = num + '0';
    10     }
    11     return chr;
    12 }

    重点TEA5767 特别说明的是,我先是在TB上找了许多资料,百度上找,但是就发现就是那一种格式的写法,还是个错误的写法,根本就不对,很多人还转来转去。(自动搜台的写法不对。)

    GOOGLE 上搜了下,C51 的不多,其它的有不少。

    自动搜台,是利用第6位的 SM ,写1 表示进入这个模式,同时还需要设置 SSL1 SSL0 ,经过我的测试,发现 HLSI 只能设为1 的时候,才能搜到台。

    别人的程序错误之处在于, 自动搜索后,从 第3个 读的数据中找 HLSI 在计算是 + 225 还是 -225 ,这个在读的时候,就变成IF 了,没有看datasheet 就写程序,还说 自动搜索模式有问题,不好用。

    经过我的试验,发现 自动搜台模式,基本能用,但是程序要复杂一些。不像是写入一个频率,读 ADC 比较数值,大于多少就表示有台。 比这种要复杂的多。

    以下 2 种算法,都有编写,并测试成功,但实际试验效果来看, 第2种,普通的写法,效果好些。(问题是,自动搜台,检测到信号停住的地方,可能并不准,有可能是,100.023 这种。如果把 每次步进频率改为100K 就会错过很多台,这里是每次进10K)

    tea5767.h

     1 #ifndef __TEA5767__
     2 #define __TEA5767__
     3 
     4 #include <string.h>
     5 #include "i2c.h"
     6 #include "uart.h"
     7 #include "str.h"
     8 #include "delay.h"
     9 #include "lcd1602.h"
    10 #include "eeprom.h" 
    11 
    12 typedef struct{
    13     unsigned char st1;
    14     unsigned char st2;
    15     unsigned char st3;
    16     unsigned char st4;
    17     unsigned char st5;
    18 } TEA_DAT, *PTEA_DAT;
    19 
    20 typedef struct {
    21     unsigned char high; //表示整数 100
    22     unsigned char low;  //表示小数 5
    23 } TEA_CH, *PTEA_CH;
    24 
    25 /* 地址定义 */
    26 #define TEA5767_ADDR_W  0xc0   //tea5767 写地址
    27 #define TEA5767_ADDR_R  0xc1   //tea5767 读地址
    28 #define TEA5767_CLK     32768  //tea5767 晶振
    29 #define TEA5767_MAX_KHZ 108000 //最高频率 108M
    30 #define TEA5767_MIN_KHZ 87500  //最低频率 87.5M
    31 #define TEA5756_HLSI //高混频器 经过测试,使用SM自动搜索功能时必须设此值 手动搜索 无所谓
    32 
    33 unsigned long tea5767_Khz_to_pll(unsigned long Khz);
    34 unsigned long tea5767_pll_to_Khz(TEA_DAT dat);
    35 TEA_DAT tea5767_set_receiver(unsigned long Khz);
    36 TEA_DAT tea5767_search(unsigned long Khz);
    37 void tea5767_auto_search();
    38 void tea5767_tiny_auto_search();
    39 void tea5767_write(TEA_DAT dat);
    40 TEA_DAT tea5767_read();
    41 void tea5767_mute(unsigned char ch_num);
    42 
    43 //Lcd显示
    44 void sohw_search(unsigned long Khz, unsigned char channel);
    45 //存储电台
    46 void save_eeprom(unsigned long Khz, unsigned char channel);
    47 //设定ch
    48 unsigned long set_ch(unsigned char ch_num);
    49 #endif

    tea5767.c

      1 #include "tea5767.h"
      2 
      3 unsigned char mute = 1;
      4 void tea5767_mute(unsigned char ch_num)
      5 {
      6     TEA_DAT dat;
      7     unsigned long Khz,pll;
      8     Khz = set_ch(ch_num);
      9     //静音位写 1
     10     pll = tea5767_Khz_to_pll(Khz);
     11     dat.st1  = (mute%2) <<7 | (pll>>8) & 0x3f;
     12     dat.st2  = pll;
     13     dat.st3  = 1;
     14     #ifdef TEA5756_HLSI
     15     dat.st3  |= 1<<4;
     16     #endif
     17     dat.st4  = 0x11;
     18     dat.st5  = 0x40;
     19     tea5767_write(dat);
     20     
     21     if(mute%2)
     22     {
     23         lcd1602_pos(40);
     24         lcd1602_write_data('M');
     25         lcd1602_write_data('U');
     26         lcd1602_write_data('T');
     27         lcd1602_write_data('E');
     28     }
     29     mute++;
     30 }
     31 
     32 unsigned long tea5767_Khz_to_pll(unsigned long Khz)
     33 {
     34     #ifdef TEA5756_HLSI
     35     return 4*(Khz*1000+225000)/TEA5767_CLK;
     36     #else
     37     return 4*(Khz*1000-225000)/TEA5767_CLK;
     38     #endif
     39 }
     40 
     41 unsigned long tea5767_pll_to_Khz(TEA_DAT dat)
     42 {
     43     unsigned long Khz,pll;     
     44     pll = ((dat.st1 & 0x3f)<<8 | dat.st2);
     45     #ifdef TEA5756_HLSI
     46     Khz = (pll*TEA5767_CLK/4-225*1000)/1000;
     47     #else
     48     Khz = (pll*TEA5767_CLK/4+225*1000)/1000;
     49     #endif
     50     
     51     return Khz;
     52 }
     53 
     54 void tea5767_write(TEA_DAT dat)
     55 {
     56     i2c_start();
     57     i2c_send(TEA5767_ADDR_W);
     58     i2c_send(dat.st1);
     59     i2c_send(dat.st2);
     60     i2c_send(dat.st3);
     61     i2c_send(dat.st4);
     62     i2c_send(dat.st5);
     63     i2c_stop();
     64 }
     65 
     66 TEA_DAT tea5767_read()
     67 {
     68     TEA_DAT dat;
     69     i2c_start();
     70     i2c_send(TEA5767_ADDR_R);
     71     dat.st1 = i2c_recv();
     72     dat.st2 = i2c_recv();
     73     dat.st3 = i2c_recv();
     74     dat.st4 = i2c_recv();
     75     dat.st5 = i2c_recv();
     76     i2c_stop();
     77     return dat;
     78 }
     79 
     80 TEA_DAT tea5767_set_receiver(unsigned long Khz)
     81 {
     82     unsigned long pll;
     83     TEA_DAT dat;
     84     
     85     pll = tea5767_Khz_to_pll(Khz);
     86     
     87     /* 发送5个控制位 顺序是 1 2 3 4 5 字节的高位先发 
     88      * HLSL = 0 : 4*(102.4*1000000-225*1000)/32768
     89      * HLSL = 1 : 4*(102.4*1000000+225*1000)/32768
     90      * PLL WORD = 0x30ef
     91      */
     92     dat.st1  = (pll>>8) & 0x3f;
     93     dat.st2  = pll;
     94     dat.st3  = 1;
     95     #ifdef TEA5756_HLSI
     96     dat.st3  |= 1<<4;
     97     #endif
     98     dat.st4  = 0x11;
     99     dat.st5  = 0x40;
    100     
    101     tea5767_write(dat);
    102     delayms(100);
    103     dat = tea5767_read();
    104     return dat;
    105 }
    106 
    107 //自动搜索 87.5 ~ 108M 由低向高搜索
    108 TEA_DAT tea5767_search(unsigned long Khz)
    109 {
    110     unsigned long pll;
    111     TEA_DAT dat;
    112     
    113     pll = tea5767_Khz_to_pll(Khz);
    114     dat.st1  = ((pll>>8) & 0x3f) | (1<<6);
    115     dat.st2  = pll;
    116     //搜索停止 信号强度 01:5 10:7 11:10 
    117     //dat.st3  = 1 | 1<<7 | 1<<6 |1<<5 ;
    118     dat.st3  = 1 | 1<<7 | 1<<6  ;
    119     #ifdef TEA5756_HLSI
    120     dat.st3  |= 1<<4;
    121     #endif
    122     
    123     dat.st4  = 0x11;
    124     dat.st5  = 0x40;
    125     tea5767_write(dat);
    126     delayms(100);
    127     dat = tea5767_read();
    128     while(dat.st1 != (dat.st1 | (1<<7)))
    129     {
    130         dat = tea5767_read();
    131     }
    132     return dat;
    133 }
    134 
    135 //自动搜台 存台到 eeprom
    136 void tea5767_auto_search()
    137 {
    138     TEA_DAT dat;
    139     unsigned long Khz;
    140     unsigned char if_counter;
    141     unsigned char channel = 0;
    142     Khz = TEA5767_MIN_KHZ;
    143     
    144     //清液晶屏
    145     lcd1602_clear();
    146     
    147     dat = tea5767_search(Khz);
    148                 
    149     //检测信号是否满足要求
    150     while(dat.st1 != (dat.st1 | (1<<6)))
    151     {
    152         //if count 在 0x31 ~ 0x3e 之间
    153         if_counter = (dat.st3 & 0x7f);
    154         if((0x31 < if_counter) && (0x3e > if_counter))
    155         {                    
    156             //比较leve 电平确认是否收到台 实际测试使用此数 不会漏台
    157             if((dat.st4>>4) > 10)
    158             {
    159                 Khz = tea5767_pll_to_Khz(dat);
    160     
    161                 save_eeprom(Khz, channel);
    162                 channel++;
    163             }
    164         }
    165         
    166         //显示当前频率
    167         sohw_search(Khz, channel);
    168         
    169         //计算搜到台的频率 加上10Khz 后重新搜索 实际测试使用此数 不会漏台
    170         Khz += 10;
    171         dat = tea5767_search(Khz);
    172     }
    173 }
    174 
    175 //细致的搜台
    176 void tea5767_tiny_auto_search()
    177 {
    178     TEA_DAT dat;    
    179     unsigned long Khz;
    180     unsigned char channel = 0;
    181     Khz = TEA5767_MIN_KHZ;
    182     //Khz = 100000;
    183     
    184     //清液晶屏
    185     lcd1602_clear();
    186     
    187     //擦除eeprom
    188     eeprom_erase(1);
    189     
    190     while(Khz <= TEA5767_MAX_KHZ)
    191     {
    192         dat = tea5767_set_receiver(Khz);
    193         //比较leve 电平确认是否收到台 实际测试使用此数 不会漏台
    194         if((dat.st4>>4) > 8)
    195         {
    196             //存储电台
    197             save_eeprom(Khz, channel++);
    198         }
    199         
    200         //显示当前频率
    201         sohw_search(Khz, channel);
    202         //频率由低到高 每次增加10Khz
    203         Khz += 100;
    204     }
    205 }
    206 
    207 
    208 void sohw_search(unsigned long Khz, unsigned char channel)
    209 {
    210     unsigned char high, low;
    211     lcd1602_pos(0);
    212     lcd1602_write_data('S');
    213     lcd1602_write_data('e');
    214     lcd1602_write_data('a');
    215     lcd1602_write_data('r');
    216     lcd1602_write_data('c');
    217     lcd1602_write_data('h');
    218     lcd1602_write_data(':');
    219     //输出频率 如果是 100M 以下第1位为空
    220     high = Khz/1000;
    221     low  = Khz%1000/100;
    222     if(high>= 100)
    223     {
    224         lcd1602_write_data(num_to_str(high/100));
    225     }
    226     else
    227     {
    228         lcd1602_write_data(' ');
    229     }
    230     lcd1602_write_data(num_to_str(high%100/10));
    231     lcd1602_write_data(num_to_str(high%10));
    232     lcd1602_write_data('.');
    233     lcd1602_write_data(num_to_str(low));
    234     lcd1602_write_data('M');
    235     lcd1602_write_data('h');
    236     lcd1602_write_data('z');
    237     
    238     //显示收到的频道
    239     lcd1602_pos(40);
    240     lcd1602_write_data('C');
    241     lcd1602_write_data('h');
    242     lcd1602_write_data('a');
    243     lcd1602_write_data('n');
    244     lcd1602_write_data('n');
    245     lcd1602_write_data('e');
    246     lcd1602_write_data('l');
    247     lcd1602_write_data(':');
    248     
    249     lcd1602_write_data(num_to_str(channel / 10));
    250     lcd1602_write_data(num_to_str(channel % 10));
    251 }
    252 
    253 //存储电台
    254 void save_eeprom(unsigned long Khz, unsigned char channel)
    255 {
    256     TEA_CH ch;     
    257     ch.high = Khz/1000;
    258     ch.low  = Khz%1000/100;
    259     eeprom_prog(channel*2,   ch.high);
    260     eeprom_prog(channel*2+1, ch.low);
    261 }
    262 
    263 //设定ch
    264 unsigned long set_ch(unsigned char ch_num)
    265 {
    266     unsigned long Khz;
    267     TEA_CH ch;
    268     ch.high = eeprom_read(ch_num*2);
    269     ch.low  = eeprom_read(ch_num*2+1);
    270     //合并为 Khz
    271     Khz  = ch.high*100; //直接使用 *1000 会计算错误 分为2部正确
    272     Khz *= 10;
    273     Khz += ch.low*100;
    274     
    275     //设定接收频率
    276     tea5767_set_receiver(Khz);
    277     
    278     //清液晶屏
    279     lcd1602_clear();
    280     
    281     //显示频道信息
    282     lcd1602_pos(0);
    283     lcd1602_write_data('C');
    284     lcd1602_write_data('h');
    285     lcd1602_write_data(':');
    286     
    287     //频道数从 0 开始计
    288     lcd1602_write_data(num_to_str(ch_num / 10));
    289     lcd1602_write_data(num_to_str(ch_num % 10));
    290     
    291     lcd1602_pos(8);
    292     if(ch.high>= 100)
    293     {
    294         lcd1602_write_data(num_to_str(ch.high/100));
    295     }
    296     else
    297     {
    298         lcd1602_write_data(' ');
    299     }
    300     lcd1602_write_data(num_to_str(ch.high%100/10));
    301     lcd1602_write_data(num_to_str(ch.high%10));
    302     lcd1602_write_data('.');
    303     lcd1602_write_data(num_to_str(ch.low));
    304     lcd1602_write_data('M');
    305     lcd1602_write_data('h');
    306     lcd1602_write_data('z');
    307     
    308     return Khz;
    309 }

    eeprom.c 

     1 #include "eeprom.h"
     2 
     3 /* 执行完操作以后安全锁 */
     4 void eeprom_lock_ISP()
     5 {
     6     ISP_CONTR = 0;
     7     ISP_CMD = 0;
     8     ISP_TRIG = 0;
     9     ISP_ADDRH = 0xff;
    10     ISP_ADDRL = 0xff;
    11 }
    12 
    13 /* 擦除指定地址所在的整个扇区  */
    14 void eeprom_erase(unsigned int addr)
    15 {
    16     addr += BASE_ADDR;
    17     
    18     //发送地址
    19     ISP_ADDRH = addr >> 8;
    20     ISP_ADDRL = addr;
    21     
    22     //发送解锁命令
    23     ISP_CONTR = En_Wait_ISP;
    24     
    25     //发擦除命令
    26     ISP_CMD = CMD_Erase;
    27     
    28     //发送触发命令
    29     ISP_TRIG = 0x46;
    30     ISP_TRIG = 0xB9;
    31     
    32     //最后锁定 ISP 仿误操作
    33     eeprom_lock_ISP();
    34 }
    35 
    36 unsigned char eeprom_read(unsigned int addr)
    37 {
    38     addr += BASE_ADDR;
    39     
    40     //发送地址
    41     ISP_ADDRH = addr >> 8;
    42     ISP_ADDRL = addr;
    43     
    44     //发送解锁命令
    45     ISP_CONTR = En_Wait_ISP;
    46     
    47     //发读命令
    48     ISP_CMD = CMD_Read;
    49     
    50     //发送触发命令
    51     ISP_TRIG = 0x46;
    52     ISP_TRIG = 0xB9;
    53     
    54     //最后锁定 ISP 仿误操作
    55     eeprom_lock_ISP();
    56     
    57     return ISP_DATA;
    58 }
    59 
    60 void eeprom_prog(unsigned int addr, unsigned char dat)
    61 {
    62     addr += BASE_ADDR;
    63     
    64     //发送要保存的数据
    65     ISP_DATA = dat;
    66     
    67     //发送地址
    68     ISP_ADDRH = addr >> 8;
    69     ISP_ADDRL = addr;
    70     
    71     //发送解锁命令
    72     ISP_CONTR = En_Wait_ISP;
    73     
    74     //发编程命令
    75     ISP_CMD = CMD_Prog;
    76     
    77     //发送触发命令
    78     ISP_TRIG = 0x46;
    79     ISP_TRIG = 0xB9;
    80     
    81     //最后锁定 ISP 仿误操作
    82     eeprom_lock_ISP();
    83 }

    最后,在简单说下,自动搜台 和 手动搜台的区别。

    自动搜台特点:

    1,设一个 LEVE 值后,当到这个值的时候,能自动停止,但是灵活性只有3种,不够灵活。

    2,能增长到最高频率时,停止 

    3,只能用 TEA5756_HLSI 

    自动搜台流程:

    1,设定 好 SM 位 和 SSL 后

    2,设一个频率 

    3,TEA5767 就会自动向上 或 向下 查找,直到 确认收到了信号,就停止 有标识位, 同时比较是否到了最终端,108M

    4,程序需要判断,有信号的标识位, 108M 到终点的标识位2个。

    5,程序也要比较ADC 电平,再次确认是否搜到了台

    手动搜台特点:

    1,控制灵活,但要自行控制以上参数。程序编写简单。

    手动搜台流程:

    1,写入一个频率

    2,读取ADC 比较高于某个值时就表示收到了台

    3,自行判断,频率范围

  • 相关阅读:
    centos7安装Python3.7,执行./configure时报错,configure: error: no acceptable C compiler found in $PATH
    Hadoop集群搭建
    jdk安装
    ssh免密登陆
    centos安装python3.7
    centos7更改yum源
    32.Java基础_异常
    31.Java基础_日期/日期格式/日历类
    1.华为路由交换技术_网络基础知识
    396. 旋转函数(数学)
  • 原文地址:https://www.cnblogs.com/ningci/p/5464679.html
Copyright © 2011-2022 走看看