STC8H開發(五): SPI驅動nRF24L01無線模塊


目錄

nRF24L01模塊

遷移到STC8H

只需要調整SPI發送部分, 為適應nRF24L01的發送方式, 增加了多字節發送方法(節省了字節間拉高拉低CS的GPIO操作)

uint8_t SPI_TxRx(uint8_t dat)
{
	SPDAT = dat;
    while (!SPI_RxTxFinished());
    SPI_ClearInterrupts();
	return SPDAT;
}

void SPI_TxRxBytes(uint8_t *pBuf, uint8_t len)
{
    while(len--)
    {
        *pBuf++ = SPI_TxRx(*pBuf);
    }
}

對應nRF24L01的SPI通信部分. 這里對發送作了一些優化

  1. 將命令和后續數據合並為字節數組一並發出, 節約發送開銷
  2. 發送和接收使用同一段內存地址, 節約內存開銷
  3. 每次交互后, 地址的第一個字節都是當前nRF24L01的狀態數據, 在某些場景可以避免二次調用
void NRF24L01_WriteReg(uint8_t reg, uint8_t value)
{
    NRF_CSN = 0;
    xbuf[0] = reg;
    xbuf[1] = value;
    SPI_TxRxBytes(xbuf, 2);
    NRF_CSN = 1;
}

uint8_t NRF24L01_ReadReg(uint8_t reg)
{
    NRF_CSN = 0;
    xbuf[0] = reg;
    xbuf[1] = NRF24_CMD_NOP;
    SPI_TxRxBytes(xbuf, 2);
    NRF_CSN = 1;
    return xbuf[1];
}

void NRF24L01_ReadToBuf(uint8_t reg, uint8_t len)
{
    NRF_CSN = 0;
    memset(xbuf, NRF24_CMD_NOP, NRF24_PLOAD_WIDTH + 1);
    xbuf[0] = reg;
    SPI_TxRxBytes(xbuf, len + 1);
    NRF_CSN = 1;
}

void NRF24L01_WriteFromBuf(uint8_t reg, const uint8_t *pBuf, uint8_t len)
{
    NRF_CSN = 0;
    xbuf[0] = reg;
    memcpy(xbuf_data, pBuf, len);
    SPI_TxRxBytes(xbuf, len + 1);
    NRF_CSN = 1;
}

nRF24L01模塊演示用例

接線方式

因為使用了20pin的 STC8H1K08, 所以可選的SPI引腳只有P3開頭的這組, 連線方式如下
20pin的STC8H3K32S2的接線和這個一樣. 如果使用的是32pin或者更多pin的型號, 可以選擇其它組的SPI

/** 
 * Example code of SPI driving NRF24L01 module
 * 
 *    Pin connection:
 *    P35(SS, Ignored) => CSN
 *    P34(MOSI)        => MOSI
 *    P33(MISO)        => MISO
 *    P32(SPCLK)       => CLK
 *    P36(INT2)        => IRQ
 *    P37(IO)          => CE
 * 
 * test-board: Minimum System; test-MCU: STC8H1K08,STC8H3K32S2
 */

配置

接收和發送方的地址配置在 nrf24l01.c, 對於發送方和接收方, 需要將這兩個地址互換.

const uint8_t TX_ADDRESS[NRF24_ADDR_WIDTH] = {0x32,0x4E,0x6F,0x64,0x22};
const uint8_t RX_ADDRESS[NRF24_ADDR_WIDTH] = {0x32,0x4E,0x6F,0x64,0x65};

pin腳的配置在 nrf24l01.h, 如果有變化, 這里要相應地調整

#define NRF_CSN  P35
#define NRF_MOSI P34
#define NRF_MISO P33
#define NRF_SCK  P32
#define NRF_IRQ  P36
#define NRF_CE   P37

初始化方法

如果只發送, 則只需要進行SPI和GPIO初始化

const NRF24_SCEN CURRENT_SCEN = NRF24_SCEN_HALF_DUPLEX;
extern uint8_t __IDATA xbuf[NRF24_PLOAD_WIDTH + 1];

void SPI_Init(void)
{
    // SPI預分頻
    SPI_SetClockPrescaler(SPI_ClockPreScaler_16);
    // 時鍾在空閑時保持低電平
    SPI_SetClockPolarity(HAL_State_OFF);
    // 由拉低SS腳觸發數據傳輸
    SPI_SetClockPhase(SPI_ClockPhase_LeadingEdge);
    // 數據順序MSB
    SPI_SetDataOrder(SPI_DataOrder_MSB);
    // 設定SPI的輸出腳
    SPI_SetPort(SPI_AlterPort_P35_P34_P33_P32);
    // 忽略SS腳, 使用 MSTR 控制主從模式
    SPI_IgnoreSlaveSelect(HAL_State_ON);
    // 主模式
    SPI_SetMasterMode(HAL_State_ON);
    // 開啟SPI
    SPI_SetEnabled(HAL_State_ON);
}

void GPIO_Init(void)
{
    // 在配置SPI之前配置GPIO
    // MISO(P33) MOSI(P34)
    GPIO_P3_SetMode(GPIO_Pin_4, GPIO_Mode_InOut_QBD);
    // SCLK(P32) CSN(P35) CE(P37)
    GPIO_P3_SetMode(GPIO_Pin_2|GPIO_Pin_5|GPIO_Pin_7, GPIO_Mode_Output_PP);
    // IRQ(P36)
    GPIO_P3_SetMode(GPIO_Pin_6, GPIO_Mode_Input_HIP);
}

如果需要接收, 則還需要初始化中斷和中斷處理方法

void INT_Init()
{
    EXTI_Int2_SetIntState(HAL_State_ON);
    EXTI_Global_SetIntState(HAL_State_ON);
}

INTERRUPT(Int2_Routine, EXTI_VectInt2)
{
    NRF24L01_HandelIrqFlag();
}

接收模式

main()
{
    ...
    NRF24L01_Init(NRF24_MODE_RX);
    INT_Init();
    while (1);

發送模式

發送部分使用了FIFO隊列的快速寫入模式

main()
{
    ...
    NRF24L01_Init(NRF24_MODE_TX);
    UART1_TxString("NRF24L01 Initialized\r\n");
    while (1)
    {
        if (NRF24L01_WriteFast(tmp) == 0)
        {
            NRF24L01_ResetTX();
            err++;
        }
        else
        {
            succ++;
        }
        if (err >= 255 || succ >= 255)
        {
            UART1_TxHex(err);
            UART1_TxHex(succ);
            UART1_TxChar('.');
            err = 0;
            succ = 0;
        }
        SYS_Delay(50);
    }

半雙工模式

在半雙工模式下, 使用的還是普通的發送方法. 空閑時處於接收狀態, 只有當發送數據時切換到發送狀態, 發送后自動回到接收狀態.

main()
{
    ...
    NRF24L01_Init(NRF24_MODE_RX);
    INT_Init();
    while (1)
    {
        NRF24L01_Tx(tmp);
        SYS_Delay(1000);
    }

實際測試性能

使用 STC8H1K08 fastwrite發送, STC8H3K32S2 使用中斷接收

  • 以下都是不帶內容輸出的測試結果
  • 發送間隔1ms時發送速率最高, 能達到720~748個package每秒, 每個package是32字節, 差不多23K字節每秒
  • 發送間隔為0ms時速度下降明顯, 只有1ms間隔時的80%

完整代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM