1. 程式人生 > >關於nRF24L01讀內部任何寄存器值為08H的經歷和解決辦法

關於nRF24L01讀內部任何寄存器值為08H的經歷和解決辦法

++ 出現 接口 stm8單片機 ces 無法運行 define else type

某次設計需要使用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,如果賦值一個非布爾型的數據,則會產生混亂。

關於nRF24L01讀內部任何寄存器值為08H的經歷和解決辦法