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

某次设计需要使用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://blog.51cto.com/14195504/2348865

时间: 2024-10-12 19:51:10

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

&#39;sudo&#39;不是内部或外部命令,,,,的解决办法

[说明] Windows系统从 Vista 版本开始加入了 UAC 机制,这导致没有足够权限的程序无法获取到一些关键资源.在 Linux 下我们可以使用 sudo 命令方便地提升当前程序的执行权限,但在 Windows 中却通常只能右键单击程序图标,再选择 "以管理员身份运行".这种必须使用鼠标点击的方式很不方便,尤其在我们希望自动化执行一些任务时更是显得碍手碍脚. 我们可以自己写一个运行在 Windows 系统的 sudo 命令工具. [源码] 'ShellExecute 方法 '作

【转】类型初始值设定项引发异常的解决办法

类型初始值设定项引发异常的解决办法 转自:小羊快跑1  http://www.cnblogs.com/SheepRunning/p/4452847.html 今天在调试代码的时候突然抛出了如下异常:"XORM.Database"的类型初始值设定项引发异常. 顿时感觉很突兀,平常的时候一点问题没有,为什么今天调试就出问题了呢?测试了一下,发现在数据处理层的一条实例化代码处出错: //获取类型的映射信息 MappingInfo mapInfo = xmlMapping.GetDataMap

ORA-06502: PL/SQL: 数字或值错误 : 字符串缓冲区太小解决办法

1.今天写的存储过程在执行过程中,报如下错误. exec PRO_T_008pro_update_add_delete(17,1,1,1,1,45.0,54.0,45.0,45.0,45.0,54.0,45.0,54.0,'生产厂家','CYB10-2',54.0,45.0,25.0,1.0,45.0,25.0,1.0,45.0,25.0,1.0,45.0,1,4545.0,0,0,0,'no'); begin PRO_T_008pro_update_add_delete(17,1,1,1,1,

类型初始值设定项引发异常的解决办法

今天在调试代码的时候突然抛出了如下异常:“XORM.Database”的类型初始值设定项引发异常. 顿时感觉很突兀,平常的时候一点问题没有,为什么今天调试就出问题了呢?测试了一下,发现在数据处理层的一条实例化代码处出错: //获取类型的映射信息 MappingInfo mapInfo = xmlMapping.GetDataMapInfo(type); Database db = new Database();//出错代码 db.CommandText = storageprocedure; /

注册依赖属性,提示默认值类型不匹配属性的解决办法

public static readonly DependencyProperty RichTextBoxWidthProperty; RichTextBoxWidthProperty = DependencyProperty.Register("RichTextBoxWidth", typeof(double), typeof(TelerikEditor), new PropertyMetadata(713, new PropertyChangedCallback(RichTextB

思科路由器寄存器值

寄存器值影响路由器启动过程的一个值,保存在NVRAM中.它实际是16个bit,4位一组(一个16进制的数),若从左到右编号为16,15,...,1,则13,14位表示consol口的波特率,第7位置1(即0x2142中的4)表示启动时不加载配置文件,第4到第1位叫bootfield. ▏这4位为: 0000:不加载IOS,直接即如ROM MONITOR 0001:加载ROM中的子版本 其它:正常顺序启动 ▏两个关键的值: 0x2102  正常,从flash中加载IOS,并且从NVRAM中读取配置

&#39;java&#39;不是内部或外部命令,另一个解决办法

我知道环境变量,也知道搞系统变量.别给我粘那些教程了,我的java路程是C:\Program Files\Java\jdk1.6.0_05谁弄好了把那三个变量和值发出来.... JAVA_HOME=C:\Program Files\Java\jdk1.6.0_05CLASSPATH=C:\Program Files\Java\jdk1.6.0_05\lb\tools.jar 设定好后开个CMD 运行java --------------------------------------------

c# AseConnection的类型初始值设定项引发异常 无法加载 DLL sybdrvado11.dll 解决办法

1.首要需要有以下三个文件 Sybase.Data.AseClient.dll sybdrvado11.dll sybdrvssl.dll 在程序运行目录,或者在System32下 2.如果以上不行,选择项目的生成目标平台为x86 3.确保System32下有msvcr71.dll以及msvcp71.dll文件 文件下载 这个下载链接,包含以上提到的五个文件 下面是错误的详细信息: System.TypeInitializationException: “Sybase.Data.AseClien

HttpWebResponse远程服务器返回错误: (500) 内部服务器错误 的解决办法

在工作中用C#开发了一个小程序,不断访问去请求一个网站的页面,在循环过程中有时会报"远程服务器返回错误: (500) 内部服务器错误",有时不会,出现的时机也不太一样.开始以为是网站的问题,后来网站是可以正常访问的,那就是自己程序的问题了. for (int i = refreshAccount.startNum; i <= refreshAccount.endNum; i++) { String data2 = urlstr; loadBranch2Request = (Htt