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; } }