简介:这份资源是面向嵌入式开发者的LT8920 2.4G无线模块测试程序,基于STM8微控制器实现,适合初学者入门2.4G无线通信,也可作为有经验开发者的参考资料。压缩包共62个文件,约825KB,包含8个c源文件与8个h头文件(如LT8920.c、spi.c、main.c、delay.c等驱动与应用代码)、12个o目标文件、13个cout编译输出文件,以及IAR工程配置(ewp、ewd、eww、dep等)和hex烧录文件,结构完整可直接在IDE中打开运行。目前已有1056人学习下载。通过分析其中的驱动代码,读者可掌握LT8920的初始化、参数配置与收发函数实现;应用代码展示了数据打包解包与错误处理机制;配合STM8的SPI、定时器与中断配置,能快速理解GFSK调制下的通信流程。开发者还可基于此修改数据帧格式、调整发射功率与接收灵敏度,适配不同短距离无线场景,是学习2.4G无线通信与STM8编程的实用起点。
1. 从一块吃灰的 LT8920 模块说起:这套 STM8 测试程序到底能跑通什么
手头有几片 LT8920 的 2.4G 模块,丝印模糊,引脚定义查不到,卖家给的资料只有一张模糊的方框图——这种场景做硬件的应该都不陌生。LT8920 是一颗工作在 2.4GHz ISM 频段的射频收发芯片,支持 GFSK 调制,通过 SPI 接口跟主控通信,常见于无线键鼠、遥控器、短距数据采集这类低速率场景。它便宜、外围简单,但寄存器手册写得相当克制,很多配置项只给了一个位定义,具体该填什么值全靠试。
这套基于 STM8 的测试程序,解决的就是“模块到手之后怎么确认它能收发”这个问题。它把 LT8920 的初始化、寄存器配置、发送和接收流程都封装成了可调用的函数,主控用的是 STM8S103 这类常见的小资源 MCU,编译环境是 IAR 或 SDCC 都能凑合。适合两类人:一是手里有 LT8920 模块但不确定好坏、想先点亮的硬件工程师;二是想用 STM8 做低功耗无线节点、需要一份能跑的底层驱动做起点的人。下面按“先搞清楚它在干什么 → 怎么把工程跑起来 → 怎么改参数适配自己的板子 → 踩过哪些坑”的顺序拆一遍。
2. LT8920 的 SPI 时序与寄存器配置:测试程序里到底写了什么
2.1 先看通信层:SPI 模式 0 和那根被忽略的 CSN
LT8920 的 SPI 接口不是标准四线 SPI 的简化版,它有自己的脾气。测试程序里对 SPI 的初始化集中在LT8920_SPI_Init()这个函数,核心是三点:时钟极性 CPOL=0、时钟相位 CPHA=0、片选 CSN 由软件控制而不是硬件 NSS。很多 STM8 的 SPI 例程默认用硬件 NSS,接上 LT8920 之后发现寄存器读出来全是 0xFF 或者 0x00,八成就是这里翻的车。
// STM8S103 SPI 初始化,针对 LT8920 void LT8920_SPI_Init(void) { // 1. 配置 SCK 和 MOSI 为推挽输出,MISO 为浮空输入 PB_DDR |= (1 << 5) | (1 << 6); // SCK(PB5), MOSI(PB6) 输出 PB_CR1 |= (1 << 5) | (1 << 6); // 推挽 PB_DDR &= ~(1 << 7); // MISO(PB7) 输入 PB_CR1 &= ~(1 << 7); // 浮空 // 2. CSN 用普通 GPIO 控制,初始拉高 PC_DDR |= (1 << 3); // CSN(PC3) 输出 PC_CR1 |= (1 << 3); LT8920_CSN_HIGH(); // 3. SPI 配置:主模式,CPOL=0, CPHA=0, 时钟 = fmaster/4 SPI_CR1 = 0x04; // MSTR=1, CPOL=0, CPHA=0, 分频 4 SPI_CR2 = 0x03; // SSM=1, SSI=1,软件从机管理 SPI_CR1 |= 0x40; // SPE=1,使能 SPI }这段代码里最容易被忽略的是SPI_CR2 = 0x03。STM8 的 SPI 在主机模式下如果 SSM 位不置 1,一旦 NSS 引脚被外部拉低,SPI 会直接退出主模式,表现就是发出去的数据没反应。LT8920 的 CSN 又必须由软件单独控制,所以 SSM 和 SSI 都得置位,把硬件 NSS 彻底旁路掉。时钟分频选了 4,对应 STM8S103 在 16MHz 主频下 SCK 约 4MHz,LT8920 的 SPI 最高支持 10MHz,这个速率留了余量,走线长一点也稳。
2.2 寄存器读写:地址的 bit7 是方向位
LT8920 的寄存器操作跟很多射频芯片不一样,它没有单独的读命令和写命令,而是用地址的最高位区分方向:bit7=0 表示写,bit7=1 表示读。测试程序里封装了两个函数:
// 写寄存器:addr 为 7 位地址,value 为 8 位数据 void LT8920_WriteReg(uint8_t addr, uint8_t value) { LT8920_CSN_LOW(); SPI_WriteByte(addr & 0x7F); // bit7=0,写方向 SPI_WriteByte(value); LT8920_CSN_HIGH(); } // 读寄存器:返回 8 位数据 uint8_t LT8920_ReadReg(uint8_t addr) { uint8_t val; LT8920_CSN_LOW(); SPI_WriteByte(addr | 0x80); // bit7=1,读方向 val = SPI_ReadByte(); // 读回数据 LT8920_CSN_HIGH(); return val; }注意读操作里SPI_ReadByte()之前没有额外的空写。有些 SPI 从机需要先发一个 dummy byte 才能读出数据,LT8920 不需要,它在地址字节的最后一个时钟沿之后就把数据推到 MISO 上了。如果你用的主控 SPI 外设带 FIFO 或者有固定的收发时序,这里可能要调一下,但 STM8 的 SPI 是单字节缓冲,直接读就行。
2.3 初始化序列:那几个不能改的魔数
测试程序里LT8920_Init()函数有一串看起来毫无规律的寄存器写入,这些值是从手册的推荐配置和实际抓包对比里凑出来的。挑几个关键的:
| 寄存器地址 | 写入值 | 作用 | 能不能改 |
|---|---|---|---|
| 0x00 | 0x6F | 使能内部晶振和 PLL | 不能,改了不工作 |
| 0x01 | 0x56 | 设置频段和信道间隔 | 可改,影响频点 |
| 0x02 | 0x1E | 配置数据速率和调制方式 | 可改,影响速率 |
| 0x03 | 0x0F | 设置发射功率 | 可改,影响距离 |
| 0x04 | 0x9C | 使能 CRC 和自动应答 | 按需改 |
| 0x05 | 0x20 | 设置地址宽度 | 按需改 |
| 0x06 | 0x00 | 清状态标志 | 每次发完要清 |
0x00 那个 0x6F 是血泪经验——手册上写的是“保留”,实际不写这个值,晶振起不来,SPI 读出来全是 0。0x01 和 0x02 决定了射频参数,后面调距离和速率的时候主要动这两个。0x03 的发射功率有 4 档,0x0F 是最大,但电流也最大,电池供电的场景要往下调。
3. 把工程跑起来:从编译到第一包数据的完整步骤
3.1 工程文件结构和编译选项
测试程序的文件不多,但组织方式决定了你移植的时候要动哪里。目录结构大概是:
LT8920_STM8_Test/ ├── main.c // 主循环,发送和接收的调度 ├── lt8920.c // 驱动层,SPI 读写和初始化 ├── lt8920.h // 寄存器地址定义和函数声明 ├── stm8s_conf.h // STM8 标准外设库配置 ├── stm8s_it.c // 中断服务函数 └── Project/ └── IAR/ // IAR 工程文件如果你用 IAR,直接打开Project/IAR/下的.eww文件就能编译。用 SDCC 的话需要自己写 Makefile,核心是加上-lstm8 -mstm8和头文件路径。编译选项里有一个要注意:优化等级建议用-O1或 IAR 的Low,不要开最高优化。LT8920 的 SPI 时序对延时敏感,高优化可能把LT8920_CSN_LOW()和SPI_WriteByte()之间的空操作优化掉,导致 CSN 建立时间不够,读出来数据错位。
3.2 主循环里的发送和接收
main.c的结构很直白,初始化之后进一个大循环,按键触发发送,中断接收:
void main(void) { CLK_Init(); // 时钟初始化,16MHz LT8920_SPI_Init(); // SPI 初始化 LT8920_Init(); // LT8920 寄存器初始化 UART_Init(9600); // 串口用于打印调试信息 while (1) { if (KEY_Read() == 0) // 按键按下 { uint8_t tx_buf[4] = {0xAA, 0xBB, 0xCC, 0xDD}; LT8920_TxPacket(tx_buf, 4); printf("TX done\r\n"); } if (LT8920_RxAvailable()) // 收到数据 { uint8_t rx_buf[32]; uint8_t len = LT8920_RxPacket(rx_buf); printf("RX %d bytes: ", len); for (uint8_t i = 0; i < len; i++) printf("%02X ", rx_buf[i]); printf("\r\n"); } } }发送函数LT8920_TxPacket()内部做了三件事:写 TX FIFO、触发发送、等发送完成标志。接收部分用的是轮询LT8920_RxAvailable(),没有用中断,因为测试程序追求的是逻辑清晰,不是实时性。实际产品里建议改成中断方式,LT8920 的 GIO1 引脚可以配置成接收中断输出,接在 STM8 的 EXTI 上。
3.3 用串口确认第一包数据
烧录之后,打开串口助手,波特率 9600。按一下按键,应该看到TX done。如果手头有第二块模块和另一块 STM8 板子,烧同样的程序,按其中一块的按键,另一块的串口应该打印出RX 4 bytes: AA BB CC DD。这一步跑通,说明 SPI 通信、寄存器配置、射频收发的基本链路都对了。
如果只有一块模块,也有办法验证发送是否正常:把 LT8920 配置成单载波发射模式,用频谱仪或者带 2.4G 接收的 SDR 看有没有载波出来。测试程序里没有直接提供这个模式,但可以手动改寄存器 0x02 的值,把调制关掉,只发载波。这个操作有风险,发射前确认天线接好,不然可能烧功放。
4. 参数怎么调:频点、速率、功率和地址的适配方法
4.1 频点设置:0x01 寄存器的位域拆解
LT8920 的频点由寄存器 0x01 和 0x02 共同决定,但 0x01 是主频段选择。测试程序默认写的 0x56 对应 2.400GHz 附近的某个信道。如果你要改到别的频点,需要按手册的公式算:
Freq = 2400 + (reg01_val - 0x50) * 2 (MHz)比如写 0x50 就是 2400MHz,写 0x5A 就是 2420MHz。但注意不是所有值都能用,LT8920 的 PLL 在 2400~2483MHz 之间比较稳,超出这个范围锁定时间会变长甚至失锁。改完频点之后,收发双方必须写一样的值,不然就是各说各话。
4.2 数据速率:0x02 寄存器里的取舍
0x02 寄存器控制数据速率,测试程序默认 0x1E 对应 250kbps。这个速率在近距离(10 米内)很稳,但距离一拉远,误码率就上来了。如果要降速增加距离,可以改成 0x0E 对应 50kbps,或者 0x06 对应 10kbps。降速的代价是空中传输时间变长,同样一包数据耗电更多。电池供电的传感器节点一般选 10kbps 或 50kbps,遥控器这种要求响应快的选 250kbps。
改速率的时候有一个隐藏坑:速率变了,接收端的带宽滤波也要跟着调。LT8920 的接收带宽由另一个寄存器控制,测试程序里没有暴露出来,默认是跟 250kbps 匹配的。如果你只改了速率没改带宽,接收灵敏度会掉 10dB 以上。常见做法是速率降一档,带宽也降一档,具体对应关系查手册的接收带宽表。
4.3 发射功率:0x03 寄存器的四档和电流关系
0x03 的低四位控制发射功率,测试程序写 0x0F 是最大档。实测在 3.3V 供电下,四档的电流大概是:
| 寄存器值 | 功率档位 | 发射电流(典型) | 空旷距离(250kbps) |
|---|---|---|---|
| 0x00 | 最低 | 12mA | 10 米 |
| 0x05 | 中低 | 18mA | 25 米 |
| 0x0A | 中高 | 26mA | 50 米 |
| 0x0F | 最高 | 35mA | 80 米 |
这些数字是模块配 PCB 天线测的,换天线会差很多。如果发现通信距离远低于预期,先确认 0x03 写对了没有,再检查天线匹配。LT8920 的差分射频输出需要巴伦或者 LC 匹配网络,直接接一根导线当天线,距离会缩到几米。
4.4 地址过滤:0x04 和 0x05 的配合
测试程序里 0x04 写了 0x9C,使能了 CRC 和自动应答,0x05 写了 0x20 设置地址宽度为 4 字节。这意味着发送的时候,前 4 个字节会被当作目标地址,接收端只有地址匹配才会收。如果你不需要地址过滤,把 0x04 的对应位清掉,0x05 写 0x00,就变成广播模式,所有模块都能收到。
地址过滤在多点通信里很有用,但调试的时候容易把自己绕进去。常见情况是发送端地址写的是 A,接收端地址写的是 B,然后两边都以为对方没发。建议调试阶段先关掉地址过滤,确认链路通了再打开。
5. 避坑与排查:LT8920 调试中最容易翻车的五个地方
5.1 现象:SPI 读寄存器全返回 0x00 或 0xFF
原因:CSN 时序不对,或者 SPI 模式配错。LT8920 要求 CSN 拉低之后至少等 1 个时钟周期再发第一个 SCK 沿,STM8 在 16MHz 下跑,LT8920_CSN_LOW()之后直接调SPI_WriteByte()可能太快。另外 CPOL/CPHA 如果配成模式 3,数据采样沿反了,读出来就是全 1 或全 0。
解决:在 CSN 拉低之后加一个__no_operation()或者几个空循环。确认 SPI_CR1 的 CPOL 和 CPHA 位都是 0。用示波器看 SCK 和 MOSI 的相位关系,第一个 SCK 上升沿应该对应 MOSI 上地址字节的最高位。
5.2 现象:初始化之后读 0x00 寄存器,返回值不是 0x6F
原因:晶振没起振,或者电源纹波太大。LT8920 的内部 PLL 对电源敏感,如果 3.3V 上有超过 50mV 的纹波,PLL 可能锁不住。另外晶振的负载电容如果选错,起振时间会变长,初始化之后立刻读寄存器可能读到默认值。
解决:在 VDD 引脚旁边加 100nF 和 10uF 电容,越近越好。初始化之后加 10ms 延时再读寄存器。如果还是不对,换一个晶振试试,LT8920 常见配 16MHz 晶振,负载电容 12pF 左右。
5.3 现象:能发送但接收不到,或者接收距离极短
原因:收发频点不一致,或者接收端的带宽配置跟发送速率不匹配。测试程序默认的 0x01 和 0x02 值只保证自己跟自己通,如果你改了一边的频点没改另一边,或者改了速率没改带宽,就会出现“发送正常但收不到”。
解决:先把两边都恢复成测试程序的默认值,确认能通。然后每次只改一个参数,改完立刻测。频点、速率、带宽这三个参数是绑定的,改一个就要检查另外两个。
5.4 现象:通信一段时间后死机,复位才能恢复
原因:SPI 读写没有加超时,LT8920 在某些状态下会把 MISO 拉低不放,STM8 的 SPI 如果配置成硬件 NSS 模式,会一直等,主循环卡死。另外如果用了中断接收,中断里调用了printf,串口输出阻塞也会导致看门狗复位。
解决:SPI 读写函数里加超时计数,超过一定次数直接返回错误。中断服务函数里只做标志位设置和数据搬运,打印放到主循环。看门狗建议开,但喂狗周期要大于最长的 SPI 操作时间。
5.5 现象:两块板子靠近时通信正常,拉开几米就断
原因:天线匹配没做好,或者发射功率档位太低。LT8920 的差分输出阻抗是 100 欧姆左右,直接接单端天线需要巴伦转换。很多模块为了省成本,用 LC 匹配代替巴伦,匹配没调好的话,发射效率可能只有 10%。
解决:先用 0x0F 最大功率档测距离,如果还是只有几米,基本就是天线问题。检查模块上的匹配元件,常见的是两个电感和两个电容组成的巴伦。没有网络分析仪的话,用频谱仪看发射频谱,中心频点应该干净,谐波抑制至少 20dB。
6. 进阶用法:用 LT8920 做低功耗无线节点的一个具体技巧
测试程序跑通之后,下一步通常是想把它改成电池供电的无线节点。这里有一个很具体的技巧:利用 LT8920 的 WOR(Wake-On-Radio)模式做周期性唤醒,配合 STM8 的 HALT 模式,把平均电流压到微安级。
WOR 模式的核心是让 LT8920 自己周期性地醒来监听前导码,收到有效前导码再通过 GIO 引脚唤醒 MCU。测试程序里没有实现这个,但寄存器层面是支持的。具体做法是配置 0x04 寄存器的 WOR 使能位,设置 0x07 和 0x08 寄存器定义唤醒周期,然后把 STM8 配成外部中断唤醒,中断源接 LT8920 的 GIO1。
// 配置 LT8920 WOR 模式,周期约 100ms void LT8920_EnableWOR(void) { LT8920_WriteReg(0x04, 0x9C | 0x20); // 使能 WOR LT8920_WriteReg(0x07, 0x64); // 唤醒周期高字节 LT8920_WriteReg(0x08, 0x00); // 唤醒周期低字节 LT8920_WriteReg(0x09, 0x01); // GIO1 映射为 WOR 唤醒输出 } // STM8 进入 HALT 模式,等 GIO1 下降沿唤醒 void MCU_EnterHalt(void) { EXTI_CR1 |= 0x02; // PB 口下降沿触发 __asm("halt"); // 进入 HALT }这个配置下,LT8920 大部分时间在睡眠,每 100ms 醒来监听一小段前导码,没收到就继续睡。STM8 在 HALT 模式下电流约 1uA,LT8920 在 WOR 模式下平均电流约 20uA,加起来不到 25uA。一节 200mAh 的纽扣电池能撑大半年。
但这里有一个坑:WOR 模式的唤醒周期和发送端的前导码长度必须匹配。如果发送端前导码太短,接收端刚好在睡眠周期里,就漏掉了。常见做法是发送端前导码长度至少是接收端唤醒周期的两倍。比如接收端 100ms 醒一次,发送端前导码要发 200ms 以上。这个参数在 0x02 寄存器的高四位里调,测试程序默认值可能不够,需要自己算。
从那以后我每次调 LT8920 的低功耗模式,都会先用示波器抓 GIO1 的波形,确认唤醒周期跟预期一致,再测整机电流。这个习惯帮我省了很多次“以为配好了其实没睡下去”的返工。希望帮到你。
本文还有配套的精品资源,点击获取