弄CC1101的频率设置问题,给用户实现一个函数,用户可以指定载波频率,然后在函数里设置这个频率
涉及到公式计算,f_carrier = f_xosc*FREQ/(2^16) (完整的公式涉及到信道号和信道间隔,为了简化,暂时没有使用信道,CHANNR配置为0)
通过用户输入的想设置的载波频率,反推FREQ寄存器的值(24bits,实际是FREQ2/FREQ1/FREQ0三个寄存器)。
用户指定函数的合法参数范围为:434050–434790kHz and 868150–868550kHz.
本人菜且懒,用GEMINI生成代码(代码只是先计算,没有设置FREQ寄存器)如下:
#define LOWER_LIMIT_1 434050e3 // 434.05 MHz in Hz
#define UPPER_LIMIT_1 434790e3 // 434.79 MHz in Hz
#define LOWER_LIMIT_2 868150e3 // 868.15 MHz in Hz
#define UPPER_LIMIT_2 868550e3 // 868.55 MHz in Hz
uint32_t SetOperatingFrequency(double f_carrier) {
const double f_xosc = 27e6; // 27 MHz in Hz
// Check if f_carrier is within valid ranges
if (f_carrier < LOWER_LIMIT_1 || (f_carrier > UPPER_LIMIT_1 &&
f_carrier < LOWER_LIMIT_2) || f_carrier > UPPER_LIMIT_2) {
print_log("Error: Carrier frequency %.2f kHz is outside valid ranges\n", f_carrier / 1e3);
print_log("(%.2f-%.2f kHz or %.2f-%.2f kHz)\n", LOWER_LIMIT_1 / 1e3, UPPER_LIMIT_1 / 1e3, LOWER_LIMIT_2 / 1e3, UPPER_LIMIT_2 / 1e3);
return UINT32_MAX; // Example: return maximum value to indicate error
}
// Calculate the ideal FREQ value
double ideal_freq = (f_carrier * pow(2, 16)) / f_xosc;
print_log("The ideal_freq: %f\n", ideal_freq);
// Check if ideal_freq is within representable range of uint32_t
if (ideal_freq > UINT32_MAX || ideal_freq < 0) {
// Handle error: desired frequency outside representable range
print_log("Error: Desired frequency cannot be represented due to hardware limitations.\n");
return UINT32_MAX; // Example: return maximum value to indicate error
}
// Round the ideal FREQ to the nearest integer (24-bit representation)
uint32_t freq = round(ideal_freq);
print_log("The FREQ: %d\n", freq);
// Calculate the actual carrier frequency based on the set FREQ
double actual_f_carrier = f_xosc / pow(2, 16) * freq;
print_log("The actual_f_carrier : %.2f\n", actual_f_carrier);
return actual_f_carrier;
}
(代码中的print_log是用RTT Viewer打印的函数,详细可以参考下列文章
【嵌入式小技巧】STM32 实现 SEGGER RTT 打印(超详细)-优快云博客)
GEMINI生成的代码,用了double作为形参, 虽然我觉得不是很有必要,但还是留下了,然后测试,
然后在main函数中调用,传入最大合法值868550kHz:
uint32_t ActualFreq = SetOperatingFrequency(868550e3);
print_log("ActualFreq: %d\n", ActualFreq);
输出结果为:
手动算一下核对结果
根据公式
f_carrier = f_xosc*FREQ/(2^16)
那么
FREQ = f_carrier * 2^16 / f_xosc
晶振用的是27MHz,
FREQ = 868550*1000 * 2^16 / 27000000 = 2108196.0296
圆整为 2108196 = = 0x 202B24 ,这是 FREQ 应该设置的值
在用这个值代入f_carrier = f_xosc*FREQ/(2^16)算实际的频率值为:
f_carrier = 27000000 * 2108196 / 2^16 = 868,549,987.79296875
但奇怪的是在函数内输出的actual_f_carrier是868550016.00
print_log("The actual_f_carrier : %.2f\n", actual_f_carrier);
可是函数返回的值把double转换成了uint32_t后输出的ActualFreq 却变正常了
print_log("ActualFreq: %d\n", ActualFreq);
于是怀疑是和RTT 打印有关,因为毕竟官方没有支持浮点打印,是网友想出的办法,(虽然我参考的博文说实现了打印小数点后面6位,但可能值是不准确的。在我这里,似乎868550016.00这个值从8685后面的数字都是不准确的。是有点离谱的,具体没有费心去分析。)
为了验证这个想法,改用串口打印:
函数内actual_f_carrier的值变正常了。所以还是用串口打印浮点数靠谱点,除非实在串口接不出来另说。