本帖最后由 svvv 于 2020-3-6 20:39 编辑
本项目是51单片机入门级别,采用商用低成本单片机制作,电路具有非常高的可靠性和简易调试最小化系统,本项目采用超精简电路,led数码直接又单片机驱动,操作控制有红外遥控器设置功能主要有,往下/往上自动搜索,往下/往上步进100hkz,音量16级调节,具体可在例程中仔细阅读
led 驱动限流电阻Q1-Q4可根据实际情况选用,100-330欧姆,
rda5807左右声道隔直电容47uf-100uf之间选用 rda5807晶振选用晶振32.768khz
其余电源滤波电容0.1uf 和47uf-100uf均可
这款单片机编译需要安装芯圣公司提供的插件环境才可编译,
本例程把i2c驱动分离,具有移植复用性。
本例程由楼主精心调试,但也难免有错误,只做学习单片机交流使用,还提示各位看官请勿拿来大量生产!
全部资料51hei下载地址:
程序:
rda5807Project.zip
(11.04 KB, 下载次数: 104)
原理图:
rda5807Projectpcb.zip
(12.88 KB, 下载次数: 61)
单片机源程序如下:
- /**
- * ************************************************************************************
- * 微电脑数控型收音机i2c工程
- *
- * ************************************************************************************
- * @Examle Version V0.0.0.1
- * @Demo Version V0.0.0.1
- * @Date 2019.07.22
- * ************************************************************************************
- * ************************************************************************************
- **/
- #define ALLOCATE_EXTERN
- #include "HC89S003F4.h"
- #include<intrins.h>
- #include "iic.h"
- #include "radio.h"
-
- uchar duan[11]={0x77,0x11,0x6b,0x3b,0x1d,0x3e,0x7e,0x13,0x7f,0x3f,0x75};
-
- uchar Display_FM[8];
- extern unsigned char RDA_reg_data[8];
- unsigned char IR_code[4] = {0,0,0,0};//存放四组数据
- uchar zd=0; //
- sbit IR_Out=P0^7; //HS0038接收头OUT端直接连P3.2(INT0)
- /**************************延时0.9ms子程序**********************/
- void Delay_ms(unsigned int fui_i)
- {
- unsigned int fui_j;
- for(;fui_i > 0;fui_i --)
- for(fui_j = 1596;fui_j > 0;fui_j --);
- }
- void DelayUs(uint us)
- {
- for(; us>0; us--)
- {
- _nop_();
- _nop_();
- _nop_();
- }
- }
- /**************************** 延时子程序 ************************/
- void Delay(void)
- {
- uchar i,j,k;
- for(i=200;i>0;i--)
- for(j=200;j>0;j--)
- for(k=3;k>0;k--) ;
- }
- void DigDisplay()
- {
- uchar i;
- uchar smgduan[4];
- smgduan[0]=duan[Display_FM[0]];
- smgduan[1]=duan[Display_FM[1]];
- smgduan[2]=duan[Display_FM[2]]+0x80;
- smgduan[3]=duan[Display_FM[3]];
- P2=0x00;//消隐
- for(i=0;i<4;i++)
- {
- switch(i) //位选,选择点亮的数码管,
- {
- case(0):
- P0_2=0;P0_3=1;P0_4=1;P0_5=1; break;//显示第0位
- case(1):
- P0_2=1;P0_3=0;P0_4=1;P0_5=1; break;//显示第1位
- case(2):
- P0_2=1;P0_3=1;P0_4=0;P0_5=1; break;//显示第2位
- case(3):
- P0_2=1;P0_3=1;P0_4=1;P0_5=0; break;//显示第3位
- }
- P2=smgduan[i];//发送段码
- Delay_ms(1); //间隔一段时间扫描
- P2=0x00;//消隐
- }
- }
-
- /***************************************************************************************
- * @实现效果 对P00口进行高、低电平转换,LED1不断翻转
- ***************************************************************************************/
- void main()
- { uchar i;
- WDTCCR = 0x00; //关闭看门狗
- //本例程为方便测试关闭看门狗,实际使用中,建议客户打开看门狗,详见WDT复位
- CLKSWR = 0x51; //选择内部高频RC为系统时钟,内部高频RC 2分频,Fosc=16MHz
- CLKDIV = 0x01; //Fosc 1分频得到Fcpu,Fcpu=16MHz
- IIC_GPIO_Init();
- // P2M0 = P2M0&0x0F|0x80; //P21设置为推挽输出
- // P0M1 = P0M1&0x0F|0x20; //P03设置为上拉输入
- // TXD_MAP = 0x21; //TXD映射P21
- // RXD_MAP = 0x03; //RXD映射P03
- // T4CON = 0x06; //T4工作模式:UART1波特率发生器
- P0M1 = P0M1&0x00|0x88; //P1.0.1设置为推挽输出
- P0M2 = P0M2&0x00|0x88; //P1.0.1设置为推挽输出
-
- // P0M0 = P0M0&0xf0|0x0a; //P1.0.1设置为推挽输出
- // P1M0 = P1M0&0x0f|0xa0; //P2.0.1设置为推挽输出
-
- P2M0 = P2M0&0x00|0x88; //P1.0.1设置为推挽输出
- P2M1 = P2M1&0x00|0x88; //P1.0.1设置为推挽输出
- P2M2 = P2M2&0x00|0x88; //P1.0.1设置为推挽输出
- P2M3 = P2M3&0x00|0x88; //P1.0.1设置为推挽输出
- // P0M0 = P0M0&0xF0|0x08; //P00设置为推挽输出
- P0M3 = P0M3&0x0F|0x00; //P27设置为带SMT输入
- PITS1 |= 0x40; //INT15下降沿中断
- PINTE0 |= 0x80; //使能INT15
- IE1 |= 0x40; //打开INT8-15中断
- // EA = 1; //打开总中断
-
- // TH4 = 0xFF;
- // TL4 = 0x98; //波特率9600
- // SCON2 = 0x02; //8位UART,波特率可变
- // SCON = 0x10; //允许串行接收
- // IE |= 0X10; //使能串口中断
- EA = 1;
-
- RDA5807_power();
- RDA_set(1077);
-
- while(1){
- show_frequency();
- DigDisplay();
-
-
- if(zd==1){
-
- if(IR_code[2]==0x07){
- RDA_reg_data[0] &= ~(1 << 1); //SEEK DOWN
- RDA5807_FM_seek();
- }else if(IR_code[2]==0x03){
- RDA_reg_data[0] |= (1 << 1); //SEEK UP
- RDA5807_FM_seek();
-
- }else if(IR_code[2]==0x0b){
-
- setup(1);
- }else if(IR_code[2]==0x50){
-
- setup(0);
- }else if(IR_code[2]==0x0f){
- setvol(0);
- i=100;
- while(i--){
- show_vol();
- DigDisplay();
- }
- }else if(IR_code[2]==0x13){
- setvol(1);
- i=100;
- while(i--){
- show_vol();
- DigDisplay();
- }
- }
- zd=0;
- }
-
-
-
-
-
-
- }
-
- }
-
- /************************中断0解码服务子程序**********************/
- void int0(void) interrupt INT2_7_VECTOR
- {
- unsigned char i,j;
-
- EA = 0;
- if(PINTF0&0x80) //判断INT15中断标志位
- {
- PINTF0 &=~ 0x80;
-
- // 关闭外部中断0
-
- i = 10; // 0.793ms延时,运行10次
- while( --i )
- {
- // 定时0.793ms,延时0.793ms*10=7.93ms
- DelayUs(800);
- // 这7.93ms期间只要IR_Out变高电平,就非合法的红外信号,跳出
- if( IR_Out )
- { // P0_0= 1;
- EA = 1; // 准许中断
-
- return ;
- }
- }
- // P0_0=1;
- // 程序进行到这里,表明是合法的红外信号(利用9ms判断)
- while( !IR_Out ); // 等待9ms低电平过去
- // 程序进行到这里,表明经过9ms低电平
- Delay_ms(2); // 延时2.305ms
- DelayUs(300);
- // IR_Out 为低表明是连发码,不予理睬,跳出
-
- if( !IR_Out )
- { // P0_0=0;
- EA=1;
- return;
- }
- // 程序进行到这里,表明是引导码,等待4.5ms高电平的过去
- while( IR_Out );
- // 开始接收四组数据
- for(i=0; i<4; i++)
- { // P0_0=1;
- for(j=0; j<8; j++)
- {
- while( !IR_Out ); // 等待低电平过去
- IR_code[ i] >>= 1; // 把上次的数据位右移一位
- DelayUs(800); //延时0.793ms
- // 若为数据"1",则延时后IR_Out为高电平
- if( IR_Out )
- {
- IR_code[ i] |= 0x80; // 所有数据位1放最高位
- while( IR_Out ); // 等待高电平过去
- }
- }
- }
- //IR_code[0]低8位用户码,IR_code[1]高8位用户码,IR_code[2]为数据码,IR_code[3]为数据反码----dat为二进制
- if (IR_code[2]!=~IR_code[3]) //数据码校验
- {
- EA=1;
- return;
- }
- for(i=0;i<4;i++) //通过串口将代码发出
- {
- SBUF=IR_code[i];
- while(!TI); //等待一个字节发送完毕
- TI=0;
- }
- zd=1;
- EA=1; // 开中断
- return;
-
- }
- }
-
-
- void UART1_Rpt(void) interrupt UART1_VECTOR
- {
- if(SCON & 0x01) //判断接收中断标志位
- {
- /* guc_Uartbuf_a[guc_Uartcnt++] = SBUF;//转存8位串口接收数据
- if(guc_Uartcnt >= 5)
- {
- SCON &=~ 0x10; //失能UART1接收
- guc_Uartflag = 1;
- } */
- SCON &=~ 0x01; //清除接收中断标志位
- }
- }
- /**
- * ************************************************************************************
- * 微电脑数控型收音机i2c工程
- *
- * ************************************************************************************
- * @Examle Version V0.0.0.1
- * @Demo Version V0.0.0.1
- * @Date 2019.07.22
- * ************************************************************************************
- * ************************************************************************************
- **/
- //radio.h
- #ifndef _radio_h
- #define _radio_h
- void RDA5807_write_reg(void);
- void RDA5807_read_reg(unsigned char *reg_buf) ;
- void RDA5807_power(void) ;
- void RDA5807_FM_seek(void);
- void show_frequency(void);
- void show_volume(void);
- void RDA_set(unsigned int p);
- void setup(unsigned char u);
- void setvol(uchar temp);
- void show_vol(void);
- void RDA5807_write_reg_byte(unsigned char add,unsigned char temp,unsigned char temp1);
- #endif
- /**
- * ************************************************************************************
- * 微电脑数控型收音机i2c工程
- *
- * ************************************************************************************
- * @Examle Version V0.0.0.1
- * @Demo Version V0.0.0.1
- * @Date 2019.07.22
- * ************************************************************************************
- * ************************************************************************************
- **/
- //radio.c
- #include "HC89S003F4.h"
- #include "iic.h"
- #include "delay.h"
- #include "radio.h"
- extern uchar data Display_FM[8];
- extern void DigDisplay();
- #define RDA_R00 0X00;
- #define RDA_R02 0X02;
- #define RDA_R03 0X03;
- #define RDA_R04 0X04;
- #define RDA_R05 0X05;
- #define RDA_READ 0X23;
- #define RDA_WRITE 0X22;
- //初始化寄存器
- unsigned char RDA_reg_data[8] =
- {
- 0x00,0x00, // 02H
- 0x00,0x00, // 03H
- 0x00,0x00, // 04H
- 0x00,0x00, // 05H
- };
- //收音模块单字节写入操作
- void RDA5807_write_reg_byte(unsigned char add,unsigned char temp,unsigned char temp1){
- IIC_Start();
- IIC_Send_Byte(0x22);
- IIC_Send_Byte(add);
- IIC_Send_Byte(temp);
- IIC_Send_Byte(temp1);
- IIC_Stop();
- }
- //连续写寄存器子函数
- void RDA5807_write_reg(void)
- {
- uchar i;
- IIC_Start(); //收音模块写入操作
- IIC_Send_Byte(0x20);
- for(i=0; i<8; i++)
- {
- IIC_Send_Byte(RDA_reg_data[i]);
- }
- IIC_Stop();
- }
- void RDA5807_read_reg(uchar *reg_buf) //连续读寄存器子函数
- {
- IIC_Start();
- IIC_Send_Byte(0x21); //寄存器连续读操作
- reg_buf[0] = IIC_Read_Byte(1);
- reg_buf[1] = IIC_Read_Byte(1);
- reg_buf[2] = IIC_Read_Byte(1);
- reg_buf[3] = IIC_Read_Byte(0);
- IIC_Stop();
- }
- void RDA5807_power(void) //模块上电初始化子函数
- {
- Delay_ms(700);
- RDA_reg_data[0] = 0x00; //发送软件复位指令
- RDA_reg_data[1] = 0x02;
- RDA5807_write_reg();
- Delay_ms(50);
- RDA_reg_data[0] = 0x00; //发送软件复位指令
- RDA_reg_data[1] = 0x01;
- RDA5807_write_reg();
- Delay_ms(700);
- RDA_reg_data[0] = 0xc0; //收音模块默认参数
- RDA_reg_data[1] = 0x01;
- RDA_reg_data[4] = 0x00; //收音模块默认参数
- RDA_reg_data[5] = 0x00;
- RDA_reg_data[6] = 0x85; //收音模块默认参数 强度
- RDA_reg_data[7] = 0x88;
- RDA_reg_data[3] |= 0x10; //调谐启用
- RDA5807_write_reg();
-
- Delay_ms(40);
- }
- //设置指定频率
- void RDA_set(uint p){
- uint temp;
- temp=(uint)(p-870);
- temp&=0x03ff;
- temp=temp<<6;
- temp|=1<<4;
- RDA_reg_data[2]=temp>>8;
- RDA_reg_data[3]=temp;
- RDA5807_write_reg();
- Delay_ms(10);
- }
-
- void RDA5807_FM_seek(void) //功能描述:收音模块自动寻台模式
- {
- uint temp;
- uchar reg_data[4] = {0x00, 0x00, 0x00, 0x00};
- RDA_reg_data[3] &= ~(1 << 4); //调谐禁用 内部自动寻台使
- RDA_reg_data[0] |= (1 << 0); //SEEK位置 1
- RDA5807_write_reg();
- while(0 == (reg_data[0] & 0x40)) //等待 STC 标志置位
- {
- Delay_ms(30);
- RDA5807_read_reg(reg_data); //读取内部状态
- }
- temp = reg_data[0] & 0x03; //获取当前工作频点
- temp = reg_data[1] | (temp << 8);
- temp = temp << 6;
- RDA_reg_data[2] = (temp >> 8) & 0xff; //保存当前工作频点
- RDA_reg_data[3] = (temp & 0xff);
-
- }
-
- void show_frequency(void) //频率显示函数
- {
- unsigned char i;
- unsigned int temp;
-
- temp = (RDA_reg_data[2]*256)+(RDA_reg_data[3]&0xc0); //计算
- temp = temp>>6;
- temp = (unsigned int)(temp+870);
-
- for(i=0; i<4; i++){
- Display_FM[i] = 0x00; //清显存单元
- }
- Display_FM[0] = (temp)/1000 ; //数据转换
- Display_FM[1] = (temp%1000)/100;
- Display_FM[2] = (temp%100)/10;
- Display_FM[3] = (temp%10);
-
- }
- void show_vol(void) //vol显示函数
- {
- unsigned char i;
- unsigned int temp;
-
- temp = (RDA_reg_data[7]& 0x0f); //计算
-
- for(i=0; i<4; i++){
- Display_FM[i] = 0x00; //清显存单元
- }
- Display_FM[0] = 10 ; //数据转换
- Display_FM[1] = 0;
- Display_FM[2] = (temp%100)/10;
- Display_FM[3] = (temp%10);
-
- }
- //设定频率上下步进100khz
- void setup(uchar u)
- {
- unsigned int temp;
- temp = (RDA_reg_data[2]*256)+(RDA_reg_data[3]&0xc0); //计算
- temp = temp>>6;
- if(u==1){
- temp=temp+1;
- if(temp>0xd2)
- temp=0;
- }else if(u==0){
- if(temp==0){
- temp=0xd2;
- }else{
- temp=temp-1;
- }
- }
- temp&=0x03ff;
-
-
- temp=temp<<6;
-
- temp|=1<<4;
- RDA_reg_data[2]=temp>>8;
- RDA_reg_data[3]=temp;
- RDA5807_write_reg();
- Delay_ms(10);
- }
- //设定音量上下16级
- void setvol(uchar u){
- if(u==1){
- if((RDA_reg_data[7] & 0x0f) < 0x0f)
- {
- RDA_reg_data[3] |= 0x10; //调谐启用
- RDA_reg_data[7]++; //音量递增
- RDA5807_write_reg_byte(0X05,RDA_reg_data[6],RDA_reg_data[7]);
- }
- }else if(u==0){
- if((RDA_reg_data[7] & 0x0f) > 0x00)
- {
- RDA_reg_data[3] |= 0x10; //调谐启用
- RDA_reg_data[7]--; //音量递增
- RDA5807_write_reg_byte(0X05,RDA_reg_data[6],RDA_reg_data[7]);
- }
- }
- }
- /**
- * ************************************************************************************
- * 微电脑数控型收音机i2c工程
- *
- * ************************************************************************************
- * @Examle Version V0.0.0.1
- * @Demo Version V0.0.0.1
- * @Date 2019.07.22
- * ************************************************************************************
- *
- * ************************************************************************************
- **/
- //IIC.h
- #ifndef __IIC_H__
- #define __IIC_H__
- #include "HC89S003F4.h"
- #include "intrins.h"
- #define IIC_SDA P0_0 //模拟IIC数据线
- #define IIC_SCL P1_1 //模拟IIC时钟线
- #define IIC_WR 0 // 写控制bit
- #define IIC_RD 1 // 读控制bit
-
- #define IIC_SDA_L P0_0=0 //SDA拉低
- #define IIC_SDA_H P0_0=1 //SDA拉高 CH1
- #define IIC_SCL_L P1_1=0 //SCL拉低 CH2
- #define IIC_SCL_H P1_1=1 //SCL拉高
- #define IIC_SDA_IN() {P0M0 = P0M0&0xf0|0x04;} //设置SDA SMT输入
- #define IIC_SDA_OUT() {P0M0 = P0M0&0xf0|0x08;} //设置SDA 推挽输出
- #define IIC_SCL_OUT() {P1M0 = P1M0&0x0f|0x80;} //设置SCL 推挽输出
-
- void IIC_GPIO_Init(void); //IIC GPIO初始化
- void IIC_Start(); //启动I2C总线
- void IIC_Stop(); //停止I2C总线
- void Delay_IIC();//IIC延时
- unsigned char IIC_Send_Byte(unsigned char txd); //IIC发送一个字节
- unsigned char IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
- unsigned char IIC_Wait_Ack(void); //IIC等待ACK信号
- void IIC_Ack(void); //IIC发送ACK信号
- void IIC_NAck(void); //IIC不发送ACK信号
- #endif/* __IIC_H__ */
- /**
- * ************************************************************************************
- * 微电脑数控型收音机i2c工程
- *
- * ************************************************************************************
- * @Examle Version V0.0.0.1
- * @Demo Version V0.0.0.1
- * @Date 2019.07.22
- * ************************************************************************************
- *
- * 若发现错误或对函数的使用存在疑问。请添加:51单片机电子交流群
- * ****************************
- 技术交流群:879778027
- ***********************************
- * ************************************************************************************
- **/
- //IIC.c
- #include "IIC.h"
- void Delay_IIC()//IIC延时
- {
- _nop_();_nop_();_nop_();_nop_();
- }
- void IIC_GPIO_Init() //IIC初始化子程序
- {
- IIC_SCL_OUT();
- IIC_SDA_OUT();
- IIC_Stop();
- }
- void IIC_Start() //启动I2C总线
- {
- IIC_SDA_OUT();
- IIC_SDA_H; //拉高SDA
- Delay_IIC(); //延时
- IIC_SCL_H; //拉高SCL
- Delay_IIC(); //延时
- IIC_SDA_L; //拉低SDA
- Delay_IIC(); //延时
- IIC_SCL_L; //拉低SCL
- Delay_IIC(); //延时
- }
- void IIC_Stop() //停止I2C总线
- {
- IIC_SDA_OUT();
- IIC_SDA_L; //拉低SDA
- IIC_SCL_H; //拉高SCL
- Delay_IIC(); //延时
- IIC_SDA_H; //拉高SDA
- Delay_IIC(); //延时
- }
- //等待应答信号到来
- //返回值:1,接收应答失败
- // 0,接收应答成功
- unsigned char IIC_Wait_Ack(void)
- {
- unsigned char ucErrTime=0;
- IIC_SDA_IN(); //SDA设置为输入
- IIC_SDA_H; Delay_IIC(); //延时
- IIC_SCL_H; Delay_IIC(); //延时;
- while(IIC_SDA!=0)
- {
- ucErrTime++;
- if(ucErrTime>250)
- {
- IIC_Stop();
- return 1;
- }
- }
- IIC_SCL_L;//时钟输出0
- return 0;
- }
- //产生ACK应答
- void IIC_Ack(void)
- {
- IIC_SCL_L;
- IIC_SDA_OUT();
- IIC_SDA_L;
- Delay_IIC(); //延时
- IIC_SCL_H;
- Delay_IIC(); //延时
- IIC_SCL_L;
- }
- //不产生ACK应答
- void IIC_NAck(void)
- {
- IIC_SCL_L;
- IIC_SDA_OUT();
- IIC_SDA_H;
- Delay_IIC(); //延时
- IIC_SCL_H;
- Delay_IIC(); //延时
- IIC_SCL_L;
- }
- //IIC发送一个字节
- //返回从机有无应答
- //1,有应答
- //0,无应答
- unsigned char IIC_Send_Byte(unsigned char txd)
- {
- unsigned char t;
- IIC_SDA_OUT();
- IIC_SCL_L;;//拉低时钟开始数据传输
- for(t=0;t<8;t++)
- {
- if((txd&0x80)>>7)
- IIC_SDA_H;
- else
- IIC_SDA_L;
- txd<<=1;
- Delay_IIC(); //延时
- IIC_SCL=1;
- Delay_IIC(); //延时
- IIC_SCL=0;
- Delay_IIC(); //延时
- }
- IIC_Wait_Ack();
- }
- //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
- unsigned char IIC_Read_Byte(unsigned char ack)
- {
- unsigned char i,receive=0;
- IIC_SDA_IN();//SDA设置为输入
- IIC_SCL_L;//拉低时钟开始数据传输
- IIC_SDA=1;
- for(i=0;i<8;i++ )
- {
- receive<<=1;
- IIC_SCL_H;
- Delay_IIC(); //延时
- if(IIC_SDA!=0)
- receive++;
- IIC_SCL_L;
- Delay_IIC(); //延时
- }
- if (!ack)
- IIC_NAck();//发送nACK
- else
- IIC_Ack(); //发送ACK
- return receive;
- }
复制代码 |