找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3336|回复: 0
打印 上一主题 下一主题
收起左侧

关于nRF24L01读内部任何寄存器值为08H的经历和解决办法

[复制链接]
跳转到指定楼层
楼主
ID:362076 发表于 2019-2-9 20:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
某次设计需要使用nRF24L01实现数据的双向通信,将原本在51单片机上运行成功的程序移植到STM8单片机上时,出现无法运行的问题。尝试读取nRF24L01内部的寄存器以查看模块工作状态时,发现无论哪个寄存器读出值均为0x08。现具体描述此次经历以及最后的解决方法。
原设计平台为IAP15W4K58S4,开发环境Keil uVision4,设定的工作频率22.1184MHz;移植的目标平台为STM8S105K4T6,开发环境IAR for STM8,使用HSE:8MHz,CPU时钟不分频。
设计同时使用波特率为115200bps的串口通信以及外部中断。
由于设计需要,在STM8S上,nRF24L01模块以软件模拟SPI的方式连接在STM8S的PB0~PB5端口上。引脚的定义如下:
  1. #define nRF24L01_MISO PB_IDR_IDR5
  2. #define nRF24L01_MOSI PB_ODR_ODR4
  3. #define nRF24L01_SCK PB_ODR_ODR3
  4. #define nRF24L01_CSN PB_ODR_ODR2
  5. #define nRF24L01_CE PB_ODR_ODR1
  6. #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读写函数如下所示:

  1. unsigned char nRF24L01_SPI_RW(unsigned char dat)//向SPI发送一个字节的数据,并且由其移位寄存器的特性,返回收到的字节
  2. {
  3.     unsigned char i;
  4.     for(i=0;i<8;i++)//输出8个比特
  5.     {
  6.         nRF24L01_MOSI=(dat&0x80);//高位先出,按位传递
  7.         dat=(dat<<1);//转移比特位
  8.         nRF24L01_SCK=1;//置高时钟
  9.         nRF24L01_MISO=1;
  10.         dat|=nRF24L01_MISO;//得到从机传来的比特位
  11.         nRF24L01_SCK=0; //拉低时钟
  12.     }
  13.     return(dat);//返回移位得到的数据
  14. }
复制代码

按照SPI的协议,重写函数如下:
  1. unsigned char nRF24L01_SPI_RW(unsigned char dat)//向SPI发送一个字节的数据,并且由其移位寄存器的特性,返回收到的字节
  2. {
  3.     unsigned char i;
  4.     for(i=0;i<8;i++)//输出8个比特
  5.     {
  6.         if(dat&0x80)
  7.         {
  8.             nRF24L01_MOSI=1;
  9.         }
  10.         else
  11.         {
  12.             nRF24L01_MOSI=0;
  13.         }
  14.         dat=(dat<<1);//转移比特位
  15.         nRF24L01_SCK=1;//置高时钟
  16.         if(nRF24L01_MISO)
  17.         {
  18.             dat|=1;
  19.         }
  20.         else
  21.         {
  22.             dat|=0;
  23.         }
  24.         nRF24L01_SCK=0; //拉低时钟
  25.     }
  26.     return(dat);//返回移位得到的数据
  27. }
复制代码


则出乎意料的恢复正常了。
后经过逐步化简调试,这样的表达在IAR环境下也可以正常运行:
  1. unsigned char nRF24L01_SPI_RW(unsigned char dat)//向SPI发送一个字节的数据,并且由其移位寄存器的特性,返回收到的字节
  2. {
  3.     unsigned char i;
  4.     for(i=0;i<8;i++)//输出8个比特
  5.     {
  6.         nRF24L01_MOSI=(_Bool)(dat&0x80);//高位先出,按位传递,强制转换为布尔类型
  7.         dat=(dat<<1);//转移比特位
  8.         nRF24L01_SCK=1;//置高时钟
  9.         dat|=nRF24L01_MISO//得到从机传来的比特位
  10.         nRF24L01_SCK=0; //拉低时钟
  11.     }
  12.     return(dat);//返回移位得到的数据
  13. }
复制代码


故此得到结论,IAR下,对于一个位只能赋值逻辑0、1,如果赋值一个非布尔型的数据,则会产生混乱。


文章首发51CTO博客,http://blog.51cto.com/14195504/2348865
此处为原作者转载,如需再次转载,烦请注明出处,不胜感谢。


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表