某次设计需要使用 nRF24L01 实现数据的双向通信, 将原本在 51 单片机上运行成功的程序移植到 STM8 单片机上时, 出现无法运行的问题. 尝试读取 nRF24L01 内部的寄存器以查看模块工作状态时, 发现无论哪个寄存器读出值均为 0x08. 现具体描述此次经历以及最后的解决方法.
原设计平台为 IAP15W4K58S4, 开发环境 Keil uVision4, 设定的工作频率 22.1184MHz; 移植的目标平台为 STM8S105K4T6, 开发环境 IAR for STM8, 使用 HSE:8MHz,CPU 时钟不分频.
设计同时使用波特率为 115200bps 的串口通信以及外部中断.
由于设计需要, 在 STM8S 上, nRF24L01 模块以软件模拟 SPI 的方式连接在 STM8S 的 PB0~PB5 端口上. 引脚的定义如下:
- #define nRF24L01_MISO PB_IDR_IDR5
- #define nRF24L01_MOSI PB_ODR_ODR4
- #define nRF24L01_SCK PB_ODR_ODR3
- #define nRF24L01_CSN PB_ODR_ODR2
- #define nRF24L01_CE PB_ODR_ODR1
- #define nRF24L01_IRQ PB_IDR_IDR0
遵循调试的基本步骤, 我更换了无线模块, 连接线, 以及平台核心板, 但是都不能够解决问题.
考虑到 STM8S 的 IIC 接口, 是真正的开漏输出, 没有内部上拉电阻. 于是查询芯片手册:
从手册可以看到, STM8S105K4T6 的 PE1,PE2 是真正的开漏输出, 而我所使用的 LQFP32 封装上没有这两个引脚, PB4,PB5 为 IIC 的映射管脚, 是具有上拉电阻的.
所以问题不在管脚选择上.
重新查阅芯片手册, 注意到 PB 管脚的输出速度均为 O1 级别, 手册上对于 O1 是这样描述的:
可以看到, O1 为不可配置的 2MHz 慢速引脚, 因为我所配置的单片机工作频率达到 8MHz, 怀疑是在与 nRF24L01 通讯过程中引脚电平变化速度过快导致 IO 电平不稳定, 于是配置 CPUDIV, 使 CPU 工作频率 8 分频在 1MHz, 故障依旧.
所以引脚输出速度不是引起问题的原因.
重新查阅 nRF24L01 的芯片手册, 想到芯片的各个寄存器读出值均为 08H, 那么应该排除芯片的初始化失败这样的可能性, 因为无论是否初始化, 按照正确配置步骤进行过之后, 芯片内部的寄存器保留位应该是保持保留值不变化, 而现在的现象是, 以 CD 载波检测寄存器为例, 本应该只有 00H 和 01H 两种取值可能性, 却读出 08H.
将关注点放在与模块进行通信的底层 SPI 模拟函数上, 我在 51 平台上使用的 SPI 读写函数如下所示:
- unsigned char nRF24L01_SPI_RW(unsigned char dat)// 向 SPI 发送一个字节的数据, 并且由其移位寄存器的特性, 返回收到的字节
- {
- unsigned char i;
- for(i=0;i<8;i++)// 输出 8 个比特
- {
- nRF24L01_MOSI=(dat&0x80);// 高位先出, 按位传递
- dat=(dat<<1);// 转移比特位
- nRF24L01_SCK=1;// 置高时钟
- nRF24L01_MISO=1;
- dat|=nRF24L01_MISO;// 得到从机传来的比特位
- nRF24L01_SCK=0; // 拉低时钟
- }
- return(dat);// 返回移位得到的数据
- }
按照 SPI 的协议, 重写函数如下:
- unsigned char nRF24L01_SPI_RW(unsigned char dat)// 向 SPI 发送一个字节的数据, 并且由其移位寄存器的特性, 返回收到的字节
- {
- unsigned char i;
- for(i=0;i<8;i++)// 输出 8 个比特
- {
- if(dat&0x80)
- {
- nRF24L01_MOSI=1;
- }
- else
- {
- nRF24L01_MOSI=0;
- }
- dat=(dat<<1);// 转移比特位
- nRF24L01_SCK=1;// 置高时钟
- if(nRF24L01_MISO)
- {
- dat|=1;
- }
- else
- {
- dat|=0;
- }
- nRF24L01_SCK=0; // 拉低时钟
- }
- return(dat);// 返回移位得到的数据
- }
则出乎意料的恢复正常了.
后经过逐步化简调试, 这样的表达在 IAR 环境下也可以正常运行:
- unsigned char nRF24L01_SPI_RW(unsigned char dat)// 向 SPI 发送一个字节的数据, 并且由其移位寄存器的特性, 返回收到的字节
- {
- unsigned char i;
- for(i=0;i<8;i++)// 输出 8 个比特
- {
- nRF24L01_MOSI=(_Bool)(dat&0x80);// 高位先出, 按位传递, 强制转换为布尔类型
- dat=(dat<<1);// 转移比特位
- nRF24L01_SCK=1;// 置高时钟
- dat|=nRF24L01_MISO// 得到从机传来的比特位
- nRF24L01_SCK=0; // 拉低时钟
- }
- return(dat);// 返回移位得到的数据
- }
故此得到结论, IAR 下, 对于一个位只能赋值逻辑 0,1, 如果赋值一个非布尔型的数据, 则会产生混乱.
来源: http://www.bubuko.com/infodetail-2947182.html