<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> MCU設計實例 >> 瀏覽文章

        完整的FM收音機模塊驅動程序(包含M62429電子調音程序)

        作者:西西   來源:本站原創   點擊數:  更新時間:2014年04月05日   【字體:

        /****************wang1jin設計的FM發射板程序************************
        電路結構:STC12C2052+M62429+BH1415+9018+3355+2053
        LCD1602顯示,電子音量

        完成時間:2007年11月初

        程序編寫:sunhm
        ***************************************************************/

        #include "STC89C51RC_RD_PLUS.H"
        #include "intrins.h"
        #define uchar unsigned char
        #define uint unsigned int
        #define nop _nop_();_nop_();_nop_();

        uchar code C51BOX2[3] _at_ 0x43;   //仿真器用三字節空間

        sbit CE_1415= P1^4;   //;1415的使能端
        sbit CK_1415= P1^5;   //;1415的時鐘
        sbit DT_1415= P1^6;   //;1415數據口
        sbit RS_1602=P3^3;    //各控制腳
        sbit RW_1602=P3^4;
        sbit EN_1602=P3^5;
        sfr  DataPort_1602=0x90;//P1數據口
        sbit CK_M62429=P3^1;
        sbit DATA_M62429=P3^0;

        sbit KeyPow  =P1^0;  //按鍵
        sbit KeyMenu  =P1^1;
        sbit KeyUp   =P1^2;
        sbit KeyDown =P1^3;
        sbit KeyGnd  =P3^7;

        sbit FmPow=P1^7;

        uchar code Megs0[]={"Sunhm  QQ8932867"};
        uchar code Megs1[]={"  FM Power Off  "};
        uchar code Megs2[]={" FM Transmitter "};
        uchar code Megs3[]={"    . MHz  -  dB"};

        uchar code CG[]={
                         0x02, 0x04, 0x19, 0x15, 0x15, 0x19, 0x04, 0x02, // 喇叭符號
             0x20, 0x1f, 0x11, 0x0a, 0x04, 0x04, 0x04, 0x04, // 天線符號
             };

        uchar Vol;   //存放音量值
        uint Freq;  //存放頻率值
        uchar KeyValue; //鍵值
        uchar MenuState;//菜單切換狀態變量
        uchar Account;uchar MenuDelayTime;
        bit FlashState; //閃動狀態變量

        /**************************延時變量*****************************/
        //#define Delay1 90   //STC12C2052+12M晶振使用
        //#define Delay2 380
        //#define Delay3 5
        //#define Delay4 100

        //#define Delay1 35   //STC12C2052+RC使用
        //#define Delay2 200
        //#define Delay3 2
        //#define Delay4 50

        #define Delay1 45    //AT89C2051+12M晶振使用
        #define Delay2 150
        #define Delay3 2
        #define Delay4 100


        /**********************延時子函數*******************************/
        void uDelay(uchar i)   //us延時子函數,入口參數每加1約加100us
        {
         for(;i>0;i--)
          {uchar j=Delay1;while(--j);}
        }

        void mDelay(uint Dat)  //ms延時子函數
        {
         uint j;  
         for (;Dat>0;Dat--)
          for (j=Delay2;j>0;j--);
        }


        /****************以下為EPPROM讀寫相關函數*******************************/
        /*以下為EPPROM保護,每次操作后更改指令值,使EPPROM免于被誤操作*/
        void EPPROM_Protect()
        {
          ISP_CONTR=0x00;   //更改指令值,防止出現誤操作
         ISP_CMD=0x00;
         ISP_TRIG=0x00;
         ISP_ADDRH=0x00;
         ISP_ADDRL=0x00;
        }

        /*以下為讀入指令,入口參數為要讀的地址(16位),返回內容(8位)*/
        uchar EEPROM_Read(uint Addr)
        {
         ISP_ADDRH=Addr/0x100;  //送地址
         ISP_ADDRL=Addr%0x100;
         ISP_CONTR=0x83;  //控制字節
         ISP_CMD=0x01;  //讀命令
         ISP_TRIG=0x46;  //觸發
         ISP_TRIG=0xB9;
         EPPROM_Protect(); //更改相關數值,防止誤操作
         return(ISP_DATA);  //返回讀出的值
        }
         
        /*以下為扇區擦除指令,入口參數為扇區首地址 */
        void EEPROM_Erase(uint Addr)
        {
         ISP_ADDRH=Addr/0x100;  //待寫入扇區首地址
         ISP_ADDRL=0x00;
         ISP_CONTR=0x83;
         ISP_CMD=0x03;  //扇區擦除指令
         ISP_TRIG=0x46;  //觸發,將擦除整個扇區
         ISP_TRIG=0xB9;
         EPPROM_Protect(); //更改相關數值,防止誤操作
        }

        /*以下為寫入指令,入口參數為寫入的地址(16位)和內容(8位),每次要寫入的位置*/
        void EEPROM_Write(uint Addr,uchar Data)
        {
         ISP_DATA=Data; //待寫入值
         ISP_ADDRH=Addr/0x100;  //待寫入扇區首地址
         ISP_ADDRL=Addr%0x100;
         ISP_CONTR=0x83;
         ISP_CMD=0x02;  //寫入指令
         ISP_TRIG=0x46;  //觸發,數據寫入
         ISP_TRIG=0xB9;
         EPPROM_Protect(); //更改相關數值,防止誤操作
        }

        /**********************數據存儲與讀取******************************/
        void DatSave()
        {
         EEPROM_Erase(0x1000);
         EEPROM_Write(0x1000,Vol);
         EEPROM_Write(0x1001,Freq/0x100);
         EEPROM_Write(0x1002,Freq%0x100);
        }
        void DatLoad()
        {
         Vol=EEPROM_Read(0x1000);
         Freq=EEPROM_Read(0x1001)*0x100+EEPROM_Read(0x1002);
         if(Vol>83){Vol=10;DatSave();}
         if ((Freq>1080)||(Freq<870))  //判斷頻率值是否有錯
          {
          Freq=908;   //如果錯誤,設置為默認90.8M
          DatSave();
          }
        }

        /**************************M62429 發送用子函數**********************/
        void VolSet(uchar Volume)
        {
         uint Dat;uchar i;
         Volume=87-Volume;  //得到要送到芯片的實際數
         Dat=0x600|(Volume&0xfc)|((Volume&0x03)<<7);  //音量合并成控制數據,詳看DATASHEET
         
         for (i=0;i<10;i++)        //發送10位數據,共11位,最后1位另外發
          {
           DATA_M62429=Dat&0x01;
           CK_M62429=1;   
           nop;
           DATA_M62429=0;  
           CK_M62429=0;    
           Dat>>=1;      
          }
         DATA_M62429=1; 
         CK_M62429=1;nop;CK_M62429=0;

        }
        /*************************1415 發送子函數*********************/

        void PLLSend(uint Dat)    //數據發送到BH1415
        {
         uchar i;
         Dat+=0x4800;
         CE_1415=1;    //打開片選準備發送
         for(i=16;i>0;i--)
         {
          DT_1415=Dat&1;
          CK_1415=1; 
          Dat>>=1;   
          CK_1415=0;   
         }
         CE_1415=0;DT_1415=0;CK_1415=0;
        }

        /**********************1602 4線使用程序***********************/
        void En1602(uchar Dat)   //使能子函數
        {
          KeyGnd=1;    //釋放鍵盤線
         uDelay(15);
         DataPort_1602&=0xf0; //數據送出,ASCII碼
         DataPort_1602|=Dat>>4;
         RS_1602=0;    //控制發出
         RW_1602=0;
         EN_1602=1;EN_1602=0;

          DataPort_1602&=0xf0;
         DataPort_1602|=Dat&0x0f;
         RS_1602=0;  
         RW_1602=0;
         EN_1602=1;EN_1602=0;
           KeyGnd=0;
        }
         
        void WrCharTo1602(uchar Dat) //寫字節子函數
        {
          KeyGnd=1;
         uDelay(15);
         DataPort_1602&=0xf0;  //數據送出,ASCII碼
         DataPort_1602|=Dat>>4;
         RS_1602=1;     //控制發出
         RW_1602=0;
         EN_1602=1;EN_1602=0;

          DataPort_1602&=0xf0;
         DataPort_1602|=Dat&0x0f;
         RS_1602=1;  
         RW_1602=0;
         EN_1602=1;EN_1602=0;
         KeyGnd=0;
        }

        void WrStringTo1602(uchar x,uchar *p)  //寫字符串子函數。入品:x行(0或1),數組
        {
         En1602(0x80+(x<<6)); 
         while(*p)
         {
          WrCharTo1602(*p);p++;
         }
        }

        void Init1602(void)   //初始化子函數
        {
          En1602(0x28);   //4位點陣方式
         mDelay(100);
         En1602(0x28); 
         mDelay(100);
         En1602(0x28); 
         mDelay(100);
         En1602(0x28); 
         mDelay(100);
         En1602(0x0c);   //開顯示
         mDelay(100);
         En1602(0x01);   //清屏
        }

        void WrCG1602(uchar *p)     //自定義字符子函數
        {     
         En1602(0x40); 
         while(*p)
         {WrCharTo1602(*p);p++;mDelay(1);}
        }

        /****************************顯示子函數*************************/
        void DispFreq(bit state) //頻率值拆分顯示。入口參數:1為有顯示,0為沒
        {
         uint Dat=Freq;
         if(state) //正常顯示
          {
          En1602(0xc5);
          WrCharTo1602(Dat%10+0x30);
          Dat/=10;
         
          En1602(0xc3);
          WrCharTo1602(Dat%10+0x30);
          Dat/=10;
         
          En1602(0xc2);
          WrCharTo1602(Dat%10+0x30);
         
          En1602(0xc1);
          if(Dat/10) WrCharTo1602(0x31);
          else WrCharTo1602(0x20);
          }
         else     //無顯示
          {
          En1602(0xc1);
          WrCharTo1602(0x20);WrCharTo1602(0x20);WrCharTo1602(0x20);
          En1602(0xc5);WrCharTo1602(0x20);
          }
        }

        void DispVol(bit State)    //聲音值拆分顯示。入口參數:1為有顯示,0為沒
        {
         if(State)
          {
          En1602(0xcc);
          if(Vol/10) WrCharTo1602(Vol/10+0x30);
          else WrCharTo1602(0x20);
          WrCharTo1602(Vol%10+0x30);
          }
         else
          {
          En1602(0xcc);WrCharTo1602(0x20);WrCharTo1602(0x20);
          }
        }
         
        void FmOn()    //發射部分工作屏幕顯示內容初始化
        {
         FmPow=0;
         WrStringTo1602(0,Megs2);
         WrStringTo1602(1,Megs3);
         En1602(0xc0);WrCharTo1602(1);
         En1602(0xca);WrCharTo1602(0);
         VolSet(Vol);
         mDelay(50);
         DispFreq(1);
         DispVol(1);
         PLLSend(Freq);
        }

        void FmOff() //發射部分不工作屏幕顯示內容初始化
        {
         FmPow=1;
         WrStringTo1602(0,Megs1);
         WrStringTo1602(1,Megs0);
        }

        void DispFlash()      //閃動顯示處理
        {
         if(!MenuState)return;  
         if(MenuState==1) DispFreq(FlashState);
         if(MenuState==2) DispVol(FlashState);
         if(MenuDelayTime>Delay4)
          {MenuState=0;DispFreq(1);DispVol(1);}
        }

        /************************按鍵讀取及處理子函數**************************/
        void KeyRead()   //讀鍵值子函數。返回值:1、2、3、31、4、41。(31、41為長按)
        {
         uchar i=250;
         KeyGnd=0;
         KeyPow=1;KeyMenu=1;KeyUp=1;KeyDown=1;
         if(KeyPow&KeyMenu&KeyUp&KeyDown) {KeyValue=0;return;}
         MenuDelayTime=0;  //清延時計數器
         mDelay(10); 
           if(!KeyPow)
            {
            while(!KeyPow); //等待鍵釋放
            KeyValue=1;
            return;
            }
           if(!KeyMenu)
            {
            while(!KeyMenu);//等待鍵釋放
            KeyValue=2;
            return;
            }
           if(!KeyUp)
            {
            if(KeyValue) return; //短按
            while(i)
             {
             if(KeyUp)
              {KeyValue=3;return;}
             mDelay(3);i--;
             }     //短按
            KeyValue=31;  //長按
            return;
            }
           if(!KeyDown)
            {
            if(KeyValue) return;//短按
            while(i)
             {
             if(KeyDown)
              {KeyValue=4;return;}
             mDelay(3);i--;
             }     //短按
            KeyValue=41;     //長按
            return;
            }

        }

        void KeyProc()    //鍵值處理子函數
        {
         switch(KeyValue)
         {
         case 1:  //KeyPow處理
          if(FmPow)  //根據當前電源狀態切換至另一狀態
           {FmOn();}
          else
           {MenuState=0;FmOff();}
          KeyValue=0;
          break;
         case 2:  //KeyMenu處理
          if(FmPow)break; //關機狀態下不處理這個按鍵
          MenuState++;
          DispFreq(1);DispVol(1);
          if(MenuState==3)MenuState=0;
          KeyValue=0;
          break;
         case 3:  //KeyUp處理
          if(FmPow)break; //關機狀態下不處理這個按鍵
          if(MenuState==1)
           {
           Freq++;
           if(Freq>1080)Freq=875;  //頻率加1
           DispFreq(1);PLLSend(Freq);
           }
          if(MenuState==2)
           {
           if(Vol)Vol--;
           DispVol(1);VolSet(Vol);
           }
          KeyValue=0;DatSave();
          break;
         case 4:  //KeyDown處理
          if(FmPow)break; //關機狀態下不處理這個按鍵
          if(MenuState==1)
           {
           Freq--;
           if(Freq<875)Freq=1080;
           DispFreq(1);PLLSend(Freq);
           }
          if(MenuState==2)
           {
           if(Vol<83)Vol++;    //音量減
           DispVol(1); VolSet(Vol);
           }
          KeyValue=0;DatSave();
          break;
         case 31: //KeyUp長按處理
          if(FmPow)break;
          if(MenuState==1)
           {
           Freq+=10;
           if(Freq>1080)Freq=875;
           DispFreq(1);PLLSend(Freq);
           }
          if(MenuState==2)
           {
           if(Vol>4)Vol-=5;
           else Vol=0;
           DispVol(1);VolSet(Vol);
           }
          mDelay(600);
          DatSave();
          break;
         case 41: //KeyDown長按處理
          if(FmPow)break;
          if(MenuState==1)
           {
           Freq-=10;
           if(Freq<875)Freq=1080;
           DispFreq(1);PLLSend(Freq);
           }
          if(MenuState==2)
           {
           Vol+=5;
           if(Vol>83)Vol=83;
           DispVol(1);VolSet(Vol);
           }
          mDelay(600);DatSave();
          break;
         }
        }  

        /*******************計數器中斷處理子函數*************************/
        void Timer0() interrupt 1   //計時中斷子函數,50ms中斷一次
        {

         Account++;       //中斷一次加1
         MenuDelayTime++;
         if(Account>Delay3) 
          {
          Account=0;
          FlashState=~FlashState;
          }
        }

        /****************************主函數*******************************/
        void main()
        {
         mDelay(1000);       //開機延時,等待設備穩定
         Init1602();
         mDelay(10);
         WrCG1602(CG);
         CE_1415=0;CK_1415=0,DT_1415=0;
         CK_M62429=0;DATA_M62429=0;
         DatLoad();

         TH0=0x3c;         //設定中斷初始值
         TL0=0xb0;
         TMOD=0x01;
         EA=1;
         TR0=1;
         ET0=1;
         
         FmOff();      //顯示關閉畫面

         while(1)  {KeyRead();DispFlash();KeyProc();};
            
        }

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮