接上TEA5767模块后可以接受FM电台87500——108000KHZ, 音量调节只能静音或者打开,因为模块本身不具有调节选项;可以手动设置频率(软件步进精度10KHZ,模块的角度不清楚)也可以自动搜台,但只能应对强台的搜索。OLED我用的是1.3寸的,0.96寸也是兼容的,但貌似1.3寸版本多了两列像素,所以可能边缘的显示0.96会出点小问题。收音模块我是用的带功放的,但最好买单独的模块来做,因为这个音量不可用程序调节!
主要模块和功能如下:
1、OLED屏:操作界面显示(选中时反显)
2、三个10K电阻下拉的按键:左边功能选择减,中间兼“确认”和“减”功能,右边“加”功能
3、DS1302:提供实时时钟:可修改时间
4、TEA5767完整带功放模块:收音的核心,静音音量示数为0其余都表示声音“开”,配有音频口用于接入天线(实测插一个耳机效果最好)
5、STM32F103C6T6单片机:C8T6也可以用,完全兼容;不过程序也就18K左右用C8浪费了,SRAM也完全够了
模块的接线为:1、OLED: SCL->PA5 SDA->PA7 3.3V电源
2、按键:10K电阻下拉,接PA2、3、4,分别对应按键1,2,3
3、TEA5767模块:SCL->PB7 SDA->PB5
4、DS1302模块: RST->PB10 DAT->PB1 CLK->PB0
制作出来的实物图如下:
收音机整体模块
菜单界面
手动搜台,步进或设置
收音机主界面
存台取台
三个按键进行操作
实测多次代码各项功能都没有问题可以运行,另外程序中有一些功能选项没有写实现代码,例如“恢复设置”,它们不影响最终功能的实现可以自由写入需要恢复的变量;还有闹钟功能,只需要按照其他界面的设计逻辑写一些“if else”语句就可以实现,由于没有蜂鸣器就没写了。不过这些都不影响主要的功能的实现,毕竟它只是一个收音机...
部分STM32单片机代码如下:
#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 //存取台在flash中的起始位置,程序大概有18KB,不能与程序冲突
u32 Frequence; //频率全局变量,单位为10KHZ
u16 count=0,result,SystemTime,Channel[41]; //存取40个台,可更改
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读出的状态
void DrawFirst1(void); //分别为各个界面的驱动函数
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); //定时读取DS1302
void InputA_Init(uint16_t a); //输入配置函数
uint16_t FLASH_ReadHalfWord(uint32_t address); //到address读一个16位数据
void FLASH_WriteMoreData(uint32_t startAddress,uint16_t *writeData,uint16_t countToWrite); //address写入任意长度的16位数据
void Updata_Channel(void); //更新电台存储,将数组中的电台写入FLASH中
void Updata_W_Channel(void); //将Flash中的电台频率读到数组中
int main(void)
{
delay_init(); //延时函数初始化
OLED_Init(); //1.3寸或0.96寸OLED均可以驱动
TIM3_INIT_Config(10); //定时10ms中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
// OLED_ColorTurn(0); //0正常显示,1 反色显示
// OLED_DisplayTurn(0); //0正常显示 1 屏幕翻转显示
Tea_Init(1); //收音机模块初始化
DrawFirst1(); //主界面
OLED_Refresh(); //更新显示
DS1302_init(); //DS1302初始化
InputA_Init(GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4); //按键输入设置
// Search(Frequence*10); //搜索
while(1)
{
if(KeyState[0]==255){
KeyState[0] = 0;
Menu1++;
if(Menu1>2) Menu1=0; // 三种状态中切换:菜单 音量 无
}
DrawFirst1(); //画出基本界面
switch (Menu1){ //设定区域反显操作
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){ //菜单键 为了保持程序可读性和整洁性,重复判断了两次Menu1的状态,可以将上面的显示更新代码移到if的大括号中
if(KeyState[1]==255)
SetPicture1_1(); //进入菜单界面
}
else if(Menu1 == 2){ //调节音量,由于模块本身不具有音量调节功能,故需要自行开发推荐用PWM来完成,音量大小用全局变量Laud表示,每次调音量都重新写入
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级可调
}
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; //当按键没有按下时,IO口检测为高电平,为上拉电阻模式,按下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; //计算去掉0X08000000后的实际偏移地址
uint32_t sectorPosition=offsetAddress/2048; //计算扇区地址,对于STM32F103VET6为0~255
uint32_t sectorStartAddress=sectorPosition*2048+FLASH_BASE; //对应扇区的首地址
uint16_t dataIndex;
FLASH_Unlock(); //解锁写保护
FLASH_ErasePage(sectorStartAddress);//擦除这个扇区
for(dataIndex=0;dataIndex<countToWrite;dataIndex++)
{
FLASH_ProgramHalfWord(startAddress+dataIndex*2,writeData[dataIndex]);
}
FLASH_Lock();//上锁写保护
}
void DrawFirst1(void)
{
OLED_ShowNum(47,28,Time[4],1,16,1);//时间数字
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); //时间
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); //自动搜台
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); //手动搜台
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), //存取电台
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), //设置闹钟
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), //设置时间
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); //设置亮度
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),//恢复设置
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); //设置频率
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); //确认
OLED_ShowChinese(16,48,25,16,1);
OLED_ShowChinese(48,48,26,16,1); //步进
OLED_ShowChinese(64,48,27,16,1);
OLED_ShowString(48,24,".",8,1); //频率数据
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); //信号强度
}
void DrawFirst4(void)
{
OLED_ShowChinese(32,0,22,16,1); //设置时间
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); //确认
OLED_ShowChinese(16,48,25,16,1);
OLED_ShowNum(50,26,TimeBuff[0],2,8,1); //时间
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);//频率数据
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); //取台
OLED_ShowChinese(16,48,17,16,1);
OLED_ShowChinese(48,48,29,16,1); //存台
OLED_ShowChinese(64,48,17,16,1);
OLED_ShowChinese(94,48,20,16,1); //返回
OLED_ShowChinese(110,48,21,16,1);
}
......限于篇幅余下代码下载附件......
代码工程51hei下载地址:
TEA5767收音机.7z
(630.89 KB, 下载次数: 194)
|