Tea5767是飛利浦公司出的一款集成化的收音機芯片,大四的時候機緣巧合遇到了這個芯片,用了一下,寫點資料
主要特性
TEA5767HN是一款低功耗立體聲收音IC,廣泛應用於手機MP3 、MP 4 播放器等便攜系統。接收頻率 76 MHz ~108MHz ( 日本/美國/歐洲頻段選擇) ,中頻頻率 225kHz采用鎖相環調諧系統,帶有AG C電路,並可以使用軟件進行靜音和消除噪音。主要電性能指標工作電壓:2.5 V~5.0 V,工作電流10 m A,靈敏度1 5 V,立體聲分離度30dB,信噪比 6 0 d B,輸出信號電平7 5mV 。總線通信界面i 2 C和3 線總線可選,具有 R F信號強度ADC輸出,軟件靜音。TEA5767HN采用HVQFN40封裝
模塊額示意圖如下


該芯片主要依靠IIC通訊,不支持SUB_CLASS模式,也就是說,這個芯片沒有內部寄存器的概念,一共有五個命令字節,每次讀取直接發送芯片地址然后就可以讀取或者寫入,如下
IICstartàsend device addràwait ackàsend commandàwait ackàrepeat 5àsend stop
可見,沒有寫入寄存器
那么這五個命令字節分別有什么含義呢?見下表



另外,讀和寫並不是相同的定義,見下表


另外,對TEA5764的控制我們推薦每次寫入讀出都按照五個字節來做,因為這樣,在寫入完后,才能完全是我們設置的內容,但是,也可以發四個字節后直接停止,不影響,沒發的那個字節的數據在芯片內部保持不變(但是如果要修改第五個字節,就必須要發送第五位了.為了簡單起見,就發送五位吧)
另外,我們在芯片內部存放的是當前頻道的PLL值,頻率值需要根據PLL計算出來,計算公式如下
射頻信號經由天線輸入並經過LNA放大后,經過混頻后產生固定的中頻225KHZ
采用高邊帶接收時換算公式( HISI = 1 ) :

.采用低邊帶接收時換算公式(HISI = 0)

要接收 98 MHz頻率,采用高邊帶接收,晶體振盪器為32.768kHz,則對應PLL值為(十進制):
(4×98000000 + 225000))/32768 =11990
換算為十六進制制為2ED6H。
而如果采用低邊帶接收,對應PLL值為(十進制) :
(4×98000000—225000))/32768=11935
換算為十六進制為 2E9F
搜台的基本流程如下
設置搜索方向,當前頻率,通過SM啟動搜索,讀取數據(50MS一次),當RF==1的時候停止了,此時BLF==0,說明不是因為到極限停止的,這就是一個台,查看IF6看是否正確調諧,是的話,就說明這是個真台
具體代碼如下
#ifndef __TEA5767_H #define __TEA5767_H #include "uart.h" #include "delay.h" #include "ioremap.h" //不完善,但是可通信了 #define MAX_FREQ 108000 #define MIN_FREQ 87500 #define MAX_PLL 0x339b //108MHz時的pll, #define MIN_PLL 0x299d //87.5MHz時的pll #define F_IF 225000 //225KHZ中頻 #define F_RES 32768 //基准頻率 #define TEA_ACK_WAIT_TIME 200 //IIC ack等待時間 200us #define TEA5767ADDR_W 0xc0 #define TEA5767ADDR_R TEA5767ADDR_W+0X01 #define TEA_DEBUG 1 //初始化命令序列 #define TEA_INIT_CIMMAND1 0x2E #define TEA_INIT_CIMMAND2 0xD6 #define TEA_INIT_CIMMAND3 0x01 #define TEA_INIT_CIMMAND4 0x07 #define TEA_INIT_CIMMAND5 0x00 extern u8 TeaSendBuffer[5]; //寫入命令序列 extern u8 TeaReadBuffer[5]; //讀出命令序列 //初始化,初始化參數在初始化宏中定義 u8 TeaInit(void); //讀取一次 u8 TeaReadStatus(void); //獲取下一個電台的頻率 u32 TeaGetNextCh(u8 dir); u32 TeaGetCurrentFreq(void); #endif
#include "tea5767.h"
u8 TeaSendBuffer[5] = {0}; //寫入命令序列
u8 TeaReadBuffer[5] = {0}; //讀出命令序列
//IO方向設置
#define TEA_SDA_IN() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}
#define TEA_SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}
//IO操作函數
#define TEA_SCL PCout(10) //TEA SCL
#define TEA_SDA PCout(11) //TEA SDA
#define TEA_READ_SDA PCin(11) //輸入SDA
static void TEAIoInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;//PC10 PC11
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
TEA_SCL = 1;//初始化均為浮空狀態
TEA_SDA = 1;
TeaSendBuffer[0] = TEA_INIT_CIMMAND1;
TeaSendBuffer[1] = TEA_INIT_CIMMAND2;
TeaSendBuffer[2] = TEA_INIT_CIMMAND3;
TeaSendBuffer[3] = TEA_INIT_CIMMAND4;
TeaSendBuffer[4] = TEA_INIT_CIMMAND5;
}
//發送IIC起始信號
static void ComStart(void)
{
TEA_SDA_OUT(); //sda線輸出
TEA_SDA=1;
TEA_SCL=1;
DelayUs(5);
TEA_SDA=0;//START:when CLK is high,DATA change form high to low
DelayUs(5);
TEA_SCL=0;//鉗住I2C總線,准備發送或接收數據
}
//發送IIC停止信號
static void ComStop(void)
{
TEA_SDA_OUT();//sda線輸出
TEA_SDA=0;//STOP:when CLK is high DATA change form low to high
TEA_SCL=1;
DelayUs(5);
TEA_SDA=1;//發送I2C總線結束信號
DelayUs(5);
}
//等待ACK,為1代表無ACK 為0代表等到了ACK
static u8 ComWaitAck(void)
{
u8 waitTime = 0;
TEA_SDA_OUT();//sda線輸出
TEA_SDA = 1;
DelayUs(5);
TEA_SDA_IN(); //SDA設置為輸入
TEA_SCL=1;
DelayUs(5);
while(TEA_READ_SDA)
{
waitTime++;
DelayUs(1);
if(waitTime > TEA_ACK_WAIT_TIME)
{
ComStop();
return 1;
}
}
TEA_SCL = 0;
return 0;
}
static void ComSendAck(void)
{
TEA_SCL = 0;
TEA_SDA_OUT();
TEA_SDA = 0;
DelayUs(2);
TEA_SCL = 1;
DelayUs(5);
TEA_SCL = 0;
DelayUs(5);
}
static void ComSendNoAck(void)
{
TEA_SCL = 0;
TEA_SDA_OUT();
TEA_SDA = 1;
DelayUs(2);
TEA_SCL = 1;
DelayUs(5);
TEA_SCL = 0;
DelayUs(5);
}
//返回0 寫入收到ACK 返回1寫入未收到ACK
static u8 ComSendByte(u8 byte)
{
u8 t;
TEA_SDA_OUT();
for(t=0;t<8;t++)
{
TEA_SDA=(byte&0x80)>>7;
byte<<=1;
TEA_SCL=1;
DelayUs(5);
TEA_SCL=0;
DelayUs(5);
}
return ComWaitAck();
}
static void ComReadByte(u8* byte)
{
u8 i,receive=0;
TEA_SDA_IN();//SDA設置為輸入
for(i=0;i<8;i++ )
{
receive <<= 1;
TEA_SCL=1;
DelayUs(5);
if(TEA_READ_SDA)receive++;
TEA_SCL=0;
DelayUs(5);
}
*byte = receive;
}
/********************************************************************************************************/
u8 TeaWriteCommand(void)
{
u8 res = 0;
u8 i = 0;
ComStart();
res = ComSendByte(TEA5767ADDR_W);//發送地址
if(res)
{
#ifdef TEA_DEBUG
printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif
return res;
}
for(i = 0; i < 5; i++)
{
res = ComSendByte(TeaSendBuffer[i]);//發送命令數據
if(res)
{
#ifdef TEA_DEBUG
printf("file=%s ,func=%s ,line=%d \r\n",__FILE__,__FUNCTION__,__LINE__);
#endif
return res;
}
}
ComStop();
return 0;
}
//返回0成功 返回1失敗
u8 TeaReadStatus(void)
{
u8 res = 0;
u8 i = 0;
ComStart();
res = ComSendByte(TEA5767ADDR_R);//讀取地址
if(res)
{
#ifdef TEA_DEBUG
printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
#endif
return res;
}
for(i = 0; i < 5; i++)
{
ComReadByte(TeaReadBuffer+i);//發送命令數據
if(i == 4) ComSendNoAck();
else ComSendAck();
}
ComStop();
return 0;
}
//返回0成功 返回1失敗
u8 TeaInit(void)
{
TEAIoInit();
return TeaWriteCommand();
}
u32 TeaGetCurrentFreq(void)
{
u8 hlsi;
u32 pll = 0;
u32 freq = 0;
if(TeaReadStatus())return 0;
hlsi = TeaSendBuffer[2]&0x10; //HLSI位
pll = TeaReadBuffer[0]&0x3f;
pll<<=8;
pll += TeaReadBuffer[1];
if(hlsi)
{
freq = (pll*(F_RES/4)) - F_IF;
}
else
{
freq = (pll*(F_RES/4)) + F_IF;
}
return freq;
}
void TeaSetFreq(u32 freq)
{
u8 hlsi;
u32 pll = 0;
u8 pllH,pllL;
hlsi = TeaSendBuffer[2]&0x10; //HLSI位
if (hlsi)
pll=(unsigned int)((float)((freq+F_IF)*4)/(float)F_RES); //頻率單位:HZ
else
pll=(unsigned int)((float)((freq-F_IF)*4)/(float)F_RES); //頻率單位:HZ
pll &= 0x00003fff;
pllL = (u8)pll;
pllH = (u8)(pll>>8);//分別PLL
TeaSendBuffer[0] &= 0xc0;
TeaSendBuffer[0] |= pllH;
TeaSendBuffer[1] = pllL;//插入發送序列
TeaWriteCommand();//寫入芯片
}
//1向上搜索 0向下搜索
u32 TeaGetNextCh(u8 dir)
{
if(dir)TeaSendBuffer[2] |= 0x80;
else TeaSendBuffer[2] &= ~0x80;//確定方向
TeaSendBuffer[0] |= 0x40;//啟動搜索
DelayMs(50);
do
{
TeaReadStatus();
}while((TeaReadBuffer[0]&0x80) == 0);
//已經結束
if((TeaReadBuffer[0]&0x40) == 0)
{
//找到一個台
return TeaGetCurrentFreq();
}
else
{
return 0;
}
}
