📄 fm_mcu51.c
字号:
/*********************************************************************************Description:the code is for the FM module of TEA5767 and the controler is AT89LV52Language: C51Tools:uVision3 3.23Author:ENWAVersion: V1.0Date: 09/30/2008ALL RIGHT RESERVED ,ONLY FOR COMMUNICATE ,DON'T USE IN COMMERCE .***********************************************************************************/#include <AT89X52.h> ` #include <intrins.h>#define uchar unsigned char#define uint unsigned int#define DELAY5US _nop_();_nop_();_nop_();_nop_();_nop_();uchar idata adress_write; // 写TEA5767地址uchar idata adress_read; //读TEA5767址uchar idata sbuf[5]; // 数据发送缓冲区uchar idata rbuf[5]; // 数据接收缓冲区uchar idata ampint[5];uchar bdata I2C_byte1; //发送的五字节TEA5767可位寻址的设置值uchar bdata I2C_byte2;uchar bdata I2C_byte3;uchar bdata I2C_byte4;uchar bdata I2C_byte5;uchar byte1; uchar byte2;uchar byte3;uchar byte4;uchar byte5;uchar bdata rec_byte1; //接收的五字节TEA5767可位寻址的状态数据uchar bdata rec_byte2;uchar bdata rec_byte3;uchar bdata rec_byte4;uchar bdata rec_byte5;uchar idata ADDRESS_SEND; //TEA5767发送地址uchar idata ADDRESS_RECEIVE; //TEA5767接收地址uchar idata ADDRESS_AMP;uchar idata numbyte;uchar idata numbyte_AMP;unsigned long int FM_FREQ;unsigned short int FM_PLL;/*发送到TEA5767的5个字节设置数据中位的定义*/sbit MUTE =I2C_byte1^7; sbit SM = I2C_byte1^6;uchar bdata PLL_HIGH;uchar bdata PLL_LOW;sbit SUD=I2C_byte3^7;sbit SSL1=I2C_byte3^6;sbit SSL0=I2C_byte3^5;sbit HLSI=I2C_byte3^4;sbit MS=I2C_byte3^3;sbit MR=I2C_byte3^2;sbit ML=I2C_byte3^1;sbit SWP1=I2C_byte3^0;sbit SWP2=I2C_byte4^7;sbit STBY=I2C_byte4^6;sbit BL=I2C_byte4^5;sbit XTAL=I2C_byte4^4;sbit SMUTE=I2C_byte4^3;sbit HCC=I2C_byte4^2;sbit SNC=I2C_byte4^1;sbit SI=I2C_byte4^0;sbit PLLREF=I2C_byte5^7;sbit DTC=I2C_byte5^6;sbit SDA=P1^0;sbit SCL=P1^1;bit bdata NACK; // 错误标志位bit bdata nackFlag; // 非应答标志位/*接收I2C5个字节设置数据中位的定义*/sbit RF=rec_byte1^7;sbit BLF=rec_byte1^6;sbit STEREO=rec_byte3^7;uchar idata IF;uchar idata LEVEL;uchar idata CI;uchar temp1;uchar temp2;/* 函数预定义 */void sendnbyte(uchar idata *sla, uchar n);//与sendbyte函数构成I2C 数据发送函数void sendbyte(uchar idata *ch); void I2C_start(void); //I2C 传输开始void stop(void); //I2C传输结束void delay1ms(void); //延迟1msvoid delay100ms(void); //延迟100msvoid delay600ms(void); //延迟600msvoid search_up(void); //接收频率向上加void search_down(void); //接收频率向下减void autosearch(void); //自动频率搜索void init(void); //TEA5767初始化void key_scan(void); //键扫描void ask(void); //问答讯号void n_ask(void); //非应答讯号void checkack(void); //检查应答讯号void recnbyte(uchar idata *sla, uchar n); //与recbyte一起构成接收I2C数据函数void recbyte(uchar idata *ch);void setByte1Byte2(void); //设置第一第二字节频率void AUTO_search_up(void); //自动频率搜索void volume_up(void);void volume_down(void);void AMP_sendnbyte(uchar idata *sla,uchar numbyte_AMP);void main(void){ numbyte = 5; numbyte_AMP=5; ADDRESS_SEND = 0xC0; // TEA5767写地址 ADDRESS_RECEIVE=0XC1; //TEA5767读地址 ADDRESS_AMP=0X8E; init(); // 初始化TEA5767 while(1){ key_scan(); //键扫描 }}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=100800000; //开机预设频率 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; I2C_byte5=0X40; byte1=0X27; byte2=0X40; byte3=0X42; byte4=0X46; byte5=0XC3; sendnbyte(&ADDRESS_SEND,numbyte); delay100ms(); AMP_sendnbyte(&ADDRESS_AMP,numbyte_AMP);}void I2C_start(void) //在SCL为高时,SDA由高变低即为I2C传输开始{ SDA=1; SCL=1; DELAY5US; SDA=0; DELAY5US; SCL=0;}void stop(void) //在SCL为高时,SDA由低变高即为I2C传输结束{ SDA=0; SCL=1; DELAY5US; SDA=1; DELAY5US; SCL=0;}void ack(void){ SDA=0; SCL=1; DELAY5US; SDA=1; SCL=0;}void n_ack(void){ SDA=1; SCL=1; DELAY5US; SDA=0; SCL=0;}/* 应答位检查子函数 */void checkack(void){ SDA = 1; // 应答位检查(将p1.0设置成输入,必须先向端口写1) SCL = 1; F0 = 0; DELAY5US;// SDA=0; if(SDA == 1) // 若SDA=1表明非应答,置位非应答标志F0 F0 = 1; SCL = 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; SCL = 0; SDA = 0; } else { SDA = 0; // 否则传送位0 SCL = 1; DELAY5US; SCL = 0; } temp = temp<<1; // 数据左移一位 }}/* 发送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(); // 全部发完则停止}/* 接收5字节数据子程序 */void recnbyte(uchar idata *sla, uchar n){ uchar idata *p; I2C_start(); // 发送启动信号 sendbyte(sla); // 发送TEA5767地址字节 checkack(); // 检查应答位 if(F0 == 1) { NACK = 1; return; } p = rbuf; // 接收字节存放在rbuf中 while(n--) { recbyte (p); ack(); // 收到一个字节后发送一个应答位 p++; } n_ack(); // 收到最后一个字节后发送一个非应答位 rec_byte1=rbuf[0]; rec_byte2=rbuf[1]; rec_byte3=rbuf[2]; rec_byte4=rbuf[3]; rec_byte5=rbuf[4]; stop();} /* 接收字节处理子程序 */void recbyte(uchar idata *ch){ uchar idata n=8; // 从SDA线上读取一位数据字节,共8位 uchar idata temp = 0; while(n--) { SDA = 1; SCL = 1; temp = temp<<1; // 左移一位 if(SDA == 1) temp = temp|0x01; // 若接收到的位为1,则数据的最后一位置1 else temp = temp&0xfe; // 否则数据的最后一位置0 SCL=0; } *ch = temp;}void delay1ms(void) //延迟1ms{ uchar i; for(i=1000;i>0;i--){}}void delay100ms() //延迟100ms{ uchar i; for(i=100;i>0;i--){delay1ms();}}void delay600ms(){ uchar i; for(i=600;i>0;i--){delay1ms();}}void delay10ms() //延迟10ms{ uchar i,j; for(i=1000;i>0;i--) {for(j=100;j>0;j--){}}}void key_scan(void){ uchar idata i; //P2=0X17; if((P2&0X1F)!=0X1F) { delay10ms();// P2=0X17; if((P2&0X1F)!=0X1F) { i=P2; switch(i&0X1F) { case 0X1E: { search_up(); //频率向上 delay600ms(); } break; case 0X1D: { search_down(); //频率向下 delay600ms(); }break; case 0X1B: { autosearch(); //自动搜索 delay600ms(); }break; case 0X17: { volume_up(); //音量加 delay600ms(); }break; case 0X0F: { volume_down(); //音量减 delay600ms(); }break; default: break; } } }}/*向上搜索*/ void search_up(void){ MUTE=1; //静音 SUD=1; //搜索标志位设为向上 if(FM_FREQ>108000000){FM_FREQ=87500000;} // 判断频率是否到顶 FM_FREQ=FM_FREQ+100000; //频率加100K FM_PLL=(unsigned short)((4000*(FM_FREQ/1000+100+225))/32768); //计算PLL值 setByte1Byte2(); //设置I2C第一第二字节PLL 值}/*向下搜索*/void search_down(void){ MUTE=1; //静音 SUD=0;//搜索标志位设为向下 if(FM_FREQ<87500000){FM_FREQ=108000000;} // 判断频率是否到底 FM_FREQ=FM_FREQ-100000; //频率减100K FM_PLL=(unsigned short)((4000*(FM_FREQ/1000-100+225))/32768); //计算PLL值 setByte1Byte2(); //设置I2C第一第二字节PLL 值}/*第一第二字节PLL值设定*/void setByte1Byte2(void){ PLL_HIGH=(uchar)((FM_PLL >> 8)&0X3f); //PLL高字节值 I2C_byte1=(I2C_byte1&0XC0)|PLL_HIGH; //I2C第一字节值 PLL_LOW=(uchar)FM_PLL; //PLL低字节值 I2C_byte2= PLL_LOW; //I2C第二字节值 sendnbyte(&ADDRESS_SEND,numbyte); //I2C数据发送 MUTE=0; delay100ms(); //延时100ms sendnbyte(&ADDRESS_SEND,numbyte); //I2C 数据发送 DELAY5US;}/*自动搜索*/void AUTO_search_up(void){ MUTE=1; //静音 SUD=1; //搜索标志位设为向上 if(FM_FREQ>108000000){FM_FREQ=87500000;} //如果频率到顶则返回到87.5M开始 FM_FREQ=FM_FREQ+100000; //频率加100K FM_PLL=(unsigned short)((4000*(FM_FREQ/1000+100+225))/32768); //计算PLL值 setByte1Byte2(); //设置第一第二字节I2C数据}void autosearch(void){ FM_PLL=(unsigned short)((4000*(FM_FREQ/1000+100+225))/32768); //计算PLL值 PLL_HIGH=(uchar)((FM_PLL >> 8)&0X3f); //PLL高字节值 PLL_LOW=(uchar)FM_PLL; //PLL低字节值 temp1=PLL_HIGH; //temp 用于判断是否搜索了一圈 temp2=PLL_LOW; AUTO_search_up(); //向上搜索 delay10ms(); recnbyte(&ADDRESS_RECEIVE,numbyte); //接收TEA5767的状态数据 while (!(RF)) //当无电台搜到时进入继续搜索 { AUTO_search_up(); //向上搜索 delay10ms(); recnbyte(&ADDRESS_RECEIVE,numbyte); //接收TEA5767的状态数据 if((RF)==1) { LEVEL = I2C_byte4&F0; //当接收到电台信号时获取电台电平 if ((LEVEL>=7)&(IF>35)&(IF<39)) //当电台电平大于7并且中频计数器数值在35 到39间时退出自动搜索 { return; } else if((PLL_HIGH==temp1)&(PLL_LOW==temp2)==1){break;} //// } } } /* 发送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(); // 全部发完则停止}/*音量增加*/ void volume_down() { if(byte1==0X30) //判断是否是最小音量 {return;} //已是最小音量则返回 byte1=byte1+1; //音量小1级 AMP_sendnbyte(&ADDRESS_AMP,numbyte_AMP); //通过I2C传送音量值}/*音量减小*/void volume_up() { if(byte1==0X00) //判断是否是最大音量 {return;} //已是最大音量则返回 byte1=byte1-1; //音量大1级 AMP_sendnbyte(&ADDRESS_AMP,numbyte_AMP); //通过I2C传送音量值}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -