51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

时间:2023-11-23 20:51:38

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

51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

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

51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

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

51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

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

51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

背面走线图

51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

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

下面是一些元件介绍:

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

51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

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

51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

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

下面讲源程序:

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

 #include "tea5767.h"
#include "delay.h"
#include "lcd1602.h"
#include "IR.h"
//K1:上一台 K2:下一台 K3:从低向高搜索台
sbit K1 = P2 ^ ;
sbit K2 = P2 ^ ;
sbit K3 = P2 ^ ; //当前频道号 从 0 开始
unsigned char ch = ; void main()
{ //初始化 1602lcd
lcd1602_init(); //初始化 串口
init_uart(); //初始化红外遥控接口
init_IR(); //主函数中扫描按键
while()
{
//上一台
if( == K1)
{
//去抖动
delayms();
if( == K1)
{
set_ch(--ch);
}
}
//下一台
if( == K2)
{
//去抖动
delayms();
if( == K2)
{
set_ch(++ch);
}
}
//自动搜索
if( == K3)
{
//去抖动
delayms();
if( == K3)
{
tea5767_tiny_auto_search();
}
}
}
} void IR_int() interrupt
{
IR_CODE ir_code;
EX0 = ;//处理过程中 关中断
ir_code = IR_recv();
if(ir_code.ir_code)
{
/**
* custom:0xCC1D code:0x05FA 上一台
* custom:0xCC1D code:0x06F9 下一台
* custom:0xCC1D code:0x01FE 静音
*/
//比较机器码
if(ir_code.custom_height == 0xcc && ir_code.custom_lower == 0x1d)
{
//比较功能码
switch(ir_code.ir_code)
{
case 0x5: set_ch(++ch); break;
case 0x6: set_ch(--ch); break;
case 0x1: tea5767_mute(ch); break;
}
//发送到串口,显示出编码,可用于记录编码,做学习型遥控器 send_code(ir_code);
}
}
EX0 = ;//处理结束后 开中断
}

lcd1602.h

 #ifndef __LCD1602__
#define __LCD1602__
#include <reg52.h>
#include "delay.h"
#define DATA P1
sbit RS = P3 ^ ;//数据 H 命令 L
sbit RW = P3 ^ ;//读 H 写 L
sbit E = P3 ^ ;//高电平 H 使能 /** * E = 1 后需要等一小段时间, 在手册中并没有说明 -
*/
void lcd1602_init();
void lcd1602_clear();
char lcd1602_is_busy();
void lcd1602_write_cmd(unsigned char cmd);
void lcd1602_write_data(unsigned char dat);
void lcd1602_pos(unsigned char pos);
unsigned char lcd1602_reverse(unsigned char dat);
#endif

lcd1602.c

 #include "lcd1602.h"

 void lcd1602_init()
{
//初始化 复位 lcd1602
lcd1602_write_cmd(0x38);//设置显示模式 指令码 00111000 => 0x38
delayms();
lcd1602_write_cmd(0x0c);//开显示 不显示光标 不闪烁
delayms();
lcd1602_write_cmd(0x06);//光标设置 写字符后指针加一
delayms();
lcd1602_write_cmd(0x01);//光标清0 指针清0
delayms();
//设置初始位置为 0
lcd1602_pos();
//打印欢迎信息 日文假名
/**
* こんにちわ ねじ
* こ 高4位是 b 低4位是 a 合并就是 0xba
*/
lcd1602_write_data(0xba);
lcd1602_write_data(0xdd);
lcd1602_write_data(0xc6);
lcd1602_write_data(0xc1);
lcd1602_write_data(0xca);
lcd1602_pos();
lcd1602_write_data(0xc8);
lcd1602_write_data(0xbd);
lcd1602_write_data(0xde); //第二行显示 Welcome Radio
lcd1602_pos();
lcd1602_write_data('W');
lcd1602_write_data('e');
lcd1602_write_data('l');
lcd1602_write_data('c');
lcd1602_write_data('o');
lcd1602_write_data('m');
lcd1602_write_data('e');
lcd1602_pos(0x4b);
lcd1602_write_data('R');
lcd1602_write_data('a');
lcd1602_write_data('d');
lcd1602_write_data('i');
lcd1602_write_data('o');
} void lcd1602_clear()
{
lcd1602_write_cmd(0x01);//光标清0 指针清0
} void lcd1602_pos(unsigned char pos)
{
//设置指针位置 0x80 | 位置
lcd1602_write_cmd(pos|0x80);
} void lcd1602_write_data(unsigned char dat)
{
while(lcd1602_is_busy());
RS = ;
RW = ;
E = ;
DATA = lcd1602_reverse(dat);
delayms();
E = ;//在E 高向低变化时传输
E = ;
} void lcd1602_write_cmd(unsigned char cmd)
{
while(lcd1602_is_busy());
RS = ;
RW = ;
E = ;
DATA = lcd1602_reverse(cmd);
delayms();
E = ; //在E 高向低变化时传输
E = ;
} char lcd1602_is_busy()
{
char result;
RS = ; //发送的是命令
RW = ; //读
E = ; //使能
delayms();
result = (<< & lcd1602_reverse(DATA));//7bit 1 忙 0 不忙
E = ; //取消使能
return result;
} //字符高低位互换
unsigned char lcd1602_reverse(unsigned char dat)
{
unsigned char chr;
chr = (dat>> & ) << ;
chr |= (dat>> & ) << ;
chr |= (dat>> & ) << ;
chr |= (dat>> & ) << ;
chr |= (dat>> & ) << ;
chr |= (dat>> & ) << ;
chr |= (dat>> & ) << ;
chr |= (dat>> & ) << ;
return chr;
}

串口 URAT

uart.h

 #ifndef __UART__
#define __UART__
#include "IR.h"
void init_uart();
void send_hex(unsigned char);
void send_str(unsigned char *);
void send_code(IR_CODE);
#endif

uart.c

 #include <reg52.h>
#include "uart.h"
void init_uart()
{
//定时器1 溢出决定波特率
EA = ; //总中断开
TMOD |= <<; //定时器1 自动重装模式
TH1 = 0xfd; //当TL1中溢出时 TH1 的值自动重装进去
TL1 = 0xfd; //省去一个中断处理函数
TR1 = ; //开始计数
SM0 = ;
SM1 = ; //8bit UART 波特率可变
} void send_str(unsigned char *str)
{
while(*str)
{
SBUF = *str;
while(! TI);
TI = ;
str++;
}
} void send_hex(unsigned char hex)
{
SBUF = hex;
while(! TI);
TI = ;
} void send_code(IR_CODE ir_code)
{
unsigned char c;
unsigned char *p;
int i,j;
p = (unsigned char *)&ir_code;
send_str("custom:0x");
for(i=; i<; i++)
{
if( == i)
{
send_str(" code:0x");
}
for(j=; j>=; j--)
{
c = (*p>>(*(j))) & 0xf;
if(<=c && c<=)
{
send_hex('' + c);
}
else
{
send_hex('A' + c - 0xa);
}
}
p++;
}
send_str("\r\n");
}

eeprom.h

 #include <reg52.h>
#ifndef __EEPROM__
#define __EEPROM__
/**
* STC90C52 结尾是 90C
* EEPROM 5K
* SRAM 215字节
* 每个扇区512字节 5K / 512 = 10 个扇区
* 扇区首地址 2000h 结束地址 33ffh
*/ /* FLASH 首地址 */
#define BASE_ADDR 0x2000 //stc89c52 stc89c52rd
//#define BASE_ADDR 0x4000 //stc89c54rd+ /* 特殊功能寄存器声明 */
sfr ISP_DATA = 0xe2;
sfr ISP_ADDRH = 0xe3;
sfr ISP_ADDRL = 0xe4;
sfr ISP_CMD = 0xe5;
sfr ISP_TRIG = 0xe6;
sfr ISP_CONTR = 0xe7; /* 定义命令字节 */
#define CMD_Read 0x01 //字节读数据命令
#define CMD_Prog 0x02 //字节编程数据命令
#define CMD_Erase 0x03 //扇区擦除数据命令
#define En_Wait_ISP 1<<7 | 1<<1 //设置等待时间 ,并使能ISP/IAP 11.0592 晶振 void eeprom_lock_ISP();
void eeprom_erase(unsigned int);
unsigned char eeprom_read(unsigned int);
void eeprom_prog(unsigned int addr, unsigned char dat); #endif

延时

delay.h

 #ifndef __DELAY__
#define __DELAY__
void delayms(int);
void delay700us();
#endif

delay.c

 #include <intrins.h>
#include "delay.h"
void delayms(int ms) //@11.0592MHz
{
unsigned char i, j;
while(ms--)
{
_nop_();
i = ;
j = ;
do
{
while (--j);
}
while (--i);
}
} void delay700us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = ;
j = ;
do
{
while (--j);
} while (--i);
}

i2c 通信

i2c.h

 #ifndef __I2C__
#define __I2C__ #include <reg52.h> /* 引脚定义 */
sbit I2C_SCL = P3 ^ ;
sbit I2C_SDA = P3 ^ ; void i2c_start();
void i2c_stop();
void i2c_send(unsigned char dat);
unsigned char i2c_recv();
char i2c_wait_ack();
void i2c_send_ack();
#endif

i2c.c

 #include "i2c.h" 

 void i2c_start()
{
/* SCL SDA 为高电平时 SDA 变为低电平 */
I2C_SCL = ;
I2C_SDA = ;
I2C_SDA = ;
I2C_SCL = ; /* 钳住I2C总线,准备发送或接收数据 */
} void i2c_stop()
{
/* SCK 高电平期间 SDA 由低变高 */
I2C_SCL = ;
I2C_SDA = ;
I2C_SCL = ;
I2C_SDA = ;
} void i2c_send(unsigned char dat)
{
char i = ;
while(i--)
{
I2C_SCL = ;
if(dat & 0x80)
{
I2C_SDA = ;
}
else
{
I2C_SDA = ;
}
I2C_SCL = ;
dat = dat<<;
}
//等待ACK回复信号
i2c_wait_ack();
} unsigned char i2c_recv()
{
unsigned char dat = ;
char i = ;
I2C_SDA = ;
while(i--)
{
I2C_SCL = ;
dat<<=; //这里要有一定延时要求是 > 1.3us
I2C_SCL = ;
if(I2C_SDA)
{
//以下3者结果一样
//dat++;
//dat += 1;
dat |= ;
}
//dat |= (unsigned char)I2C_SDA;
}
i2c_send_ack();
return dat;
} //无响应返回0
char i2c_wait_ack()
{
unsigned char time_out = 0xff;
I2C_SCL = ;
I2C_SDA = ;
I2C_SCL = ; //由 slaver 拉低 SDA 表示回应
while(I2C_SDA)
{
time_out--;
if( == time_out)
{
i2c_stop();
return ;
}
}
return ;
} void i2c_send_ack()
{
//拉低SDA 响应ACK 当SCL 由低电平变高电平时 从机接收
I2C_SCL = ;
I2C_SDA = ;
I2C_SCL = ;
I2C_SCL = ;
}

IR 红外接收

IR.h

 #ifndef __IR__
#define __IR__
#include <reg52.h>
#include "delay.h"
#include <string.h> //公用
typedef struct {
unsigned char custom_height;
unsigned char custom_lower;
unsigned char ir_code;
unsigned char re_ir_code;
} IR_CODE, *pIR_CODE; //接收
sbit IR = P3 ^ ;//红外线一体接收头 OUT void init_IR();
IR_CODE IR_recv();
#endif

IR.c

 #include "IR.h"

 void init_IR()
{
//接收
EA = ; //总中断开
EX0 = ; //IR 接收头使用外部中断0 来处理
IT0 = ; //下降沿触发
} //接收
IR_CODE IR_recv()
{
/**
* 数据格式:
* 9ms低电平 4.5ms高电平 头部
* 定制高位 定制低位 数据码 数据反码
* 1: 560us低电平 1680us高电平 0.56ms 1.7ms
* 0: 560us低电平 560us高电平 0.56ms 0.56ms
*/
IR_CODE ir_code;
unsigned char i,k;
unsigned char *ir_char_p;
unsigned char ir_char;
ir_char_p = (unsigned char *)&ir_code; //栈分配 IR_CODE 竟然还要手动清0
memset(&ir_code, , ); delayms(); //9ms 内必须是低电平否则就不是头信息
if( == IR)
{
while(! IR);//等待4.5ms的高电平 //检测是否是 2.5ms 重码
delayms();
if( == IR)
{
//k 4位编码
for(k=; k<; k++)
{
ir_char = 0x0;
//i 每一个编码的 8bit
for(i=;i<;i++)
{
while(IR); //等待变为低电平时
while(! IR); //等待变为高电平后
delay700us(); //休眠700us 后读值
ir_char |= (char)IR << i;//先存低位
//使用下面指针操作就会失败出现不稳定
//*ir_char_p |= (char)IR << i;
}
*ir_char_p = ir_char;
ir_char_p++;
} //计算反码 code码是否正确
if(ir_code.ir_code != ~(ir_code.re_ir_code))
{
memset(&ir_code, , );
}
}
}
return ir_code;
}

str 处理相关

str.h

 #ifndef __STR__
#define __STR__
unsigned char num_to_str(unsigned char num);
#endif

str.c

 #include "str.h"

 unsigned char num_to_str(unsigned char num)
{
unsigned char chr;
//asc2 表 0 在前面
if(<= num && >= num)
{
chr = num + '';
}
return chr;
}

重点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

 #ifndef __TEA5767__
#define __TEA5767__ #include <string.h>
#include "i2c.h"
#include "uart.h"
#include "str.h"
#include "delay.h"
#include "lcd1602.h"
#include "eeprom.h" typedef struct{
unsigned char st1;
unsigned char st2;
unsigned char st3;
unsigned char st4;
unsigned char st5;
} TEA_DAT, *PTEA_DAT; typedef struct {
unsigned char high; //表示整数 100
unsigned char low; //表示小数 5
} TEA_CH, *PTEA_CH; /* 地址定义 */
#define TEA5767_ADDR_W 0xc0 //tea5767 写地址
#define TEA5767_ADDR_R 0xc1 //tea5767 读地址
#define TEA5767_CLK 32768 //tea5767 晶振
#define TEA5767_MAX_KHZ 108000 //最高频率 108M
#define TEA5767_MIN_KHZ 87500 //最低频率 87.5M
#define TEA5756_HLSI //高混频器 经过测试,使用SM自动搜索功能时必须设此值 手动搜索 无所谓 unsigned long tea5767_Khz_to_pll(unsigned long Khz);
unsigned long tea5767_pll_to_Khz(TEA_DAT dat);
TEA_DAT tea5767_set_receiver(unsigned long Khz);
TEA_DAT tea5767_search(unsigned long Khz);
void tea5767_auto_search();
void tea5767_tiny_auto_search();
void tea5767_write(TEA_DAT dat);
TEA_DAT tea5767_read();
void tea5767_mute(unsigned char ch_num); //Lcd显示
void sohw_search(unsigned long Khz, unsigned char channel);
//存储电台
void save_eeprom(unsigned long Khz, unsigned char channel);
//设定ch
unsigned long set_ch(unsigned char ch_num);
#endif

tea5767.c

 #include "tea5767.h"

 unsigned char mute = ;
void tea5767_mute(unsigned char ch_num)
{
TEA_DAT dat;
unsigned long Khz,pll;
Khz = set_ch(ch_num);
//静音位写 1
pll = tea5767_Khz_to_pll(Khz);
dat.st1 = (mute%) << | (pll>>) & 0x3f;
dat.st2 = pll;
dat.st3 = ;
#ifdef TEA5756_HLSI
dat.st3 |= <<;
#endif
dat.st4 = 0x11;
dat.st5 = 0x40;
tea5767_write(dat); if(mute%)
{
lcd1602_pos();
lcd1602_write_data('M');
lcd1602_write_data('U');
lcd1602_write_data('T');
lcd1602_write_data('E');
}
mute++;
} unsigned long tea5767_Khz_to_pll(unsigned long Khz)
{
#ifdef TEA5756_HLSI
return *(Khz*+)/TEA5767_CLK;
#else
return *(Khz*-)/TEA5767_CLK;
#endif
} unsigned long tea5767_pll_to_Khz(TEA_DAT dat)
{
unsigned long Khz,pll;
pll = ((dat.st1 & 0x3f)<< | dat.st2);
#ifdef TEA5756_HLSI
Khz = (pll*TEA5767_CLK/-*)/;
#else
Khz = (pll*TEA5767_CLK/+*)/;
#endif return Khz;
} void tea5767_write(TEA_DAT dat)
{
i2c_start();
i2c_send(TEA5767_ADDR_W);
i2c_send(dat.st1);
i2c_send(dat.st2);
i2c_send(dat.st3);
i2c_send(dat.st4);
i2c_send(dat.st5);
i2c_stop();
} TEA_DAT tea5767_read()
{
TEA_DAT dat;
i2c_start();
i2c_send(TEA5767_ADDR_R);
dat.st1 = i2c_recv();
dat.st2 = i2c_recv();
dat.st3 = i2c_recv();
dat.st4 = i2c_recv();
dat.st5 = i2c_recv();
i2c_stop();
return dat;
} TEA_DAT tea5767_set_receiver(unsigned long Khz)
{
unsigned long pll;
TEA_DAT dat; pll = tea5767_Khz_to_pll(Khz); /* 发送5个控制位 顺序是 1 2 3 4 5 字节的高位先发
* HLSL = 0 : 4*(102.4*1000000-225*1000)/32768
* HLSL = 1 : 4*(102.4*1000000+225*1000)/32768
* PLL WORD = 0x30ef
*/
dat.st1 = (pll>>) & 0x3f;
dat.st2 = pll;
dat.st3 = ;
#ifdef TEA5756_HLSI
dat.st3 |= <<;
#endif
dat.st4 = 0x11;
dat.st5 = 0x40; tea5767_write(dat);
delayms();
dat = tea5767_read();
return dat;
} //自动搜索 87.5 ~ 108M 由低向高搜索
TEA_DAT tea5767_search(unsigned long Khz)
{
unsigned long pll;
TEA_DAT dat; pll = tea5767_Khz_to_pll(Khz);
dat.st1 = ((pll>>) & 0x3f) | (<<);
dat.st2 = pll;
//搜索停止 信号强度 01:5 10:7 11:10
//dat.st3 = 1 | 1<<7 | 1<<6 |1<<5 ;
dat.st3 = | << | << ;
#ifdef TEA5756_HLSI
dat.st3 |= <<;
#endif dat.st4 = 0x11;
dat.st5 = 0x40;
tea5767_write(dat);
delayms();
dat = tea5767_read();
while(dat.st1 != (dat.st1 | (<<)))
{
dat = tea5767_read();
}
return dat;
} //自动搜台 存台到 eeprom
void tea5767_auto_search()
{
TEA_DAT dat;
unsigned long Khz;
unsigned char if_counter;
unsigned char channel = ;
Khz = TEA5767_MIN_KHZ; //清液晶屏
lcd1602_clear(); dat = tea5767_search(Khz); //检测信号是否满足要求
while(dat.st1 != (dat.st1 | (<<)))
{
//if count 在 0x31 ~ 0x3e 之间
if_counter = (dat.st3 & 0x7f);
if((0x31 < if_counter) && (0x3e > if_counter))
{
//比较leve 电平确认是否收到台 实际测试使用此数 不会漏台
if((dat.st4>>) > )
{
Khz = tea5767_pll_to_Khz(dat); save_eeprom(Khz, channel);
channel++;
}
} //显示当前频率
sohw_search(Khz, channel); //计算搜到台的频率 加上10Khz 后重新搜索 实际测试使用此数 不会漏台
Khz += ;
dat = tea5767_search(Khz);
}
} //细致的搜台
void tea5767_tiny_auto_search()
{
TEA_DAT dat;
unsigned long Khz;
unsigned char channel = ;
Khz = TEA5767_MIN_KHZ;
//Khz = 100000; //清液晶屏
lcd1602_clear(); //擦除eeprom
eeprom_erase(); while(Khz <= TEA5767_MAX_KHZ)
{
dat = tea5767_set_receiver(Khz);
//比较leve 电平确认是否收到台 实际测试使用此数 不会漏台
if((dat.st4>>) > )
{
//存储电台
save_eeprom(Khz, channel++);
} //显示当前频率
sohw_search(Khz, channel);
//频率由低到高 每次增加10Khz
Khz += ;
}
} void sohw_search(unsigned long Khz, unsigned char channel)
{
unsigned char high, low;
lcd1602_pos();
lcd1602_write_data('S');
lcd1602_write_data('e');
lcd1602_write_data('a');
lcd1602_write_data('r');
lcd1602_write_data('c');
lcd1602_write_data('h');
lcd1602_write_data(':');
//输出频率 如果是 100M 以下第1位为空
high = Khz/;
low = Khz%/;
if(high>= )
{
lcd1602_write_data(num_to_str(high/));
}
else
{
lcd1602_write_data(' ');
}
lcd1602_write_data(num_to_str(high%/));
lcd1602_write_data(num_to_str(high%));
lcd1602_write_data('.');
lcd1602_write_data(num_to_str(low));
lcd1602_write_data('M');
lcd1602_write_data('h');
lcd1602_write_data('z'); //显示收到的频道
lcd1602_pos();
lcd1602_write_data('C');
lcd1602_write_data('h');
lcd1602_write_data('a');
lcd1602_write_data('n');
lcd1602_write_data('n');
lcd1602_write_data('e');
lcd1602_write_data('l');
lcd1602_write_data(':'); lcd1602_write_data(num_to_str(channel / ));
lcd1602_write_data(num_to_str(channel % ));
} //存储电台
void save_eeprom(unsigned long Khz, unsigned char channel)
{
TEA_CH ch;
ch.high = Khz/;
ch.low = Khz%/;
eeprom_prog(channel*, ch.high);
eeprom_prog(channel*+, ch.low);
} //设定ch
unsigned long set_ch(unsigned char ch_num)
{
unsigned long Khz;
TEA_CH ch;
ch.high = eeprom_read(ch_num*);
ch.low = eeprom_read(ch_num*+);
//合并为 Khz
Khz = ch.high*; //直接使用 *1000 会计算错误 分为2部正确
Khz *= ;
Khz += ch.low*; //设定接收频率
tea5767_set_receiver(Khz); //清液晶屏
lcd1602_clear(); //显示频道信息
lcd1602_pos();
lcd1602_write_data('C');
lcd1602_write_data('h');
lcd1602_write_data(':'); //频道数从 0 开始计
lcd1602_write_data(num_to_str(ch_num / ));
lcd1602_write_data(num_to_str(ch_num % )); lcd1602_pos();
if(ch.high>= )
{
lcd1602_write_data(num_to_str(ch.high/));
}
else
{
lcd1602_write_data(' ');
}
lcd1602_write_data(num_to_str(ch.high%/));
lcd1602_write_data(num_to_str(ch.high%));
lcd1602_write_data('.');
lcd1602_write_data(num_to_str(ch.low));
lcd1602_write_data('M');
lcd1602_write_data('h');
lcd1602_write_data('z'); return Khz;
}

eeprom.c

 #include "eeprom.h"

 /* 执行完操作以后安全锁 */
void eeprom_lock_ISP()
{
ISP_CONTR = ;
ISP_CMD = ;
ISP_TRIG = ;
ISP_ADDRH = 0xff;
ISP_ADDRL = 0xff;
} /* 擦除指定地址所在的整个扇区 */
void eeprom_erase(unsigned int addr)
{
addr += BASE_ADDR; //发送地址
ISP_ADDRH = addr >> ;
ISP_ADDRL = addr; //发送解锁命令
ISP_CONTR = En_Wait_ISP; //发擦除命令
ISP_CMD = CMD_Erase; //发送触发命令
ISP_TRIG = 0x46;
ISP_TRIG = 0xB9; //最后锁定 ISP 仿误操作
eeprom_lock_ISP();
} unsigned char eeprom_read(unsigned int addr)
{
addr += BASE_ADDR; //发送地址
ISP_ADDRH = addr >> ;
ISP_ADDRL = addr; //发送解锁命令
ISP_CONTR = En_Wait_ISP; //发读命令
ISP_CMD = CMD_Read; //发送触发命令
ISP_TRIG = 0x46;
ISP_TRIG = 0xB9; //最后锁定 ISP 仿误操作
eeprom_lock_ISP(); return ISP_DATA;
} void eeprom_prog(unsigned int addr, unsigned char dat)
{
addr += BASE_ADDR; //发送要保存的数据
ISP_DATA = dat; //发送地址
ISP_ADDRH = addr >> ;
ISP_ADDRL = addr; //发送解锁命令
ISP_CONTR = En_Wait_ISP; //发编程命令
ISP_CMD = CMD_Prog; //发送触发命令
ISP_TRIG = 0x46;
ISP_TRIG = 0xB9; //最后锁定 ISP 仿误操作
eeprom_lock_ISP();
}

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

自动搜台特点:

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

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

3,只能用 TEA5756_HLSI 

自动搜台流程:

1,设定 好 SM 位 和 SSL 后

2,设一个频率

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

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

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

手动搜台特点:

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

手动搜台流程:

1,写入一个频率

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

3,自行判断,频率范围