标题:
网友TEA5767做FM收音机
[打印本页]
作者:
51黑fan
时间:
2016-1-30 01:17
标题:
网友TEA5767做FM收音机
本帖最后由 51黑fan 于 2016-1-30 01:18 编辑
可能好多朋友说一个买收音机也就几块钱,何必花这么大精力鼓捣这个烂玩意,如果真有这个想法的朋友请打住,不要在往下面看了。之前也一直认为TEA5767较差,实际中发觉选择大厂的模块出来的音频经放大器推动后还是很有震撼力,大大超出我的预期。不过前提是使用好模块,而不是现在满淘宝卖的那种5-7块左右的那种简装版咯。
TEA5767主要出来的音频没音量控制,也不够推动耳机。我就外加电子音量调节芯片、小功率放大、调节显示等。我电子音量选用M62429 显示选用了一种非常小尺寸的MINI1602 另外使用了手机上那种5向导航键、加了单键开关机电路,小功率放大选用2块TDA2822(3-6V) 就是TDA2822这次把我害惨了,PCB出来后所有正常,就是推动2个2W的小喇叭会有那种噗噗声,晕死。线路输出则很好,在网上一查,发觉很多朋友都有这个问题,现在这个玩意买不到贴片封装的原装进口的,而国产的做BTL方式放大时,由于内部2个放大器的参数国产工艺存在差异较大造成,而做普通双声道放大则不存在这个问题。唉~~ 国货呀,你什么时候才能让人放心!发誓以后再一不会选择使用TDA2822这个垃圾了(需要的朋友 我可以送 现在看着就恼火)
内部震荡 8M
部分参考程序:
Tea5767.c
#include "Tea5767.h"
#include "TwiLib.h"
// 初始化TEA5767
void TEA5767_Init(ulong Freq,uchar Mono)
{
// 初始化
TWI_Init();
TEA5767_Adjust(Freq,Mono,TRUE);
}
// 调整频率、声道
void TEA5767_Adjust(ulong Freq,uchar Mono,uchar MuteControl)
{
uchar data[5] = { 0 };
ulong pll = TEA5767_GetPLLFromFreq(Freq);
data[0] = (uchar)(pll/256);
data[1] = (uchar)(pll%256);
data[2] = (Mono!=0)?0x09:0x01;
data[3] = 0x92;
if( MuteControl )
{
data[0] |= 0x80;
TWI_MasterSendBytes(TEA5767_TWI_ADDR,5,data);
data[0] &= 0x7f;
DelayMs(500);
}
TWI_MasterSendBytes(TEA5767_TWI_ADDR,5,data);
}
// 信号强度
uchar TEA5767_GetLevel()
{
uchar data[5] = { 0 };
TWI_MasterRecvBytes(TEA5767_TWI_ADDR,5,data);
return (data[3]>>4);
}
// 由频率计算PLL(频率单位为KHZ)
ulong TEA5767_GetPLLFromFreq(ulong Freq)
{
ulong pll = (ulong)(((Freq-225)*4000)/32768);
return pll;
}
// 由PLL计算频率(频率单位为KHZ)
ulong TEA5767_GetFreqFromPLL(ulong Pll)
{
ulong Freq = (ulong)(((float)Pll)*((float)8.192)+225);
return Freq;
}
Tea5767.h
#ifndef __TEA5767__H__INCLUDED__
#define __TEA5767__H__INCLUDED__
#include "common.h"
// TEA5767的TWI地址
#define TEA5767_TWI_ADDR 0xC0 // TEA5767基地址
// 初始化TEA5767(频率单位为KHZ)
void TEA5767_Init(ulong Freq,uchar Mono);
// 调整频率、声道
void TEA5767_Adjust(ulong Freq,uchar Mono,uchar MuteControl);
// 信号强度
uchar TEA5767_GetLevel();
// 由频率计算PLL(频率单位为KHZ)
ulong TEA5767_GetPLLFromFreq(ulong Freq);
// 由PLL计算频率(频率单位为KHZ)
ulong TEA5767_GetFreqFromPLL(ulong Pll);
#endif // __TEA5767__H__INCLUDED__
FM62429.c
#include "FM62429.h"
// 初始化函数
void FM62429_Init(uchar Volume)
{
FM62429_PORT_INIT();
FM62429_AdjustVolume(Volume);
}
// 调整音量(0~84)
void FM62429_AdjustVolume(uchar Volume)
{
uchar i = 0;
ushort VolData = 0;
if( Volume > 0 )
{
Volume = Volume+3;
VolData = (ushort)(Volume&0x7C);
VolData |= (ushort)((Volume&0x03)<<7);
}
// D9、D10均为1
VolData |= 0x600;
FM62429_SDA_L();
FM62429_SCL_L();
for( i = 0; i < 10; i++)
{
if( VolData & 0x01 )
FM62429_SDA_H();
else
FM62429_SDA_L();
FM62429_SCL_H();
FM62429_SDA_L();
FM62429_SCL_L();
VolData >>= 1;
}
FM62429_SDA_H();
FM62429_SCL_H();
NOP();
FM62429_SCL_L();
}
FM62429.h
#ifndef __FM62429_H_INCLUDED__
#define __FM62429_H_INCLUDED__
#include "Common.h"
// 端口定义
#define FM62429_SDA_H() SET_BIT(PORTB,PB2)
#define FM62429_SDA_L() CLR_BIT(PORTB,PB2)
#define FM62429_SCL_H() SET_BIT(PORTB,PB5)
#define FM62429_SCL_L() CLR_BIT(PORTB,PB5)
#define FM62429_PORT_INIT() SET_BIT(DDRB,DDB2);SET_BIT(DDRB,DDB5)
// 初始化函数
void FM62429_Init(uchar Volume);
// 调整音量(0-83)
void FM62429_AdjustVolume(uchar Volume);
#endif //__FM62429_H_INCLUDED__
main.c
#include <avr/eeprom.h>
#include "common.h"
#include "LCD1602.h"
#include "TWILib.h"
#include "Tea5767.h"
#include "FM62429.h"
#define OPER_MODE_RADIO 0 // 正常收音机模式
#define OPER_MODE_SET 1 // 设置模式
// 正确保存标志
#define SAVE_MASK 0x4B // 'K'
// 设置模式
#define SET_MODE_SEARCH 1 // 搜索
#define SET_MODE_SOUNDMODE 2 // 立体声、单声道模式选中
#define SET_MODE_MIN 1
#define SET_MODE_MAX 2
// 声音模式
#define SOUND_MODE_STEREO 1
#define SOUND_MODE_MONO 2
#define SOUND_MODE_MIN 1
#define SOUND_MODE_MAX 2
// 音量
#define VOLUME_MAX 84
#define VOLUME_MIN 0
#define CHANNEL_NUM 10
#define CHANNEL_MIN 1
#define CHANNEL_MAX CHANNEL_NUM
// 搜索模式
#define STATE_SEARCH 1
#define STATE_STORE 2
// 最小频率
#define FREQ_MIN ((ulong)87500)
#define FREQ_MAX ((ulong)120000)
// 全局变量
uchar OperMode = OPER_MODE_RADIO; // 操作模式
uchar SetMode = SET_MODE_MIN; // 搜索频道
uchar SoundMode = SOUND_MODE_MIN; // 声音模式
BOOL DoingMenu = FALSE; // 是否处于选择菜单方式
ushort BlinkCounter = 0; // 控制闪烁
uchar Volume = 42; // 音量
ulong ChannelFreq = 96600; // 频道频率(单位为KHZ)
ulong ChannelSearch = FREQ_MIN; // 搜索起始频率
uchar ChannelIndex = 0; // 当前播放的频道编号(1-10)
uchar ChannelSaveIndex = CHANNEL_MIN;
uchar ChannelState = STATE_SEARCH;
// 开关健(PD7)
#define POWER_ON()
#define POWER_OFF() SET_BIT(DDRD,DDD7);CLR_BIT(PORTD,PD7);
// 闪烁控制变量的最大值
#define BLINK_COUNTER_MAX 10
// 是否闪烁
#define IS_BLINK() (BlinkCounter > BLINK_COUNTER_MAX/2)
//======================================================================================================
// 预先保持的10个频道
//======================================================================================================
ulong EEMEM ChannelConfig[CHANNEL_NUM+1] = { 0 };
ulong ChannelArray[CHANNEL_NUM+1 ] = { 0 };
// 读取预先保持的频道
void ReadChannelConfig()
{
ulong data = 0;
uchar mask = 0 , i = 0;
// 等待EEPROM空闲
eeprom_busy_wait();
// 写入数据
eeprom_read_block( ChannelArray,ChannelConfig, 4*(1+CHANNEL_NUM));
// 解析第一个字节,构造第一个字节,从地位到高位分别是:ChannelIndex,Volume,SoundMode,SAVEMASK
data = ChannelArray[0];
ChannelIndex = (uchar)(data & 0xFF);
data >>= 8;
Volume = (uchar)(data & 0xFF);
data >>= 8;
SoundMode = (uchar)(data & 0xFF);
data >>= 8;
mask = (uchar)(data & 0xFF);
if( ( mask != SAVE_MASK ) ||
( ChannelIndex < CHANNEL_MIN || ChannelIndex > CHANNEL_MAX ) ||
( SoundMode < SOUND_MODE_MIN || SoundMode > SOUND_MODE_MAX ) ||
( Volume > VOLUME_MAX ) )
{
ChannelIndex = 0;
Volume = 42;
SoundMode = SOUND_MODE_STEREO;
for(i = 0; i < CHANNEL_NUM+1; i++ )
ChannelArray[i] = 0;
}
else
{
ChannelFreq = ChannelArray[ChannelIndex];
}
}
// 写设置
void WriteChannelConfig()
{
// 构造第一个字节,构造第一个字节,从低位到高位分别是:ChannelIndex,Volume,SoundMode,SaveMask
ulong data = SAVE_MASK;
data <<=8;
data |= SoundMode;
data <<=8;
data |= Volume;
data <<=8;
data |= ChannelIndex;
ChannelArray[0] = data;
// 等待EEPROM空闲
eeprom_busy_wait();
// 写入数据
eeprom_write_block( ChannelArray,ChannelConfig, 4*(1+CHANNEL_NUM) );
}
// 显示存储频道信息
void DisplayFreqSave(uchar Index)
{
uchar i = 0;
uchar buffer[17] = { 0 };
// 显示音量、声音模式
for( i = 0;i < 16; i++ )buffer[i] = ' ' ;
buffer[0] = 'S';
buffer[1] = 'T';
buffer[2] = 'O';
buffer[3] = 'R';
buffer[4] = 'E';
buffer[5] = ':';
buffer[6] = 'C';
buffer[7] = 'H';
buffer[8] = (Index/10)+'0';
buffer[9] = (Index%10)+'0';
LCD1602_Display_String(1,0,buffer);
}
// 显示频率信息
void DisplayFreqInfo(ulong Freq,uchar Index)
{
uchar i = 0,j = 0;
ulong data = 0;
uchar buffer[17] = { 0 };
// 显示频率
data = Freq/10;
for( i = 0;i < 16; i++ )buffer[i] = ' ';
if( Index <= CHANNEL_MAX )
{
j = 3;
buffer[0] = (Index/10)+'0';
buffer[1] = (Index%10)+'0';
}
else
{
j = 2;
}
buffer[j+0] = 'F';
buffer[j+1] = 'M';
buffer[j+2] = ':';
if( data > 9999 )
{
data %= 100000;
buffer[j+3] = (data/10000)+'0';data %= 10000;
buffer[j+4] = (data/1000)+'0'; data %= 1000;
buffer[j+5] = (data/100)+'0'; data %= 100;
buffer[j+6] = '.';
buffer[j+7] = (data/10)+'0'; data %= 10;
buffer[j+8]= (data%10)+'0';
buffer[j+9]= 'M';
buffer[j+10]= 'H';
buffer[j+11]= 'Z';
}
else
{
buffer[j+3] = (data/1000)+'0';data %= 1000;
buffer[j+4] = (data/100)+'0'; data %= 100;
buffer[j+5] = '.';
buffer[j+6] = (data/10)+'0'; data %= 10;
buffer[j+7] = (data%10)+'0';
buffer[j+8]= 'M';
buffer[j+9]= 'H';
buffer[j+10]= 'Z';
}
LCD1602_Display_String(2,0,buffer);
}
//=======================================================================
// 按键处理
//=======================================================================
// 按键S1-S5(PD2-PD7)
// 是否为单个键按下
#define IS_KEY_PRESSED(k) (((k) > 0) && (((k) & ((k)-1)) == 0 ))
//#define GET_KEY_CODE() ((~PIND) & 0x1F)
#define KEY_CODE(n) (((uchar)1) << (n) )
#define KEY_S1 KEY_CODE(0)
#define KEY_S2 KEY_CODE(1)
#define KEY_S3 KEY_CODE(2)
#define KEY_S4 KEY_CODE(3)
#define KEY_S5 KEY_CODE(4)
#define KEY_S6 KEY_CODE(5)
// 读取按键
uchar GET_KEY_CODE()
{
uchar keycode = PIND;
keycode >>= 2;
keycode = ~keycode;
keycode &= 0x3F; // 6个键
return keycode;
}
// 读取按键
uchar GetKey( )
{
uchar key = 0;
static uchar lastkey = 0; // 记录上次的按键
// 读取键盘
key = GET_KEY_CODE();
if( !IS_KEY_PRESSED(key) )
{
lastkey = 0;
return 0;
}
// 确定是否新的键按下
if( lastkey == 0 )
{
lastkey = key; // 保存本次扫描结果
DelayMs(10); // 去抖处理
key = GET_KEY_CODE();
if( key == lastkey )
{
return key;
}
}
return 0;
}
//=======================================================================
// 设置函数
//=======================================================================
void SetHandler()
{
uchar key = 0;
// 切换闪烁标志
BlinkCounter++;
if( BlinkCounter > BLINK_COUNTER_MAX )
BlinkCounter = 0;
// 确定是否为选择菜单
if( DoingMenu )
{
key = GetKey();
if( key == KEY_S1) // 设置键(确认)
{
DoingMenu = FALSE; // 结束菜单选择
if( SetMode == SET_MODE_SOUNDMODE )
SoundMode = SOUND_MODE_MIN;
else
ChannelState = STATE_SEARCH;
}
else if( key == KEY_S4 ) // 左移键
{
if(SetMode <= SET_MODE_MIN)
SetMode = SET_MODE_MAX;
else
SetMode--;
}
else if( key == KEY_S5 ) // 右移键
{
if( SetMode >= SET_MODE_MAX )
SetMode = SET_MODE_MIN;
else
SetMode++;
}
else // 显示菜单
{
// 选中的菜单应该闪烁(SETMODE)
LCD1602_Display_String(1,0,(const uchar*)" FM RADIO ");
LCD1602_Display_String(2,0,(const uchar*)"1:SEARCH 2:MODE ");
if(IS_BLINK())
{
if( SetMode == SET_MODE_SEARCH )
LCD1602_Display_Char(2,0,' ');
else
LCD1602_Display_Char(2,9,' ');
}
}
}
else
{
key = GetKey();
if( SetMode == SET_MODE_SOUNDMODE ) // 声音模式
{
if( key == KEY_S1) // 确认
{
// 结束设置
OperMode = OPER_MODE_RADIO;
}
else if( key == KEY_S4 ) // 左移键
{
if(SoundMode <= SOUND_MODE_MIN)
SoundMode = SOUND_MODE_MAX;
else
SoundMode--;
// 保存声道模式
WriteChannelConfig();
}
else if( key == KEY_S5 ) // 右移键
{
if( SoundMode >= SOUND_MODE_MAX )
SoundMode = SOUND_MODE_MIN;
else
SoundMode++;
// 保存声道模式
WriteChannelConfig();
}
else // 显示菜单
{
// 显示声音模式菜单,选中的声音模式闪烁
LCD1602_Display_String(1,0,(const uchar*)"MODE ");
LCD1602_Display_String(2,0,(const uchar*)"1.STEREO 2.MONO");
if(IS_BLINK())
{
if( SoundMode == SOUND_MODE_STEREO )
LCD1602_Display_Char(2,0,' ');
else
LCD1602_Display_Char(2,10,' ');
}
}
}
else // 搜索频道
{
if(ChannelState == STATE_SEARCH)
{
if( key == KEY_S1)
{
ChannelState = STATE_STORE;
}
else if ( key == KEY_S2 )
{
if( ChannelSearch < FREQ_MAX )
{
ChannelSearch += 100;
TEA5767_Adjust( ChannelSearch,(SoundMode == SOUND_MODE_MONO),FALSE);
}
}
else if( key == KEY_S3 )
{
if( ChannelSearch > FREQ_MIN )
{
ChannelSearch -= 100;
TEA5767_Adjust( ChannelSearch,(SoundMode == SOUND_MODE_MONO),FALSE);
}
}
else
{
LCD1602_Display_String(1,0,(const uchar*)"SEARCHING... ");
DisplayFreqInfo(ChannelSearch,CHANNEL_MAX+1);
}
}
else // 选择存取频道
{
if( key == KEY_S1)
{
// 显示正在存储信息
LCD1602_Display_String(1,0,(const uchar*)"STOREING... ");
DisplayFreqInfo(ChannelSearch,CHANNEL_MAX+1);
// 存储频道信息
ChannelArray[ChannelSaveIndex] = ChannelSearch;
WriteChannelConfig();
// 显示存储完成信息
LCD1602_Display_String(1,0,(const uchar*)"STORE OK! ");
DisplayFreqInfo(ChannelSearch,CHANNEL_MAX+1);
// 自动移动到下一个频道
if(ChannelSaveIndex < CHANNEL_MAX )
ChannelSaveIndex++;
else
ChannelSaveIndex = CHANNEL_MIN;
// 切换到正常收听状态
OperMode = OPER_MODE_RADIO;
}
else if ( key == KEY_S4 )
{
if( ChannelSaveIndex > CHANNEL_MIN )
ChannelSaveIndex--;
}
else if( key == KEY_S5 )
{
if( ChannelSaveIndex < CHANNEL_MAX )
ChannelSaveIndex++;
}
else
{
DisplayFreqSave(ChannelSaveIndex);
DisplayFreqInfo(ChannelSearch,CHANNEL_MAX+1);
}
}
}
}
}
//=======================================================================
// 显示音量、信号强度、声音模式、频率
//=======================================================================
void DisplayChannelInfo()
{
uchar i = 0;
uchar buffer[17] = { 0 };
uchar level = TEA5767_GetLevel(); // 0-15
for( i = 0;i < 16; i++ )buffer[i] = ' ' ;
// 显示音量、声音模式
buffer[6] = 'V';
buffer[7] = 'O';
buffer[8] = 'L';
buffer[9] = ':';
buffer[10]= (Volume/10)+'0';
buffer[11]= (Volume%10)+'0';
if( SoundMode == SOUND_MODE_STEREO)
{
buffer[14]= 'S';
buffer[15]= 'T';
}
else
{
buffer[14]= 'M';
buffer[15]= 'O';
}
LCD1602_Display_String(1,4,&buffer[4]);
LCD1602_Display_Volume();
LCD1602_Display_Level(level);
// 显示频率
DisplayFreqInfo(ChannelFreq,ChannelIndex);
}
// 正常收听函数
void RadioHandler()
{
DisplayChannelInfo();
}
// 关机函数
void PowerOff()
{
LCD1602_Display_String(1,0,(const uchar*)"Power Off ... ");
LCD1602_Display_String(2,0,(const uchar*)" ");
DelayMs(500);
POWER_OFF();
}
//=======================================================================
// 主函数
//=======================================================================
int main()
{
uchar key = 0;
// 初始化端口(S1-S5)
DDRD = 0;
PORTD = 0xFF;
// 先把音量改为0
FM62429_Init(0);
// 处理开关键
POWER_ON();
// 读取频道配置
ReadChannelConfig();
// LCD初始化
LCD1602_Init();
// Tea5767初始化
TEA5767_Init(ChannelFreq,(SoundMode == SOUND_MODE_MONO));
DelayMs(500);
// FM62429初始化
if( Volume %2 ) Volume--;
FM62429_AdjustVolume(Volume);
while(1)
{
// 设置模式
if( OperMode == OPER_MODE_SET )
{
SetHandler();
}
else // 正常收听模式
{
key = GetKey();
switch(key)
{
case KEY_S1:
OperMode = OPER_MODE_SET;
DoingMenu = TRUE;
SetMode = SET_MODE_MIN;
// 调用设置函数
SetHandler();
break;
case KEY_S2: // 音量增加
if(Volume < VOLUME_MAX )
{
Volume += 2;
FM62429_AdjustVolume(Volume);
WriteChannelConfig();// 保存音量
}
break;
case KEY_S3: // 音量减少
if( Volume > VOLUME_MIN )
{
Volume -=2;
FM62429_AdjustVolume(Volume);
WriteChannelConfig();// 保存音量
}
break;
case KEY_S4: // 切换到前一频道
if( ChannelIndex > CHANNEL_MIN )
{
ChannelIndex--;
ChannelFreq = ChannelArray[ChannelIndex];
FM62429_AdjustVolume(0);
TEA5767_Adjust( ChannelFreq,(SoundMode == SOUND_MODE_MONO),FALSE);
DelayMs(500);
FM62429_AdjustVolume(Volume);
WriteChannelConfig(); // 保存频道
}
break;
case KEY_S5: // 切换到后一频道
if( ChannelIndex < CHANNEL_MAX )
{
ChannelIndex++;
ChannelFreq = ChannelArray[ChannelIndex];
FM62429_AdjustVolume(0);
TEA5767_Adjust( ChannelFreq,(SoundMode == SOUND_MODE_MONO),FALSE);
DelayMs(500);
FM62429_AdjustVolume(Volume);
WriteChannelConfig();// 保存频道
}
break;
case KEY_S6:
PowerOff();
break;
default:
// 正常收听函数
RadioHandler();
break;
}
}
// 延时
DelayMs(50);
}
return 0;
}
复制代码
作者:
sunyou
时间:
2019-3-28 20:55
您好,有图纸吗
作者:
12333890
时间:
2024-4-26 11:41
5向指的是ec11?
作者:
devcang
时间:
2024-4-26 12:07
也做过,放大用数字放大 PM8403。。。。使用红外遥控控制0-9快速选台、调频率、保存频率、调音量,等
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1