51单片机+SI4713模块做带RDS信号的FM调频广播电台
·
买的模块例程都是Arduino的,没事,根本难不倒咱,原神启动!哦不对,千问启动!ai给代码再稍微改改,贴代码
#include <STC8051U.H>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long
// 51单片机I/O定义(根据你的硬件修改)
sbit SCL = P2^1;
sbit SDA = P2^0;
sbit RST = P2^2;
sbit R_LED=P0^0;//故障指示灯 低电平点亮
sbit G_LED=P0^1;//正常指示灯
// ================= 常量定义 =================
#define SI47XX_ADDR_WR 0xC6 // I2C 写地址 (SENB=1)
#define SI47XX_ADDR_RD 0xC7 // I2C 读地址 (SENB=1)
// 命令定义 (来自文档)
#define CMD_POWER_UP 0x01
#define CMD_GET_REV 0x10
#define CMD_TX_TUNE_FREQ 0x30
#define CMD_TX_TUNE_POWER 0x31
#define CMD_TX_RDS_PS 0x36
#define CMD_GET_INT_STATUS 0x14
void DelayMs(uint time) //@11.0592MHz
{
unsigned long edata i;
for(;time>0;time--)
{
_nop_();
_nop_();
i = 2763UL;
while (i) i--;
}
}
void DelayUs(uint time) //@11.0592MHz
{
unsigned long edata i;
for(;time>0;time--)
{
_nop_();
_nop_();
i = 1UL;
while (i) i--;
}
}
// ================= I2C 驱动 =================
void I2C_Start(void) {
SDA = 1; DelayUs(5);
SCL = 1; DelayUs(5);
SDA = 0; DelayUs(5);
SCL = 0;
}
void I2C_Stop(void) {
SDA = 0; DelayUs(5);
SCL = 1; DelayUs(5);
SDA = 1; DelayUs(5);
}
void I2C_SendByte(unsigned char dat) {
unsigned char i;
for (i = 0; i < 8; i++) {
SCL = 0;
SDA = (bit)(dat & 0x80);
DelayUs(5);
SCL = 1; DelayUs(5);
SCL = 0;
dat <<= 1;
}
}
unsigned char I2C_WaitAck(void) {
// unsigned char ack;
SCL = 1; DelayUs(5);
if (SDA) { SCL = 0; I2C_Stop(); return 1; } // 非应答
SCL = 0; DelayUs(5);
return 0; // 应答
}
unsigned char I2C_ReceiveByte(void) {
unsigned char i, dat = 0;
SDA = 1; // 释放总线
for (i = 0; i < 8; i++) {
DelayUs(5);
SCL = 1; DelayUs(5);
dat <<= 1;
if (SDA) dat |= 1;
SCL = 0;
}
return dat;
}
void I2C_SendAck(bit ack) {
SDA = ack; // 0为ACK, 1为NAK
DelayUs(5);
SCL = 1; DelayUs(5);
SCL = 0; DelayUs(5);
}
// ================= Si47xx 驱动函数 =================
void Si47xx_Reset(void) {
RST = 0;
DelayMs(10);
RST = 1;
DelayMs(10);
}
// 写命令函数
bit Si47xx_Write_Cmd(unsigned char cmd_len, unsigned char *cmd_buf) {
unsigned char i;
I2C_Start();
I2C_SendByte(SI47XX_ADDR_WR);
if (I2C_WaitAck()) return 1;
for (i = 0; i < cmd_len; i++) {
I2C_SendByte(cmd_buf[i]);
if (I2C_WaitAck()) return 1;
}
I2C_Stop();
return 0;
}
// 读响应函数 (简化版,读取固定长度)
bit Si47xx_Read_Response(unsigned char byte_cnt, unsigned char *data_buf) {
unsigned char i;
I2C_Start();
I2C_SendByte(SI47XX_ADDR_RD);
if (I2C_WaitAck()) return 1;
for (i = 0; i < byte_cnt; i++) {
data_buf[i] = I2C_ReceiveByte();
I2C_SendAck((i == (byte_cnt - 1))); // 最后一个字节发NAK
}
I2C_Stop();
return 0;
}
// 等待芯片就绪 (CTS)
bit Si47xx_Wait_CTS(void) {
unsigned char status;
unsigned char timeout = 100;
do {
I2C_Start();
I2C_SendByte(SI47XX_ADDR_RD);
if (I2C_WaitAck()) return 1;
status = I2C_ReceiveByte();
I2C_SendAck(1); // NAK
I2C_Stop();
DelayMs(10);
timeout--;
} while (((status & 0x80) == 0) && timeout); // 检查 CTS 位
return (timeout ? 0 : 1);
}
// ================= 功能函数 =================
// 初始化 Si47xx
bit Si47xx_Init(void) {
// unsigned char rev_data[9];
// 1. Power Up 命令:0x01 (Cmd), 0x42 (Tx Mode), 0x00 (Analog Input)
// 如果你的板子是数字输入,请改回 0x50
unsigned char power_up_cmd[] = {CMD_POWER_UP, 0x42, 0x00};
// 2. 关键配置属性 (Properties)
// Property ID: 0x12 0x00 (SET_PROPERTY 命令)
// Argument: 0x21 0x00 (Property Number, 低字节在前)
// Value: 0x00 0x00 (Property Value)
// A. 设置预加重 (0x2106): 0x0001 = 50us (Europe), 0x0000 = 75us (US/China)
// 建议设为 0 (75us)
unsigned char prop_pre[] = {0x12, 0x00, 0x06, 0x21, 0x00, 0x00};
// B. 设置模拟输入电平 (0x2104): 告诉芯片输入信号的最大峰值
// 默认是 636mV (0x327C),如果你的音频信号较小,可以设为 0x0FA0 (400mV)
// 这里先设为默认值
unsigned char prop_level[] = {0x12, 0x00, 0x04, 0x21, 0x32, 0x7C};
// C. 解除静音 (0x2105): 确保左右声道都不静音
unsigned char prop_mute[] = {0x12, 0x00, 0x05, 0x21, 0x00, 0x00};
// 配置外部参考时钟频率为 32768 Hz (0x8000)
// 命令: 0x12 (SET_PROPERTY)
// 参数: 0x00 0x02 (Property ID: 0x0200 -> REFCLK_FREQ)
// 值: 0x00 0x00 0x80 0x00 (32768 Hz 的十六进制,高位在前)
unsigned char cmd_refclk[] = {0x12, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00};
Si47xx_Reset();
// 严格的上电时序
DelayMs(10); // RST 拉低后的保持时间
// 发送 Power Up
if (Si47xx_Write_Cmd(3, power_up_cmd)) return 1;
if (Si47xx_Wait_CTS()) return 1;
// 关键延时!必须等待芯片内部 PLL 锁定
DelayMs(150); // 必须大于 110ms,保险起见设为 150ms
// 设置属性
if (Si47xx_Write_Cmd(6, prop_pre)) return 1;
if (Si47xx_Wait_CTS()) return 1;
if (Si47xx_Write_Cmd(6, prop_level)) return 1;
if (Si47xx_Wait_CTS()) return 1;
if (Si47xx_Write_Cmd(6, prop_mute)) return 1;
if (Si47xx_Wait_CTS()) return 1;
Si47xx_Write_Cmd(8, cmd_refclk);//设置晶振频率
if (Si47xx_Wait_CTS()) return 1;
return 0; // 成功
}
// 设置发射频率
bit Si47xx_Set_Freq(unsigned int freq_khz) {
// freq_khz 例如: 9810 表示 98.10 MHz
unsigned char cmd[4];
cmd[0] = CMD_TX_TUNE_FREQ;
cmd[1] = 0x00;
cmd[2] = (unsigned char)(freq_khz >> 8);
cmd[3] = (unsigned char)(freq_khz & 0xFF);
if (Si47xx_Write_Cmd(4, cmd)) return 1;
if (Si47xx_Wait_CTS()) return 1;
return 0;
}
// 设置发射功率
bit Si47xx_Set_Power(unsigned char power_dbuv) {
// 建议值: 88 ~ 115 dBuV
unsigned char cmd[5];
cmd[0] = CMD_TX_TUNE_POWER;
cmd[1] = 0x00;
cmd[2] = 0x00; // MSB
cmd[3] = power_dbuv; // LSB
cmd[4] = 0x00;
if (Si47xx_Write_Cmd(5, cmd)) return 1;
if (Si47xx_Wait_CTS()) return 1;
return 0;
}
// 发送 RDS PS (节目服务名,最多8个字符)
bit Si47xx_Send_RDS_PS(unsigned char *str) {
unsigned char cmd[6];
unsigned char i;
// 填充命令: CMD(1) + PS_ID(1) + 4个字符
cmd[0] = CMD_TX_RDS_PS;
cmd[1] = 0x00; // PS ID 0
// 填充字符串 (最多4个字符)
for (i = 0; i < 4; i++) {
if (str[i] == '\0') break;
cmd[i+2] = str[i];
}
// 如果不足4个字符,补空格或保持原样
if (Si47xx_Write_Cmd(6, cmd)) return 1;
if (Si47xx_Wait_CTS()) return 1;
return 0;
}
void main ()
{
// uchar i;
WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P0M0=0X00;P0M1=0X00;P1M0=0X00;P1M1=0X00;
P2M0=0X00;P2M1=0X00;P3M0=0X00;P3M1=0X00;
P4M0=0X20;P4M1=0X00;P5M0=0X00;P5M1=0X00;
// Si47xx_Reset();
DelayMs(500);
// 核心初始化流程
while (Si47xx_Init()) {
// 初始化失败,闪烁LED或重试
R_LED=!R_LED;
DelayMs(500);
}
// 配置发射参数
while(Si47xx_Set_Power(115)) // 配置功率
{
R_LED=!R_LED;
DelayMs(500);
}
while(Si47xx_Set_Freq(8810)) // 88.1 MHz
{
R_LED=!R_LED;
DelayMs(500);
}
// 发送 RDS 信息
while(Si47xx_Send_RDS_PS("51MCU"))
{
R_LED=!R_LED;
DelayMs(500);
}
R_LED=1;
G_LED=0;
while(1)
{
/* while(Si47xx_Send_RDS_PS("51 CSDN"))// 循环发送 RDS 信息
{
R_LED=!R_LED;
DelayMs(500);
}
DelayMs(500);
R_LED=1;
G_LED=0;*/
//摆烂吧 累了
}
}
基于STC的AI8051型号编写,用其他型号单片机记得稍微改延时函数啥的。单片机只需接模块的RST,SCLK,SDA接口

下面开始调试硬件,无论死活调不出信号。SDR软件接收机无法接收到信号。最后注意力落在晶振身上,模块本身用的32.768k无源晶振。用示波器测量无波形输出。通过检查硬件发现这个模块的晶振负载电容一个角没有接地。可能是抄板的没注意,网上卖有两种版本的,紫色的这种是抄板的,蓝色板的应该是原创,蓝色的负载电容那里有一根接线。后来就算将负载电容这里接地,晶振依然无法起振,可能负载电容不匹配。没事,都是小问题。这种小晶振不起振,我见的多了,直接上有源晶振,通过焊接+粘胶信号出来了。





接收信号贴图


此代码是简化的功能代码,RDS信号还没有调,不知是否正确,以后再调,想稳定工作的话,可以在while循环里加上时刻检测模块寄存器当前状态。发射调试请遵守无线电管理条例。
更多推荐
所有评论(0)