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,自行判断,频率范围