本帖最后由 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;
- }
復制代碼
|