本章主要讲解iic通信下串口改变占空比和频率
单独拿出来讲解的主要原因是,关于寄存器的配置。
在上一章节的实验当中,我们借助工具配置了9mhz的输出.h文件,但是现在要改变频率,就需要对具体的几个寄存器的值进行输入/改变。这也是最复杂的地方
1.经过查找我们可以得到
2.代码部分
1)(交给ai生成关于写入寄存器的内容)
c
// I2C 句柄(假设你用的是 I2C1)
extern I2C_HandleTypeDef hi2c2;
#include "Si5351A.h"
// Si5351 的 I2C 7位从机地址
#define SI5351_DEV_ADDR_WRITE (0x60 << 1) // 0xC0
//计算并修改CLK输出频率
#include <stdint.h>
#include <stdbool.h>
// ============================================================
// 配置常量
// ============================================================
#define SI5351_XTAL_FREQ 27000000UL // 晶振频率(Hz),根据实际修改
// ============================================================
// 底层 I2C 读写函数
// ============================================================
void Si5351_Write_Reg(uint8_t reg, uint8_t value)
{
uint8_t tx_buffer[2];
tx_buffer[0] = reg;
tx_buffer[1] = value;
HAL_I2C_Master_Transmit(&hi2c2, SI5351_DEV_ADDR_WRITE, tx_buffer, 2, 100);
}
uint8_t Si5351_Read_Reg(uint8_t reg)
{
uint8_t value = 0;
HAL_I2C_Mem_Read(&hi2c2, SI5351_DEV_ADDR_WRITE, reg, I2C_MEMADD_SIZE_8BIT, &value, 1, 100);
return value;
}
// ============================================================
// 批量写入配置表
// ============================================================
#define SI5351_REGS_COUNT (sizeof(si5351a_revb_registers) / sizeof(si5351a_revb_registers[0]))
HAL_StatusTypeDef Si5351_WriteConfig(void)
{
uint16_t i;
HAL_StatusTypeDef status;
uint8_t tx_buffer[2];
for (i = 0; i < SI5351_REGS_COUNT; i++) {
tx_buffer[0] = (uint8_t)(si5351a_revb_registers[i].address & 0xFF);
tx_buffer[1] = si5351a_revb_registers[i].value;
status = HAL_I2C_Master_Transmit(&hi2c2, SI5351_DEV_ADDR_WRITE, tx_buffer, 2, 100);
if (status != HAL_OK) {
return status;
}
}
return HAL_OK;
}
// ============================================================
// 读取单个寄存器(带返回值)
// ============================================================
HAL_StatusTypeDef Si5351_ReadReg(uint8_t reg, uint8_t *value)
{
return HAL_I2C_Mem_Read(&hi2c2, SI5351_DEV_ADDR_WRITE, reg, I2C_MEMADD_SIZE_8BIT, value, 1, 100);
}
// ============================================================
// 计算分频器 P1/P2/P3
// ============================================================
static void Si5351_Calc_Params(uint32_t a, uint32_t b, uint32_t c,
uint32_t *P1, uint32_t *P2, uint32_t *P3)
{
if (b == 0) {
*P3 = 1;
*P2 = 0;
*P1 = 128 * a - 512;
} else {
*P3 = c;
*P2 = 128 * b - c * ((128 * b) / c);
*P1 = 128 * a + ((128 * b) / c) - 512;
}
}
// ============================================================
// 配置 PLLA(寄存器 26~33)
// ============================================================
static void Si5351_Config_PLLA(uint32_t pll_freq)
{
uint32_t a, b, c;
uint32_t P1, P2, P3;
uint64_t temp;
temp = (uint64_t)pll_freq * 1000000ULL / SI5351_XTAL_FREQ;
a = (uint32_t)(temp / 1000000);
b = (uint32_t)(temp % 1000000);
c = 1000000;
if (a < 15) { a = 15; b = 0; }
if (a > 90) { a = 90; b = 0; }
Si5351_Calc_Params(a, b, c, &P1, &P2, &P3);
Si5351_Write_Reg(26, (P3 >> 8) & 0xFF);
Si5351_Write_Reg(27, P3 & 0xFF);
uint8_t reg28 = Si5351_Read_Reg(28) & 0xFC;
reg28 |= (P1 >> 16) & 0x03;
Si5351_Write_Reg(28, reg28);
Si5351_Write_Reg(29, (P1 >> 8) & 0xFF);
Si5351_Write_Reg(30, P1 & 0xFF);
uint8_t reg31 = ((P3 >> 16) & 0x0F) << 4 | ((P2 >> 16) & 0x0F);
Si5351_Write_Reg(31, reg31);
Si5351_Write_Reg(32, (P2 >> 8) & 0xFF);
Si5351_Write_Reg(33, P2 & 0xFF);
}
// ============================================================
// 配置 CLK0 输出分频器(寄存器 42~49)
// ============================================================
static void Si5351_Config_CLK0(uint32_t pll_freq, uint32_t output_freq, uint8_t r_div)
{
uint32_t a, b, c;
uint32_t P1, P2, P3;
uint64_t temp;
uint8_t reg_val;
temp = (uint64_t)pll_freq * 1000000ULL / ((uint64_t)output_freq * (1 << r_div));
a = (uint32_t)(temp / 1000000);
b = (uint32_t)(temp % 1000000);
c = 1000000;
if (a < 6) { a = 6; b = 0; }
if (a > 900) { a = 900; b = 0; }
Si5351_Calc_Params(a, b, c, &P1, &P2, &P3);
Si5351_Write_Reg(42, (P3 >> 8) & 0xFF);
Si5351_Write_Reg(43, P3 & 0xFF);
reg_val = (r_div << 5) & 0xE0;
reg_val |= (P1 >> 16) & 0x03;
Si5351_Write_Reg(44, reg_val);
Si5351_Write_Reg(45, (P1 >> 8) & 0xFF);
Si5351_Write_Reg(46, P1 & 0xFF);
reg_val = ((P3 >> 16) & 0x0F) << 4 | ((P2 >> 16) & 0x0F);
Si5351_Write_Reg(47, reg_val);
Si5351_Write_Reg(48, (P2 >> 8) & 0xFF);
Si5351_Write_Reg(49, P2 & 0xFF);
}
// ============================================================
// 复位 PLLA
// ============================================================
static void Si5351_Reset_PLLA(void)
{
uint8_t reg177 = Si5351_Read_Reg(177);
Si5351_Write_Reg(177, reg177 | 0x04);
for (volatile int i = 0; i < 100; i++);
Si5351_Write_Reg(177, reg177 & ~0x04);
}
// ============================================================
// 使能 CLK0 输出
// ============================================================
static void Si5351_Enable_CLK0(bool enable)
{
uint8_t reg3 = Si5351_Read_Reg(3);
if (enable) {
reg3 &= ~0x01;
} else {
reg3 |= 0x01;
}
Si5351_Write_Reg(3, reg3);
}
// ============================================================
// 自动选择 R 分频值
// ============================================================
static uint8_t Si5351_Find_R_Div(uint32_t pll_freq, uint32_t output_freq)
{
uint8_t r_div;
uint32_t ms_div;
for (r_div = 0; r_div <= 7; r_div++) {
ms_div = pll_freq / (output_freq * (1 << r_div));
if (ms_div <= 900) {
break;
}
}
if (r_div > 0) {
ms_div = pll_freq / (output_freq * (1 << (r_div - 1)));
if (ms_div < 6) {
r_div--;
}
}
if (r_div > 7) r_div = 7;
return r_div;
}
// ============================================================
// 自动寻找最优 PLL 频率
// ============================================================
static uint32_t Si5351_Find_Best_PLL(uint32_t output_freq, uint8_t *r_div)
{
uint32_t best_pll = 800000000;
uint32_t best_error = 0xFFFFFFFF;
uint32_t test_pll;
uint8_t test_r;
uint32_t ms_div;
uint32_t actual_freq;
uint32_t error;
uint32_t fb_div;
for (test_pll = 600000000; test_pll <= 900000000; test_pll += 1000000) {
fb_div = test_pll / SI5351_XTAL_FREQ;
if (fb_div < 15 || fb_div > 90) continue;
test_r = Si5351_Find_R_Div(test_pll, output_freq);
ms_div = test_pll / (output_freq * (1 << test_r));
if (ms_div >= 6 && ms_div <= 900) {
actual_freq = test_pll / (ms_div * (1 << test_r));
error = (actual_freq > output_freq) ? (actual_freq - output_freq) : (output_freq - actual_freq);
if (error < best_error) {
best_error = error;
best_pll = test_pll;
*r_div = test_r;
}
}
}
return best_pll;
}
// ============================================================
// 设置 CLK0 频率
// ============================================================
void Si5351_Set_CLK0(uint32_t freq_hz)
{
uint32_t pll_freq;
uint8_t r_div;
if (freq_hz == 0) return;
pll_freq = Si5351_Find_Best_PLL(freq_hz, &r_div);
Si5351_Config_PLLA(pll_freq);
Si5351_Config_CLK0(pll_freq, freq_hz, r_div);
uint8_t reg16 = Si5351_Read_Reg(16) & ~0x20;
Si5351_Write_Reg(16, reg16);
Si5351_Enable_CLK0(true);
Si5351_Reset_PLLA();
}
// ============================================================
// 简化版:固定 PLL 频率
// ============================================================
void Si5351_Set_CLK0_Simple(uint32_t freq_hz)
{
uint32_t pll_freq = 800000000;
uint8_t r_div;
if (freq_hz == 0) return;
r_div = Si5351_Find_R_Div(pll_freq, freq_hz);
Si5351_Config_PLLA(pll_freq);
Si5351_Config_CLK0(pll_freq, freq_hz, r_div);
uint8_t reg16 = Si5351_Read_Reg(16) & ~0x20;
Si5351_Write_Reg(16, reg16);
Si5351_Enable_CLK0(true);
Si5351_Reset_PLLA();
}
// ============================================================
// 初始化 Si5351
// ============================================================
void Si5351_Init_CLK0(void)
{
Si5351_Write_Reg(3, 0xFF);
uint8_t reg16 = Si5351_Read_Reg(16) & ~0x20;
Si5351_Write_Reg(16, reg16);
uint8_t reg0;
do {
reg0 = Si5351_Read_Reg(0);
} while (reg0 & 0x80);
}
// ============================================================
// 直接设置频率(最简调用)
// ============================================================
void Si5351_Init_and_Set_CLK0(uint32_t freq_hz)
{
Si5351_Init_CLK0();
Si5351_Set_CLK0(freq_hz);
}
2)在main函数中
c
Si5351_Init_CLK0();
Si5351_Set_CLK0(10000000);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); //启动pwm输出
uint8_t per;
uint8_t fre;
uint8_t beg[] = "please input your CRR \r\n";
uint8_t err[] = "wrong\r\n";
uint8_t reg_value; // ← 在这里声明变量
int i;
// 1. 写入配置(修正:加上括号)
if (Si5351_WriteConfig() != HAL_OK) {
// 错误处理
while (1);
}
HAL_Delay(10);
uint8_t R = 1;
while (1) {
if (R == 1) {
HAL_UART_Transmit(&huart1, beg, sizeof(beg), 1000);
R = 0;
}
if (R == 0) {
HAL_StatusTypeDef status = HAL_UART_Receive(&huart1, &per,
sizeof(per), HAL_MAX_DELAY);
if (status == HAL_OK)
{
HAL_UART_Transmit(&huart1, &per, sizeof(per), 1000);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, per);
HAL_UART_Transmit(&huart1, (uint8_t*)"\r\n write down your Freq !\r\n", 18, 100);
HAL_UART_Receive(&huart1, &fre,sizeof(fre), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart1, &fre, sizeof(fre), 1000);
Si5351_Set_CLK0(fre * 1000000);
R = 1;
}
else if (status != HAL_OK) {
HAL_UART_Transmit(&huart1, err, sizeof(err), 1000);
R = 1;
}
}
}
3.实验现象
由于代码中没有设置二进制转换HEX输入的09=0x09是9
50====0x50也就是80,所以输出的频率9Mhz;占空比是80%


但是可以看出实验成功的