基于51单片机FM数字收音机
(程序+原理图+PCB+设计报告)
功能介绍
具体功能:
该系统利主要由STC89C51单片机、液晶显示器、按键、调频收音模块TEA5767、功放LM386组成。
1.收音芯片采用TEA5767模块,采用LM386芯片放大音频功率;
2.LCD1602液晶显示当前所收听的FM频道;
3.可以通过按键进行调换,实现87.5MHz~108MHz调频广播的接收;
演示视频:
基于51单片机FM数字收音机设计
添加图片注释,不超过 140 字(可选)
程序
/****************************************************************
/***公众号:木子单片机****
工程名称:数字收音机
功能: 以LCD1602为显示的TEA5767模块的收音机
***************************************************************/
#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--);
}
}
//******************************************
void init(void)
{
uchar idata sbuf[5]={0XF0,0X2C,0XD0,0X10,0X40}; //FM模块预设值
uchar idata rbuf[5]={0X00,0X00,0X00,0X00,0X00};
uchar idata ampint[5]={0X27,0X40,0X42,0X46,0XC3};
FM_PLL=0X302C;
FM_FREQ=97000000; //开机预设频率
PLL_HIGH=0;
PLL_LOW=0;
delay100ms();
delay100ms();
P1=0XFF;
P2=0XFF;
I2C_byte1=0XF0; //FM模块预设值
I2C_byte2=0X2C;
I2C_byte3=0XD0;
I2C_byte4=0X10;
byte1=0X27;
byte2=0X40;
byte3=0X42;
byte4=0X46;
sendnbyte(&ADDRESS_SEND,numbyte);
delay100ms();
AMP_sendnbyte(&ADDRESS_AMP,numbyte_AMP);
}
//************************************************
//送n字节数据子程序
void sendnbyte(uchar idata *sla, uchar n)
{
uchar idata *p;
sbuf[0]=I2C_byte1;
sbuf[1]=I2C_byte2;
sbuf[2]=I2C_byte3;
sbuf[3]=I2C_byte4;
I2C_start(); // 发送启动信号
sendbyte(sla); // 发送从器件地址字节
checkack(); // 检查应答位
if(F0 == 1)
{
NACK = 1;
return; // 若非应答表明器件错误置错误标志位NACK
}
p = &sbuf[0];
while(n--)
{
sendbyte(p);
checkack(); // 检查应答位
if (F0 == 1)
{
NACK=1;
return; // 若非应答表明器件错误置错误标志位NACK
}
p++;
}
stop(); // 全部发完则停止
}
//***********************************************
延迟100ms
void delay100ms()
{
uchar i;
for(i=100;i>0;i--){delay1ms();}
}
//**********************************************
//延迟1ms
void delay1ms(void)
{
uchar i;
for(i=1000;i>0;i--){;}
}
//*************************************************
//在SCL为高时,SDA由高变低即为I2C传输开始
void I2C_start(void)
{
SDA=1;
SCL=1;
DELAY5US;
SDA=0;
}
//****************************************************
//发送一个字节数据子函数
void sendbyte(uchar idata *ch)
{
uchar idata n = 8;
uchar idata temp;
temp = *ch;
while(n--)
{
if((temp&0x80) == 0x80) // 若要发送的数据最高位为1则发送位1
{
SDA = 1; // 传送位1
SCL = 1;
DELAY5US;
}
else
{
SDA = 0; // 否则传送位0
SCL = 1;
DELAY5US;
SCL = 0;
}
temp = temp<<1; // 数据左移一位
}
}
//发送n字节数据子程序
void AMP_sendnbyte(uchar idata *sla, uchar n)
{
uchar idata *p;
ampint[0]=byte1;
ampint[1]=byte2;
ampint[2]=byte3;
ampint[3]=byte4;
ampint[4]=byte5;
I2C_start(); // 发送启动信号
sendbyte(sla); // 发送从器件地址字节
checkack(); // 检查应答位
if(F0 == 1)
{
NACK = 1;
return; // 若非应答表明器件错误置错误标志位NACK
}
p=&int[0];
while(n--)
{
sendbyte(p);
checkack(); // 检查应答位
if (F0 == 1)
{
NACK=1;
return; // 若非应答表明器件错误置错误标志位NACK
}
p++;
}
stop(); // 全部发完则停止
}
//****************************************
硬件设计
使用元器件:
单片机:STC89C51;
(注意:单片机是通用的,无论51还是52、无论stc还是at都一样,引脚功能都一样。程序也是一样的。)
9*15万用板;40脚IC座;
LCD1602液晶;103电位器(蓝白);
16P排阵;16脚液晶IC座;
220uf电解电容;100uf电解电容;
10k电阻;10uf电容;30pf电容*2;
12M晶振;轻触按键*3;
TEA5767模块;104pf*2;
103电位器(精密大号);
耳机插口;伸缩天线;
LM386;8脚IC座;
2P白色插口;红黑并线;
8欧5W喇叭;
导线:若干;
添加图片注释,不超过 140 字(可选)
流程图:
设计资料
01原理图
本系统原理图采用Altium Designer19设计,具体如图!
添加图片注释,不超过 140 字(可选)
02PCB
本系统pcb采用Altium Designer19设计,具体如图!
添加图片注释,不超过 140 字(可选)
03程序
本设计使用软件Keil5版本编程设计!具体如图!
添加图片注释,不超过 140 字(可选)
04设计报告
一万两千字设计报告,具体如下!
添加图片注释,不超过 140 字(可选)
05设计资料
资料获取请关注同名公众号,全部资料包括程序(含注释)、AD原理图、PCB、设计报告、流程图、答辩PPT、实物图、元件清单等。具体内容如下,全网最全! !
可以关注下方公众号!
点赞分享一起学习成长。