STM32驱动TEA5767收音机模块

时间:2024-03-05 16:53:24

Tea5767是飞利浦公司出的一款集成化的收音机芯片,大四的时候机缘巧合遇到了这个芯片,用了一下,写点资料

 

主要特性

TEA5767HN是一款低功耗立体声收音IC,广泛应用于手机MP3 MP 4 播放器等便携系统接收频率 76 MHz 108MHz ( 日本/美国/欧洲频段选择) ,中频频率 225kHz采用锁相环调谐系统,带AG C电路,并可以使用软件进行静音和消除噪音。主要电性能指标工作电压2.5 V5.0 V工作电流10 m A灵敏度1 5 V,立体声分离度30dB,信噪比 6 0 d B输出信号电平7 5mV 。总线通信界面i 2 C3 线总线可选,具有 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×98000000225000))/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;
	}
}