物联网loT从业者物联网相关技术研究

STM32F103学习笔记(2)——收音机模块TEA5767使用

2020-06-23  本文已影响0人  Leung_ManWah

一、简介

TEA5767是由菲利普公司推出的一款低功耗立体声收音机接收器芯片。频率范围从76-108MHz自动数字调谐。高灵敏度,高稳定性,低噪音,收音模块。一片低功耗电调谐调频立体声收音机电路,其内部集成了中频选频和解调网络,可以做到完全免调。

  • 电源 5V
  • I2C 总线通讯
  • 可以使用软件进行静音和消除噪音

二、硬件连接

功能口 引脚
SCL PB.6
SDA PB.5

三、添加I2C驱动

查看 STM32F103学习笔记(1)——FreeRTOS下模拟I2C

四、移植文件

注意:以下出现缺失common.h文件错误,去除即可。uint8改为uint8_t或unsigned char或自己宏定义
链接:https://pan.baidu.com/s/1KlliOYSGgdlYcb5J52Twrw 提取码:xp0z
board_i2c.cboard_i2c.hboard_tea5767.cboard_tea5767.h 四个文件加入到工程

4.1 board_tea5767.c

/*********************************************************************
 * INCLUDES
 */
#include "stdlib.h"
#include "stm32f10x.h"

#include "board_i2c.h" 
#include "board_tea5767.h" 
#include "common.h"

/*********************************************************************
 * GLOBAL VARIABLES
 */
unsigned long g_frequency = TEA5767_MIN_KHZ;

/*********************************************************************
 * LOCAL VARIABLES
 */                                     
static uint8 s_radioWriteData[5] = {0x31,0xA0,0x20,0x11,0x00};          // 要写入TEA5767的数据,默认存台的PLL,104.3MHz
static uint8 s_radioReadData[5] = {0};                                  // TEA5767读出的状态
static uint32 s_pll = 0;

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief 向TEA5767写入5个字节数据
 @param 无
 @return 无
*/
void TEA5767_Write(void)
{       
    uint8 i;
    
    IIC_Start();                                                        // 发送起始信号
    IIC_SendByte(TEA5767_ADDR_W);                                       // TEA5767写地址
    IIC_WaitAck();                                                      // 等待应答
    for(i = 0; i < 5; i++)
    {
        IIC_SendByte(s_radioWriteData[i]);                              // 连续写入5个字节数据
        IIC_Ack();                                                      // 发送应答
    }
    IIC_Stop();                                                         // 发送停止信号   
}

/**
 @brief 读TEA5767状态
 @param 无
 @return 无
*/
void TEA5767_Read(void)
{
    uint8 i;
    uint8 tempLow;
    uint8 tempHigh;
    s_pll = 0;
    
    IIC_Start();
    IIC_SendByte(TEA5767_ADDR_R);                                       // TEA5767读地址
    IIC_WaitAck();
    for(i = 0; i < 5; i++)                                              // 读取5个字节数据
    {
        s_radioReadData[i] = IIC_ReadByte();                            // 读取数据后,发送应答
    }
    IIC_Stop();
    tempLow = s_radioReadData[1];                                       // 得到s_pll低8位 
    tempHigh = s_radioReadData[0];                                      // 得到s_pll高6位
    tempHigh &= 0x3f;
    s_pll = tempHigh * 256 + tempLow;                                   // PLL值 
}

/**
 @brief 由频率计算PLL
 @param 无
 @return 无
*/
void TEA5767_GetPLL(void)
{
    uint8 hlsi;
    hlsi = s_radioWriteData[2] & 0x10;                                  // HLSI位
    if(hlsi)
    {
        s_pll = (uint32)((float)((g_frequency+225)*4)/(float)32.768);   // 频率单位:k
    }
    else
    {
        s_pll = (uint32)((float)((g_frequency-225)*4)/(float)32.768);   // 频率单位:k
    }
}

/**
 @brief 设置频率
 @param frequency -[in] 频率,单位:KHz
 @return 无
*/
void TEA5767_SetFrequency(uint32 frequency)
{
    g_frequency = frequency;
    TEA5767_GetPLL();
    s_radioWriteData[0] = s_pll / 256;
    s_radioWriteData[1] = s_pll % 256;
    s_radioWriteData[2] = 0x20;
    s_radioWriteData[3] = 0x11;
    s_radioWriteData[4] = 0x00;
    
    TEA5767_Write();
}

/**
 @brief 由PLL计算频率
 @param 无
 @return 无
*/
uint32 TEA5767_GetFrequency(void)
{
    uint8 hlsi;
    uint32 pll = 0;
    pll = s_pll;
    hlsi = s_radioWriteData[2] & 0x10;
    if(hlsi)
    {
        g_frequency = (unsigned long)((float)(pll)*(float)8.192-225);   // 频率单位:KHz
    }
    else
    {
        g_frequency = (unsigned long)((float)(pll)*(float)8.192+225);   // 频率单位:KHz
    }
    
    return g_frequency;
}

/**
 @brief 手动搜索电台,不用考虑TEA5767用于搜台的相关位:SM,SUD
 @param mode -[in] 搜索方式,mode=1,向上搜索,频率值+0.1MHz;mode=0,向下搜索,频率值-0.1MHz
 @return 无
*/
void TEA5767_Search(uint8 mode)
{
    TEA5767_Read();                                                     // 读取当前频率值 
    if(mode)                                                            // 向上搜索
    {
        g_frequency += 100;
        if(g_frequency > TEA5767_MAX_KHZ)                               // 频率达到最大值
        {
            g_frequency = TEA5767_MIN_KHZ;
        }
    }
    else
    {
        g_frequency -= 100;
        if(g_frequency < TEA5767_MIN_KHZ)
        {
            g_frequency = TEA5767_MAX_KHZ;
        }
    }          
    TEA5767_GetPLL();                                                   // 计算PLL值
    s_radioWriteData[0] = s_pll / 256;
    s_radioWriteData[1] = s_pll % 256;
    s_radioWriteData[2] = 0x20;
    s_radioWriteData[3] = 0x11;
    s_radioWriteData[4] = 0x00;
    TEA5767_Write();
    TEA5767_Read();
    if(s_radioReadData[0] & 0x80)                                       // 搜台成功,RF=1,可保存其频率值待用
    {
        printf(" frequency=%d\n", (int)g_frequency);
    }    
}

/**
 @brief 自动搜索电台
 @param mode -[in] 搜索方式,mode=1,频率增加搜台,频率值+0.1MHz;mode=0,频率减小搜台
 @return 无
*/
void TEA5767_AutoSearch(uint8 mode)
{
    uint8 radioRf = 0;                                                  // 1=发现一个电台,0=未找到电台
    uint8 radioIf = 0;                                                  // 中频计数结果
    uint8 radioLev = 0;                                                 // 信号电平ADC输出
    
    // 直到搜台成功,RF=1,0x31<IF<0x3E
    while((radioRf==0) || ((0x31>=radioIf)||(radioIf>=0x3E)))
    {
        if(mode)                                                        // 频率增加搜台
        {
            s_radioWriteData[2] = 0xC0;                                 // SUD=1,SSLadc=7,HLSI=0
            g_frequency += 100;
            if(g_frequency > TEA5767_MAX_KHZ)                           // 频率达到最大值
            {
                g_frequency = TEA5767_MIN_KHZ;
            }
        }
        else                                                            // 频率减小搜台
        {
            s_radioWriteData[2] = 0x40;                                 // SUD=0,SSLadc=7,HLSI=0
            g_frequency -= 100;
            if(g_frequency < TEA5767_MIN_KHZ)
            {
                g_frequency = TEA5767_MAX_KHZ;
            }           
        }
        TEA5767_GetPLL();                                               // 转换为PLL值
        s_radioWriteData[0] = s_pll / 256 + 0xC0;                       // MUTE=1,SM=1
        s_radioWriteData[1] = s_pll % 256;
        s_radioWriteData[3] = 0x11;
        s_radioWriteData[4] = 0x00;
        TEA5767_Write();                                                // 写入5个字节数据
        TEA5767_Read();                                                 // 读取当前频率值 
        radioRf = s_radioReadData[0] & 0x80;
        radioIf = s_radioReadData[2] & 0x7F;
        radioLev = s_radioReadData[3] >> 4;
        printf(" r=%02x\n", radioRf);
        printf(" i=%02x\n", radioIf);
        printf(" l=%d\n", radioLev);
        printf(" f=%d\n", (int)g_frequency);
    }
    TEA5767_GetPLL();                                                   // 转换为PLL值
    s_radioWriteData[0] = s_pll / 256;                                  // MUTE=0,SM=0
    s_radioWriteData[1] = s_pll % 256;
    s_radioWriteData[3] = 0x11;
    s_radioWriteData[4] = 0x00;
    TEA5767_Write();                                                    // 写入5个字节数据
    TEA5767_Read();                                                     // 读取当前频率值 
    printf(" frequency=%d\n", (int)g_frequency);
}

/**
 @brief 静音
 @param mode -[in] 静音方式,mode=1,静音;mode=0,非静音
 @return 无
*/
void TEA5767_Mute(uint8 mode)
{       
    if(mode == TEA5767_MUTE_ON)
    {
        s_radioWriteData[0] = s_radioWriteData[0] | 0x80;
    }
    else
    {
        s_radioWriteData[0] = s_radioWriteData[0] & 0x7F;
    }
    
    TEA5767_Write();
}

/****************************************************END OF FILE****************************************************/

4.2 board_tea5767.h

#ifndef _BOARD_TEA5767_H_
#define _BOARD_TEA5767_H_

/*********************************************************************
 * INCLUDES
 */
#include "stm32f10x.h"

#include "common.h"

/*********************************************************************
 * DEFINITIONS
 */
#define TEA5767_ADDR_W      0xc0    // TEA5767 写地址
#define TEA5767_ADDR_R      0xc1    // TEA5767 读地址

#define TEA5767_MAX_KHZ     108000  // 最高频率 108M
#define TEA5767_MIN_KHZ     87500   // 最低频率 87.5M

#define TEA5767_MUTE_ON     1       // 非静音
#define TEA5767_MUTE_OFF    0       // 静音

#define TEA5767_SEARCH_UP   1       // 向上搜索
#define TEA5767_SEARCH_DOWN 0       // 向下搜索

/*********************************************************************
 * GLOBAL VARIABLES
 */
extern unsigned long g_frequency;

/*********************************************************************
 * API FUNCTIONS
 */
void TEA5767_Write(void);
void TEA5767_Read(void);
void TEA5767_GetPLL(void);
void TEA5767_SetFrequency(uint32 frequency);
uint32 TEA5767_GetFrequency(void);
void TEA5767_Search(uint8 mode);
void TEA5767_AutoSearch(uint8 mode);
void TEA5767_Mute(uint8 mode);

#endif /* _BOARD_TEA5767_H_ */

五、API调用

需包含头文件 board_tea5767.h

TEA5767_Write

功能 向TEA5767写入5个字节数据
函数定义 void TEA5767_Write(void)
参数
返回

TEA5767_Read

功能 读TEA5767状态
函数定义 void TEA5767_Read(void)
参数
返回

TEA5767_GetPLL

功能 由频率计算PLL
函数定义 void TEA5767_GetPLL(void)
参数
返回

TEA5767_SetFrequency

功能 设置频率
函数定义 void TEA5767_SetFrequency(uint32 frequency)
参数 frequency:频率,单位:KHz
返回

TEA5767_GetFrequency

功能 由PLL计算频率
函数定义 uint32 TEA5767_GetFrequency(void)
参数
返回 当前频率

TEA5767_Search

功能 手动搜索电台,不用考虑TEA5767用于搜台的相关位:SM,SUD
函数定义 void TEA5767_Search(uint8 mode)
参数 mode:搜索方式,mode=1,向上搜索,频率值+0.1MHz;mode=0,向下搜索,频率值-0.1MHz
返回

TEA5767_AutoSearch

功能 自动搜索电台
函数定义 void TEA5767_AutoSearch(uint8 mode)
参数 mode:搜索方式,mode=1,向上搜索,频率值+0.1MHz;mode=0,向下搜索,频率值-0.1MHz
返回

TEA5767_Mute

功能 静音
函数定义 void TEA5767_Mute(uint8 mode)
参数 mode:静音方式,mode=1,静音;mode=0,非静音
返回

六、使用例子

6.1 手动加减台

+-0.1MHz,87.5-108MHz,循环增减

TEA5767_Search(1);  // 加台
TEA5767_Search(0);  // 减台

6.2 自动搜台

由于从IC中读回的频率不准,这里采用静态变量g_frequency来记录当前频率,87.5-108MHz,循环增减

TEA5767_AutoSearch(1);  // 向上搜台
TEA5767_AutoSearch(0);  // 向下搜台

参考自动搜台流程:


由上面流程可知,决定参数有

void TEA5767_AutoSearch(uint8 mode)
{
    uint8 radioRf = 0;                                                  // 1=发现一个电台,0=未找到电台
    uint8 radioIf = 0;                                                  // 中频计数结果
    uint8 radioLev = 0;                                                 // 信号电平ADC输出
    
    // 直到搜台成功,RF=1,0x31<IF<0x3E
    while((radioRf==0) || ((0x31>=radioIf)||(radioIf>=0x3E)))
    {
        if(mode)                                                        // 频率增加搜台
        {
            s_radioWriteData[2] = 0xC0;                                 // SUD=1,SSLadc=7,HLSI=0
            g_frequency += 100;
            if(g_frequency > TEA5767_MAX_KHZ)                           // 频率达到最大值
            {
                g_frequency = TEA5767_MIN_KHZ;
            }
        }
        else                                                            // 频率减小搜台
        {
            s_radioWriteData[2] = 0x40;                                 // SUD=0,SSLadc=7,HLSI=0
            g_frequency -= 100;
            if(g_frequency < TEA5767_MIN_KHZ)
            {
                g_frequency = TEA5767_MAX_KHZ;
            }           
        }
        TEA5767_GetPLL();                                               // 转换为PLL值
        s_radioWriteData[0] = s_pll / 256 + 0xC0;                       // MUTE=1,SM=1
        s_radioWriteData[1] = s_pll % 256;
        s_radioWriteData[3] = 0x11;
        s_radioWriteData[4] = 0x00;
        TEA5767_Write();                                                // 写入5个字节数据
        TEA5767_Read();                                                 // 读取当前频率值 
        radioRf = s_radioReadData[0] & 0x80;
        radioIf = s_radioReadData[2] & 0x7F;
        radioLev = s_radioReadData[3] >> 4;
        printf(" r=%02x\n", radioRf);
        printf(" i=%02x\n", radioIf);
        printf(" l=%d\n", radioLev);
        printf(" f=%d\n", (int)g_frequency);
    }
    TEA5767_GetPLL();                                                   // 转换为PLL值
    s_radioWriteData[0] = s_pll / 256;                                  // MUTE=0,SM=0
    s_radioWriteData[1] = s_pll % 256;
    s_radioWriteData[3] = 0x11;
    s_radioWriteData[4] = 0x00;
    TEA5767_Write();                                                    // 写入5个字节数据
    TEA5767_Read();                                                     // 读取当前频率值 
    printf(" frequency=%d\n", (int)g_frequency);
}

6.3 软件静音

TEA5767_Mute(TEA5767_MUTE_ON);      // 收音机静音
TEA5767_Mute(TEA5767_MUTE_OFF);         // 收音机开启收听

七、附录

7.1 写数据

向TEA5767 写入数据时,地址的最低位是0,即写地址是C0。读出数据时地址的最低位是1,即读地址是C1。TEA5767的控制寄存器要写入5个字节,每次写入数据时必须严格按照下列顺序进行:
地址、字节1、字节2、字节3、字节4、字节5。

每个字节的最高位首先发送。在时钟的下降沿后写入的数据生效。上电复位后,设置为静音,所有其它位均被置低,必须写入控制字初始化芯片。

TEA5767内部有一个5个字节的控制寄存器,在IC上电复位后必须通过总线接口向其中写入适当的控制字,它才能够正常工作。每个数据字节各位的功能含义见表4到表14。

表4 数据字节1的格式

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
MUTE SM PLL13 PLL12 PLL11 PLL10 PLL9 PLL8

表5 数据字节1各位的说明

BIT SYMBOL 说明
7 MUTE 若MUTE=1 左右声道静音;若 MUTE=0 左右声道非静音
6 SM 搜索模式;若SM=1 搜索模式;若 SM=0 非搜索模式
5 to 0 PLL(13:8) 预置或搜索电台的频率数据高6位

表6 数据字节2的格式

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
PLL7 PLL6 PLL5 PLL4 PLL3 PLL2 PLL1 PLL0

表7 数据字节2各位的说明

BIT SYMBOL 说明
7 to 0 PLL(7:0) 预置或搜索电台的频率数据低8位

表8 数据字节3的格式

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
SUD SSL1 SSL0 HLSI MS ML MR SWP1

表9 数据字节3各位的说明

BIT SYMBOL 说明
7 SUD 若 SUD=1 向上搜索;
若 SUD=0 向下搜索
6 and 5 SSL[1:0] 搜索停止电平:见表10-11
4 HLSI 若 HLSI=1 高端本振注入;
若 HLSI=0 低端本振注入
3 MS 若 MS=1 强制单声道;
若 MS=0 开立体声
2 ML 若 ML=1 左声道静音强制单声道;
若 ML=0 左声道非静音
1 MR 若 MR=1 右声道静音强制单声道;
若 MR=0 右声道非静音
0 SWP1 软件可编程输出口1:若 SWP1=1 SWPOR1为高;
若 SWP1=0 SWPOR1为低

表10 搜索停止电平设定

SSL1 SSL0 搜索停止电平
0 0 不搜索
0 1 低电平 ADC output=5
1 0 中电平ADC output=7
1 1 高电平ADC output=10

表11 数据字节4的格式

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
SWP2 STBY BL XTAL SMUTE HCC SNC SI

表12 数据字节4各位的说明

BIT SYMBOL 说明
7 SWP2 软件可编程输出口2:若 SWP2=1 口2为高;
若 SWP2=0口2为低
6 STBY 若 STBY=1 待机模式;
若 STBY=0 非待机模式
5 BL 若 BL=1 日本FM波段;
若 BL=0 美/欧 FM 波段
4 XTAL 若 XTAL=1 fxtal=32.768KHz;
若 XTAL=0 fxtal=13MHz
3 SMUTE 若SMUTE=1 软件静音开;
若 MUTE=0 软件静音关
2 HCC 若 HCC=1高音切割开;
若 HCC=0高音切割关
1 SNC 若 SNC =1立体声噪声消除开;
若 SNC=0立体声噪声消除关
0 SI 若SI=1 引脚SWPORT1 作ready flag输出标志;
若 SI=0 引脚SWOPRT1 作软件可编程输出口

表13 数据字节5的格式

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
PLLREF DTC - - - - - -

表14 数据字节5各位的说明

BIT SYMBOL 说明
7 PLLREF 若 PLLREF=1 则6.5 MHz 参考频率 PLL可用;
若 PLLREF=0 则6.5 MHz参考频率 PLL不可用
6 DTC 若DTC=1 the 去加重时间常数为75μs;
若 DTC=0 the 去加重时间常数为50μs
5 to 0 - 不用管它

7.2 读数据

和写数据类似,从TEA5767 读出数据时,也要按照“地址、字节1、字节2、字节3、字节4、字节5”这样的顺序读出,读地址是C1。读出的5个字节的含义见表16到表25中的说明。

表15 读模式

数据字节1 数据字节2 数据字节3 数据字节4 数据字节5

表16 数据字节1的格式

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
RF BLF PLL13 PLL12 PLL11 PLL10 PLL9 PLL8

表17 数据字节1各位的说明

BIT SYMBOL 说明
7 RF 若RF=1 则发现了一个电台或搜索到头;
若 RF=0 未找到电台
6 BLF 若BLF=1 搜索到头;
若 BLF=0 未搜索到头
5 to 0 PLL[13:8] 搜索或预置的电台频率值的高6位

表18 数据字节2的格式

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
PLL7 PLL6 PLL5 PLL4 PLL3 PLL2 PLL1 PLL0

表19 数据字节2各位的说明

BIT SYMBOL 说明
7 to 0 PLL(7:0) 预置或搜索电台的频率数据低8位

表20 数据字节3的格式

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
STEREO IF6 IF5 IF4 IF3 IF2 IF1 IF0

表21 数据字节3各位的说明

BIT SYMBOL 说明
7 STEREO 若 STEREO=1 为立体声;
若 STEREO=0 为单声道
6 to 0 IF[6:0] 中频计数结果

表22 数据字节4的格式

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
LEV3 LEV2 LEV1 LEV0 CI3 CI2 CI1 CI0

表23 数据字节4各位的说明

BIT SYMBOL 说明
7 to 4 LEV[3:0] 信号电平ADC 输出
3 to 1 CI[3:1] 芯片标记; 设置为0
0 - 该位为 0

表24 数据字节5的格式

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
0 0 0 0 0 0 0 0

表25 数据字节5各位的说明

BIT SYMBOL 说明
7 to 0 - 供以后备用的字节;设置为0

7.3 举例

根据上面的算法,以106.8的天津交通台为例,它的PLL为32d1H,第一个字节的BIT7=0非静音,BIT6=0不搜索,第三个字节的BIT4=0低本振,第四个字节的BIT5=0欧美制式,BIT4=1用32768晶振,其余位的设置无所谓,可任意。各字节值见表27~31。

表27字节1:0x32

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
MUTE SM PLL13 PLL12 PLL11 PLL10 PLL9 PLL8
0 0 1 1 0 0 1 0
非静音 非搜索 3 2

表28字节2:0xd1

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
PLL7 PLL6 PLL5 PLL4 PLL3 PLL2 PLL1 PLL0
1 1 0 1 0 0 0 1
d 1

表29字节3:0xc0

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
SUD SSL1 SSL0 HLSI MS ML MR SWP1
1 1 0 0 0 0 0 0
向上搜索 搜索停止中电平 低本振 立体声 非静音 随便

表30字节4:0x17

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
SWP2 STBY BL XTAL SMUTE HCC SNC SI
0 0 0 1 0 1 1 1
任意(不用) 非待机 欧美 32.768 非软件静音 高音切割 除噪声 SWP1=RF

表31字节5:0x00

BIT7(MSB) BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0(LSB)
PLLREF DTC - - - - - -
0 0 0 0 0 0 0 0
不用6.5M 50μs

据此给出的控制字是:0x32,0xd1,0xC0,0x17,0x00,将这个控制字写入TEA5767就可以了。


• 由 Leung 写于 2020 年 6 月 23 日

• 参考:STM32驱动TEA5767收音机模块
    TEA5767收音模块介绍

上一篇下一篇

猜你喜欢

热点阅读