找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

帖子
查看: 6814|回復(fù): 8
打印 上一主題 下一主題
收起左側(cè)

STM32與TEA5767收音機(jī)OLED顯示、自動(dòng)/手動(dòng)搜臺(tái),DS1302顯示時(shí)間 源程序

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
接上TEA5767模塊后可以接受FM電臺(tái)87500——108000KHZ, 音量調(diào)節(jié)只能靜音或者打開,因?yàn)槟K本身不具有調(diào)節(jié)選項(xiàng);可以手動(dòng)設(shè)置頻率(軟件步進(jìn)精度10KHZ,模塊的角度不清楚)也可以自動(dòng)搜臺(tái),但只能應(yīng)對(duì)強(qiáng)臺(tái)的搜索。OLED我用的是1.3寸的,0.96寸也是兼容的,但貌似1.3寸版本多了兩列像素,所以可能邊緣的顯示0.96會(huì)出點(diǎn)小問題。收音模塊我是用的帶功放的,但最好買單獨(dú)的模塊來做,因?yàn)檫@個(gè)音量不可用程序調(diào)節(jié)!
主要模塊和功能如下:
1、OLED屏:操作界面顯示(選中時(shí)反顯)
2、三個(gè)10K電阻下拉的按鍵:左邊功能選擇減,中間兼“確認(rèn)”和“減”功能,右邊“加”功能
3、DS1302:提供實(shí)時(shí)時(shí)鐘:可修改時(shí)間
4、TEA5767完整帶功放模塊:收音的核心,靜音音量示數(shù)為0其余都表示聲音“開”,配有音頻口用于接入天線(實(shí)測(cè)插一個(gè)耳機(jī)效果最好)
5、STM32F103C6T6單片機(jī):C8T6也可以用,完全兼容;不過程序也就18K左右用C8浪費(fèi)了,SRAM也完全夠了

模塊的接線為:1、OLED: SCL->PA5  SDA->PA7  3.3V電源
2、按鍵:10K電阻下拉,接PA2、3、4,分別對(duì)應(yīng)按鍵1,2,3
3、TEA5767模塊:SCL->PB7   SDA->PB5
4、DS1302模塊:  RST->PB10   DAT->PB1   CLK->PB0

制作出來的實(shí)物圖如下:

收音機(jī)整體模塊


菜單界面


手動(dòng)搜臺(tái),步進(jìn)或設(shè)置


收音機(jī)主界面


存臺(tái)取臺(tái)


三個(gè)按鍵進(jìn)行操作

實(shí)測(cè)多次代碼各項(xiàng)功能都沒有問題可以運(yùn)行,另外程序中有一些功能選項(xiàng)沒有寫實(shí)現(xiàn)代碼,例如“恢復(fù)設(shè)置”,它們不影響最終功能的實(shí)現(xiàn)可以自由寫入需要恢復(fù)的變量;還有鬧鐘功能,只需要按照其他界面的設(shè)計(jì)邏輯寫一些“if else”語句就可以實(shí)現(xiàn),由于沒有蜂鳴器就沒寫了。不過這些都不影響主要的功能的實(shí)現(xiàn),畢竟它只是一個(gè)收音機(jī)...

部分STM32單片機(jī)代碼如下:
#include "delay.h"
#include "sys.h"
#include "stdio.h"
#include "interrupt.h"
#include "stdlib.h"
#include "oled.h"
#include "tea5657.h"
#include "ds1302.h"

#define StartPosition  0x08005000 //存取臺(tái)在flash中的起始位置,程序大概有18KB,不能與程序沖突


u32 Frequence; //頻率全局變量,單位為10KHZ
u16 count=0,result,SystemTime,Channel[41]; //存取40個(gè)臺(tái),可更改
u8  KeyState[3],Menu1, Menu2, ItemSwitch,Menu2_1;
unsigned char countNumber = 0, SetNumber[5], Time[8], TimeBuff[8], Laud, ChannelSet=1,Signal, Brightness = 3; //初始亮度為3(1—5)
unsigned char radio_write_data[5]={0x29,0xc2,0x40,0x12,0x40};      
unsigned char radio_read_data[5];        //TEA5767讀出的狀態(tài)


void DrawFirst1(void); //分別為各個(gè)界面的驅(qū)動(dòng)函數(shù)
void DrawFirst2(void);
void DrawFirst3(void);
void DrawFirst4(void);
void DrawFirst5(void);
void DrawFirst6(void);
void DrawFirst7(void);
void SetPicture1_1(void);
void SetPicture2_1(void);
void SetPicture2_2(void);
void SetPicture2_5(void);        
void SetPicture2_3(void);
void SetPicture2_6(void);        
void ClockTime(void); //定時(shí)讀取DS1302
void InputA_Init(uint16_t a); //輸入配置函數(shù)
uint16_t FLASH_ReadHalfWord(uint32_t address); //到address讀一個(gè)16位數(shù)據(jù)
void FLASH_WriteMoreData(uint32_t startAddress,uint16_t *writeData,uint16_t countToWrite); //address寫入任意長度的16位數(shù)據(jù)
void Updata_Channel(void);   //更新電臺(tái)存儲(chǔ),將數(shù)組中的電臺(tái)寫入FLASH中
void Updata_W_Channel(void); //將Flash中的電臺(tái)頻率讀到數(shù)組中





int main(void)
{
                        delay_init(); //延時(shí)函數(shù)初始化
                        OLED_Init();  //1.3寸或0.96寸OLED均可以驅(qū)動(dòng)
                        TIM3_INIT_Config(10);                          //定時(shí)10ms中斷
                        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設(shè)置中斷優(yōu)先級(jí)分組為組2:2位搶占優(yōu)先級(jí),2位響應(yīng)優(yōu)先級(jí)
                //        OLED_ColorTurn(0);                             //0正常顯示,1 反色顯示
                //        OLED_DisplayTurn(0);                           //0正常顯示 1 屏幕翻轉(zhuǎn)顯示
                        Tea_Init(1);                                 //收音機(jī)模塊初始化
                        DrawFirst1();                                //主界面
                        OLED_Refresh();                              //更新顯示
            DS1302_init();                               //DS1302初始化
            InputA_Init(GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4); //按鍵輸入設(shè)置
                //        Search(Frequence*10);                        //搜索
        while(1)
        {
                if(KeyState[0]==255){
                         KeyState[0] = 0;
                         Menu1++;
                        if(Menu1>2) Menu1=0; // 三種狀態(tài)中切換:菜單 音量 無
                }
                  DrawFirst1();   //畫出基本界面
                          switch (Menu1){                  //設(shè)定區(qū)域反顯操作
                                case 1: OLED_ShowChinese(0,2,3,16,0),
                            OLED_ShowChinese(16,2,4,16,0);   break; //菜單
                                case 2: OLED_ShowChinese(75,2,5,16,0),
                            OLED_ShowChinese(91,2,6,16,0);   break; //音量
                                default:break;
                }
       if(Menu1 == 1){ //菜單鍵 為了保持程序可讀性和整潔性,重復(fù)判斷了兩次Menu1的狀態(tài),可以將上面的顯示更新代碼移到if的大括號(hào)中
                         if(KeyState[1]==255)
       SetPicture1_1();                 //進(jìn)入菜單界面                 
       }
                         else if(Menu1 == 2){ //調(diào)節(jié)音量,由于模塊本身不具有音量調(diào)節(jié)功能,故需要自行開發(fā)推薦用PWM來完成,音量大小用全局變量Laud表示,每次調(diào)音量都重新寫入
                           if(KeyState[1]==255)      {Laud++,KeyState[1]=0,Search(Frequence*10);}
                                 else if(KeyState[2]==255) {Laud--,KeyState[2]=0,Search(Frequence*10);} //9:01001 16: 10000 15:01111
         if(Laud>19) Laud = 0; //19級(jí)可調(diào)
       }
                        OLED_Refresh(); //更新顯示
                }
}



void InputA_Init(uint16_t a){ //按鍵初始化
GPIO_InitTypeDef  GPIO_InitStructure;     
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);      
GPIO_InitStructure.GPIO_Pin = a;                     
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //當(dāng)按鍵沒有按下時(shí),IO口檢測(cè)為高電平,為上拉電阻模式,按下IO口與地連接,為低電平   
GPIO_Init(GPIOA ,&GPIO_InitStructure);  
}



void Updata_R_Channel(void)
{
        u8 i;
        for(i=0; i<40; i++)
        {
                Channel[ i] = FLASH_ReadHalfWord(StartPosition + 2*i);
        }
        
}




void Updata_W_Channel(void)
{
        FLASH_WriteMoreData(StartPosition,Channel,40);
}






uint16_t FLASH_ReadHalfWord(uint32_t address)
{
   return *(__IO uint16_t*)address;
}







void FLASH_WriteMoreData(uint32_t startAddress,uint16_t *writeData,uint16_t countToWrite)
  {   
      uint32_t offsetAddress=startAddress - 0X08000000;               //計(jì)算去掉0X08000000后的實(shí)際偏移地址
      uint32_t sectorPosition=offsetAddress/2048;            //計(jì)算扇區(qū)地址,對(duì)于STM32F103VET6為0~255
      uint32_t sectorStartAddress=sectorPosition*2048+FLASH_BASE;    //對(duì)應(yīng)扇區(qū)的首地址
      uint16_t dataIndex;


   FLASH_Unlock();         //解鎖寫保護(hù)

   FLASH_ErasePage(sectorStartAddress);//擦除這個(gè)扇區(qū)

   for(dataIndex=0;dataIndex<countToWrite;dataIndex++)
   {
     FLASH_ProgramHalfWord(startAddress+dataIndex*2,writeData[dataIndex]);
   }

   FLASH_Lock();//上鎖寫保護(hù)
}










void DrawFirst1(void)
{
          OLED_ShowNum(47,28,Time[4],1,16,1);//時(shí)間數(shù)字
    OLED_ShowNum(55,28,Time[5],1,16,1);
          OLED_ShowString(63,28,":",16,1);
          OLED_ShowNum(71,28,Time[0],1,16,1);
          OLED_ShowNum(79,28,Time[1],1,16,1);
          OLED_ShowNum(90,35,Time[2],1,8,1);
          OLED_ShowNum(96,35,Time[3],1,8,1);
               
          OLED_ShowNum(47,48,Frequence/100,3,16,1);//頻率
          OLED_ShowNum(80,48,Frequence%100,2,16,1);
          OLED_ShowString(72,48,".",16,1);
          OLED_ShowString(100,48,"MHZ",16,1);
        
          OLED_ShowChinese(0,2,3,16,1); //菜單
                OLED_ShowChinese(16,2,4,16,1);
        
          OLED_ShowChinese(75,2,5,16,1); //音量
                OLED_ShowChinese(91,2,6,16,1);
          OLED_ShowNum(110,2,Laud,2,16,1);
        
                OLED_ShowChinese(0,28,7,16,1); //時(shí)間
                OLED_ShowChinese(16,28,8,16,1);
                OLED_ShowString(32,28,":",16,1);
        
                OLED_ShowChinese(0,48,13,16,1); //頻率
                OLED_ShowChinese(16,48,19,16,1);
                OLED_ShowString(32,48,":",16,1);
               
                OLED_DrawLine(0,21,130,21,1);
}



void DrawFirst2(void)
{
            
                  OLED_ShowChinese(0,0-ItemSwitch,14,16,1); //自動(dòng)搜臺(tái)
                                                OLED_ShowChinese(16,0-ItemSwitch,15,16,1);
                                          OLED_ShowChinese(32,0-ItemSwitch,16,16,1);
                                          OLED_ShowChinese(48,0-ItemSwitch,17,16,1);
                                         
                                          OLED_ShowChinese(0,16-ItemSwitch,18,16,1); //手動(dòng)搜臺(tái)
                                                OLED_ShowChinese(16,16-ItemSwitch,15,16,1);
                                          OLED_ShowChinese(32,16-ItemSwitch,16,16,1);
                                          OLED_ShowChinese(48,16-ItemSwitch,17,16,1);
                                         
                                                OLED_ShowChinese(0,32-ItemSwitch,29,16,1), //存取電臺(tái)
                                          OLED_ShowChinese(16,32-ItemSwitch,33,16,1),
                                                OLED_ShowChinese(32,32-ItemSwitch,28,16,1),
                                          OLED_ShowChinese(48,32-ItemSwitch,17,16,1);
                                                                        
                                                OLED_ShowChinese(0,48-ItemSwitch,22,16,1), //設(shè)置鬧鐘
                                                OLED_ShowChinese(16,48-ItemSwitch,23,16,1),
                                                OLED_ShowChinese(32,48-ItemSwitch,9,16,1),
                                                OLED_ShowChinese(48,48-ItemSwitch,10,16,1);
        
            OLED_ShowChinese(0,64-ItemSwitch,22,16,1), //設(shè)置時(shí)間
                                                OLED_ShowChinese(16,64-ItemSwitch,23,16,1),
                                                OLED_ShowChinese(32,64-ItemSwitch,7,16,1),
                                                OLED_ShowChinese(48,64-ItemSwitch,8,16,1);
                                                
                                                OLED_ShowChinese(0,80-ItemSwitch,37,16,1); //設(shè)置亮度
                                                OLED_ShowChinese(16,80-ItemSwitch,38,16,1);
                                          OLED_ShowChinese(32,80-ItemSwitch,39,16,1);
                                          OLED_ShowChinese(48,80-ItemSwitch,40,16,1);
                                                                        
                                                OLED_ShowChinese(0,96-ItemSwitch,31,16,1),//恢復(fù)設(shè)置
                                                OLED_ShowChinese(16,96-ItemSwitch,32,16,1),
                                                OLED_ShowChinese(32,96-ItemSwitch,22,16,1),
                                                OLED_ShowChinese(48,96-ItemSwitch,23,16,1);
                                                                        
                                                OLED_ShowChinese(94,48,20,16,1),//返回
                                                OLED_ShowChinese(110,48,21,16,1);
}



void DrawFirst3(void)
{
                  OLED_ShowChinese(32,0,22,16,1); //設(shè)置頻率
                                                OLED_ShowChinese(48,0,23,16,1);
                                          OLED_ShowChinese(64,0,13,16,1);
                                          OLED_ShowChinese(80,0,19,16,1);

                  OLED_ShowChinese(94,48,20,16,1);//返回
                                          OLED_ShowChinese(110,48,21,16,1);
        
                  OLED_ShowChinese(0,48,24,16,1); //確認(rèn)
                                                OLED_ShowChinese(16,48,25,16,1);
        
                  OLED_ShowChinese(48,48,26,16,1); //步進(jìn)
                                          OLED_ShowChinese(64,48,27,16,1);

        
            OLED_ShowString(48,24,".",8,1); //頻率數(shù)據(jù)
                  OLED_ShowString(78,24,"MHZ",8,1);
                        OLED_ShowNum(20,24,SetNumber[0],1,8,1);
                                                OLED_ShowNum(30,24,SetNumber[1],1,8,1);
                                                OLED_ShowNum(40,24,SetNumber[2],1,8,1);
                                                OLED_ShowNum(56,24,SetNumber[3],1,8,1);
                  OLED_ShowNum(66,24,SetNumber[4],1,8,1);
                                                
                                                OLED_ShowNum(110,24,Signal,2,8,1); //信號(hào)強(qiáng)度
}



void DrawFirst4(void)
{
                  OLED_ShowChinese(32,0,22,16,1); //設(shè)置時(shí)間
                                                OLED_ShowChinese(48,0,23,16,1);
                                          OLED_ShowChinese(64,0,7,16,1);
                                          OLED_ShowChinese(80,0,8,16,1);

                  OLED_ShowChinese(94,48,20,16,1);//返回
                                          OLED_ShowChinese(110,48,21,16,1);
        
                  OLED_ShowChinese(0,48,24,16,1); //確認(rèn)
                                                OLED_ShowChinese(16,48,25,16,1);

                        OLED_ShowNum(50,26,TimeBuff[0],2,8,1); //時(shí)間
                  OLED_ShowString(63,26,":",8,1);
                                                OLED_ShowNum(68,26,TimeBuff[1],2,8,1);
}        



void DrawFirst5(void)
{
          OLED_ShowString(20,0,"Channel:",16,1); //頻道顯示
    OLED_ShowNum(84,0,ChannelSet,2,16,1);        
        
          OLED_ShowNum(22,25,Channel[ChannelSet]/100,3,16,1);//頻率數(shù)據(jù)
          OLED_ShowNum(55,25,Channel[ChannelSet]%100,2,16,1);
          OLED_ShowString(47,25,".",16,1);
          OLED_ShowString(75,25,"MHZ",16,1);
        
          OLED_ShowChinese(0,48,33,16,1);  //取臺(tái)
                OLED_ShowChinese(16,48,17,16,1);
                OLED_ShowChinese(48,48,29,16,1); //存臺(tái)
                OLED_ShowChinese(64,48,17,16,1);
          OLED_ShowChinese(94,48,20,16,1); //返回
                OLED_ShowChinese(110,48,21,16,1);
        
}

......限于篇幅余下代碼下載附件......

代碼工程51hei下載地址:
TEA5767收音機(jī).7z (630.89 KB, 下載次數(shù): 194)

評(píng)分

參與人數(shù) 1黑幣 +100 收起 理由
admin + 100 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏17 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:170270 發(fā)表于 2021-8-13 14:37 | 只看該作者
能收到幾個(gè)臺(tái)?為啥我做的總是只有3到4個(gè)清晰地臺(tái)。。。。
回復(fù)

使用道具 舉報(bào)

板凳
ID:338727 發(fā)表于 2021-8-14 13:34 來自觸屏版 | 只看該作者
依然是你 發(fā)表于 2021-8-13 14:37
能收到幾個(gè)臺(tái)?為啥我做的總是只有3到4個(gè)清晰地臺(tái)。。。。

我做的只能收到強(qiáng)臺(tái),弱臺(tái)不清晰
回復(fù)

使用道具 舉報(bào)

地板
ID:525016 發(fā)表于 2022-12-3 15:27 | 只看該作者
請(qǐng)問樓主,能分享一下原理圖嗎?謝謝
回復(fù)

使用道具 舉報(bào)

5#
ID:651494 發(fā)表于 2022-12-10 16:27 | 只看該作者
的沈嬌妮 發(fā)表于 2021-8-14 13:34
我做的只能收到強(qiáng)臺(tái),弱臺(tái)不清晰

OLED會(huì)干擾FM接收靈敏度,解決的方法:1,軟件OLED寫入只在數(shù)據(jù)更新時(shí)寫入一次,不要頻繁循環(huán)寫入;2,OLED數(shù)據(jù)時(shí)鐘線使用三極管隔離反向,濾波電容處理,可以增加阻抗,從而降低IIC輻射干擾;3,硬件收音模塊,OLED電源等濾波,OLED有條件可以加裝接地屏蔽罩
回復(fù)

使用道具 舉報(bào)

6#
ID:1062732 發(fā)表于 2023-2-14 23:04 | 只看該作者
請(qǐng)問樓主只能收到電流聲,收不到電臺(tái)里的聲音是怎么回事
回復(fù)

使用道具 舉報(bào)

7#
ID:72088 發(fā)表于 2023-2-27 18:11 | 只看該作者
數(shù)碼管靜態(tài)顯示屏才能避免干擾收聽廣播,多年經(jīng)驗(yàn)總結(jié),
回復(fù)

使用道具 舉報(bào)

8#
ID:996773 發(fā)表于 2023-3-1 13:18 | 只看該作者


我是剛學(xué)匯編兩年沒多久,拋磚引玉,匯編程序短小精悍,4k容量51單片機(jī)足夠跑了,

同時(shí)驅(qū)動(dòng)液晶和LED,想用哪個(gè)就哪個(gè),直接驅(qū)動(dòng)松下大廠的原裝收音板,松下的品質(zhì)

我就不用說了。有頻道模式和頻率雙模式,內(nèi)部eeprom存儲(chǔ)30個(gè)頻道的頻率,立體聲和

單聲道可選
回復(fù)

使用道具 舉報(bào)

9#
ID:621661 發(fā)表于 2025-5-2 21:32 | 只看該作者
無人之 發(fā)表于 2023-2-14 23:04
請(qǐng)問樓主只能收到電流聲,收不到電臺(tái)里的聲音是怎么回事

我的也是這種情況,請(qǐng)問你是怎么解決的
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表