链接:https://pan.baidu.com/s/10tXZyQjqkFi-KFaApVWgHw
提取码:r0bg
硬件设计
该系统利主要由STC89C52单片机、液晶显示器、按键、调频收音模块TEA5767、功放LM386组成[1]。实际运行时,用TEA5767搜索频率,利用单片机STC89C52控制处理,经LM386芯片放大音频功率同时再通过液晶显示器显示频率,最终实现87.5MHz~108MHz调频广播的接收
系统以STC89C52单片机作为控制模块,无线FM模块作为调频选台模块。系统框图如图1-1所示。
原理图:
程序设计
/****************************************************************
***************************************************************/
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define DELAY5US _nop_();_nop_();_nop_();_nop_();_nop_();
//**************TEA5767模块接线方法********************
sbit SDA=P1^0;
sbit SCL=P1^1;
//*************频率调节按键接线************************
sbit Key1=P1^2;
sbit Key2=P1^3;
//==============LCD1602接口连接方法=====================
/*-----------------------------------------------------
|DB0-----P0.0 | DB4-----P0.4 | RW-------P2.3 |
|DB1-----P0.1 | DB5-----P0.5 | RS-------P2.4 |
|DB2-----P0.2 | DB6-----P0.6 | E--------P2.2 |
|DB3-----P0.3 | DB7-----P0.7 |
---------------------------------------------------*/
//================================================*/
#define LCM_Data P0 //LCD1602数据接口
#define Busy 0x80 //用于检测LCM状态字中的Busy标识
sbit LCM_RW = P2^6; //读写控制输入端,LCD1602的第五脚
sbit LCM_RS = P2^5; //寄存器选择输入端,LCD1602的第四脚
sbit LCM_E = P2^7; //使能信号输入端,LCD1602的第6脚
//*****************参数定义*****************************
unsigned long int FM_FREQ; //频率
unsigned short int FM_PLL; //PLL
uchar idata sbuf[5]; // 数据发送缓冲区
uchar idata numbyte;
uchar idata numbyte_AMP;
uchar idata ADDRESS_AMP;
uchar idata ADDRESS_SEND; //TEA5767发送地址
uchar idata ADDRESS_RECEIVE; //TEA5767接收地址
uchar idata rbuf[5]; // 数据接收缓冲区
uchar idata ampint[5];
uchar bdata PLL_HIGH;
uchar bdata PLL_LOW; //设定用于搜索和预设的可编程频率合成器
uchar bdata I2C_byte1;//发送的五字节TEA5767可位寻址的设置值
uchar bdata I2C_byte2;
uchar bdata I2C_byte3;
uchar bdata I2C_byte4;
uchar bdata I2C_byte5;
sbit MUTE =I2C_byte1^7;//如果MUTE=1,则左右声道被静音;MUTE=0,左右声道正常工作
sbit SM = I2C_byte1^6; //SM=1,则处于搜索模式;SM=0,不处于搜索模式
sbit SUD=I2C_byte3^7; //SUD=1,增加频率搜索;SUD=0,减小频率搜索
uchar byte1;
uchar byte2;
uchar byte3;
uchar byte4;
uchar byte5;
uchar num1,num2,num3,num4;
uchar tab1[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
bit bdata NACK; // 错误标志位
//**********相关函数声明**************************************
void init(void); //TEA5767初始化
void delay600ms(void); //延迟600ms
void delay100ms(void); //延迟100ms
void delay10ms();
void delay1ms(void); //延迟1ms
void sendnbyte(uchar idata *sla, uchar n);//与sendbyte函数构成I2C 数据发送函数
void I2C_start(void); //I2C 传输开始
void sendbyte(uchar idata *ch);
void checkack(void); //检查应答讯号
void stop(void); //I2C传输结束
void AMP_sendnbyte(uchar idata *sla,uchar numbyte_AMP);
void key_scan(void); //键扫描
void search_up(void); //接收频率向上加
void search_down(void); //接收频率向下减
void setByte1Byte2(void); //设置第一第二字节频率
void LCMInit(void);//LCD初始
void DelayMs(uint Ms);//1MS基准延时程序
void WriteDataLCM (uchar WDLCM);//LCD模块写数据
void WriteCommandLCM (uchar WCLCM,BuysC); //LCD模块写指令
uchar ReadStatusLCM(void);//读LCD模块的忙标
void DisplayOneChar(uchar X,uchar Y,uchar ASCII);//在第X+1行的第Y+1位置显示一个字符
void LCDshow(void);
void DelayMs(uint Ms);
void show(); //开机问候语
//*****************主程序******************************
void main(void)
{
numbyte = 5;
numbyte_AMP=5;
ADDRESS_SEND = 0xC0;// TEA5767写地址 1100 0000
ADDRESS_RECEIVE=0XC1;//TEA5767读地址 1100 0001
ADDRESS_AMP=0X8E;
init(); // 初始化TEA5767
show(); //开机问候语
LCMInit();//LCD初始
LCDshow();
while(1)
{
key_scan(); //键扫描
}
}
//**************开机问候语**************************
void show()
{
LCMInit();//LCD初始
DisplayOneChar(0, 1,'H');//
DisplayOneChar(0, 2,'e');//
DisplayOneChar(0, 3,'l');//
DisplayOneChar(0, 4,'l');//
DisplayOneChar(0, 5,'o');//
DisplayOneChar(0, 6, ',');
DisplayOneChar(0, 7,'W');//
DisplayOneChar(0, 8,'e');//
DisplayOneChar(0, 9, 'l');
DisplayOneChar(0, 10, 'c');
DisplayOneChar(0, 11, 'o');
DisplayOneChar(0, 12, 'm');
DisplayOneChar(0, 13, 'e');
DelayMs(500);
DisplayOneChar(1, 1,' ');// 显示姓名
DisplayOneChar(1, 2,' ');//
DisplayOneChar(1, 3,' ');//
DisplayOneChar(1, 4,' ');//
DisplayOneChar(1, 5,' ');//
DisplayOneChar(1, 6,' ');//
DisplayOneChar(1, 7,' ');
DisplayOneChar(1, 8,' ');//
DisplayOneChar(1, 9,' ');//
DisplayOneChar(1, 10,' ');
DisplayOneChar(1, 11,' ');
DisplayOneChar(1, 12,' ');
DisplayOneChar(1, 13,' ');
DisplayOneChar(1, 14,' ');
DelayMs(500);
}
//**************按键扫描程序************************
void key_scan(void)
{
if(Key1==0)
{
delay10ms();
if(Key1==0)
{
while(Key1==0);
search_up(); //频率向上
LCDshow();
delay600ms();
}
}
if(Key2==0)
{
delay10ms();
if(Key2==0)
{
while(Key2==0);
search_down(); //频率向下
LCDshow();
delay600ms();
}
}
}
//*********************LCD1602显示程序*********************
void LCDshow(void)
{
num1=FM_FREQ/100000000;
num2=(FM_FREQ%100000000)/10000000;
num3=(FM_FREQ%10000000)/1000000;
num4=(FM_FREQ%1000000)/100000;
DisplayOneChar(0, 4,'F');//
DisplayOneChar(0, 5,'M');//
DisplayOneChar(0, 6,'R');//
DisplayOneChar(0, 7,'a');//
DisplayOneChar(0, 8,'d');//
DisplayOneChar(0, 9,'i');//
DisplayOneChar(0, 10,'o');//
DisplayOneChar(1, 4, tab1[num1]);
DisplayOneChar(1, 5, tab1[num2]);
DisplayOneChar(1, 6, tab1[num3]);
DisplayOneChar(1, 7, '.');
DisplayOneChar(1, 8, tab1[num4]);
DisplayOneChar(1, 9,'M');//
DisplayOneChar(1, 10,'H');//
DisplayOneChar(1, 11,'Z');//
}
/*======================================================================
LCM初始化
======================================================================*/
void LCMInit(void)
{
LCM_Data = 0;
WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号
DelayMs(5);
WriteCommandLCM(0x38,0);
DelayMs(5);
WriteCommandLCM(0x38,0);
DelayMs(5);
WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号
WriteCommandLCM(0x08,1); //关闭显示
WriteCommandLCM(0x01,1); //显示清屏
WriteCommandLCM(0x06,1); // 显示光标移动设置
WriteCommandLCM(0x0C,1); // 显示开及光标设置
DelayMs(100);
}
//==============================LCD1602显示子程序================================================
// 写数据函数: E =高脉冲 RS=1 RW=0
//======================================================================*/
void WriteDataLCM(uchar WDLCM)
{
ReadStatusLCM(); //检测忙
LCM_Data = WDLCM;
LCM_RS = 1;
DelayMs(1);
LCM_RW = 0;
DelayMs(1);
LCM_E = 0; //若晶振速度太高可以在这后加小的延时
LCM_E = 0; //延时
DelayMs(1);
LCM_E = 1;
}
/*====================================================================
写指令函数: E=高脉冲 RS=0 RW=0
======================================================================*/
void WriteCommandLCM(uchar WCLCM,BuysC) //BuysC为0时忽略忙检测
{
if (BuysC) ReadStatusLCM(); //根据需要检测忙
LCM_Data = WCLCM;
LCM_RS = 0;
LCM_RW = 0;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
}
/*====================================================================
正常读写操作之前必须检测LCD控制器状态:E=1 RS=0 RW=1;
DB7: 0 LCD控制器空闲,1 LCD控制器忙。
读状态
======================================================================*/
uchar ReadStatusLCM(void)
{
LCM_Data = 0xFF;
LCM_RS = 0;
LCM_RW = 1;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
while (LCM_Data & Busy); //检测忙信号
return(LCM_Data);
}
/*======================================================================
功 能: 在1602 指定位置显示一个字符:第一行位置0~15,第二行16~31
说 明: 第 X 行,第 y 列 注意:字符串不能长于16个字符
======================================================================*/
void DisplayOneChar( uchar X, uchar Y, uchar ASCII)
{
X &= 0x1;
Y &= 0xF; //限制Y不能大于15,X不能大于1
if (X) Y |= 0x40; //当要显示第二行时地址码+0x40;
Y |= 0x80; // 算出指令码
WriteCommandLCM(Y, 0); //这里不检测忙信号,发送地址码
WriteDataLCM(ASCII);
}
/*====================================================================
设定延时时间:x*1ms
====================================================================*/
void DelayMs(uint Ms)
{
uint i,TempCyc;
for(i=0;i<Ms;i++)
{
TempCyc = 250;
while(TempCyc--);
}
}
.
.