买的模块例程都是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循环里加上时刻检测模块寄存器当前状态。发射调试请遵守无线电管理条例。

 

更多推荐