STC8H開發(十六): GPIO驅動XL2400無線模組

目錄

XL2400 簡介

小眾的2.4G射頻收發晶片, 和 Ci24R1, XN297L 一樣, 都屬於 nRF24L01 派生的 SOP8 版本. 在暫存器和操作上類似於nRF24L01, 但是暫存器中存在大量多位元組的設置, 沒有中斷, 完全靠輪詢工作, 這是這個型號的特點.

在兼容性上, 和XN297L管腳布局一致但是暫存器不一樣, 比XN297L的外圍電路元件更少, 只需要一個16MHz晶振, 兩個電容就能工作. 和Ci24R1比管腳和暫存器都不一樣.

具體的參數可以查看官網上的產品介紹 和手冊 XL2400規格書V2.0a.pdf, XL240X應用說明v2.1a.pdf, 市場上還有型號為 WL2400 的晶片, 看手冊應該是同一個晶片.

XL2400 管腳和典型電路

直接看電路和程式碼

管腳定義

PIN Name I/O 說明
1 CSN DI SPI 片選訊號
2 SCK DI SPI 時鐘訊號
3 DATA/IRQ IO SPI 數據輸入/輸出/中斷訊號
4 VDD Power 電源(+2.1 ~ +3.6V,DC)
5 XC1 AI 晶振輸入
6 XC2 AO 晶振輸出
8 VSS GND
7 ANT RF 天線介面

可以和 Ci24R1 對比一下, 僅僅是管腳位置不同

電路

電路非常簡單, C3可以省略, C7可以用1pF至3pF.

沒有現成的模組, 在立創打的板子, 成品圖, 兼容XN297, 因此多預留了一些焊盤

STC8H 驅動 XL2400

驅動說明

從測試的過程看, 基於GPIO模擬SPI驅動比較穩妥, 如果用硬體SPI, 收發的通訊成功率太低. STC8H對三線SPI半雙工通訊沒有說明, 還需要進一步嘗試. 因此以下僅說明基於GPIO模擬SPI驅動的方式.

接線

示例程式碼中, 使用了與硬體SPI一樣的Pin, 實際上換成其他Pin也一樣, 因為都是通過GPIO模擬驅動.

 *    Pin connection:
 *    P35              => CSN
 *    P34              => DATA
 *    P32              => SCK
 *                        VDD1     => 3.3V
 *                        XC1,XC2  => 16MHz OSC
 *                        GND      => GND

示例程式碼

程式碼下載地址

在SPI目錄下也有硬體SPI驅動方式的程式碼, 通訊效果較差, 有興趣的可以試一下.

基礎宏定義

切換收發模式, 通過main.c中的XL2400_MODE設置

// 0:TX, 1:RX
#define XL2400_MODE 1

宏定義和Ci24R1是一樣的, 只是XL2400的CE操作更複雜一點, 需要讀寫兩個位元組所以沒放到宏定義里

#define XL2400_CSN  P35
#define XL2400_SCK  P32
#define XL2400_MOSI P34

#define XL2400_PLOAD_WIDTH       32   // Payload width

#define XL2400_DATA_OUT()        GPIO_P3_SetMode(GPIO_Pin_4, GPIO_Mode_Output_PP)
#define XL2400_DATA_IN()         GPIO_P3_SetMode(GPIO_Pin_4, GPIO_Mode_Input_HIP)
#define XL2400_DATA_LOW()        XL2400_MOSI = 0
#define XL2400_DATA_HIGH()       XL2400_MOSI = 1
#define XL2400_DATA_READ()       XL2400_MOSI

#define XL2400_CLK_LOW()         XL2400_SCK = 0
#define XL2400_CLK_HIGH()        XL2400_SCK = 1

#define XL2400_NSS_LOW()         XL2400_CSN = 0
#define XL2400_NSS_HIGH()        XL2400_CSN = 1

SPI基礎通訊, 暫存器讀寫和多位元組讀寫

SPI基本讀寫和 Ci24R1 完全一致, 可以參考 Ci24R1 的對應部分. 從官方的程式碼樣例移植時, 並沒有使用官方提供的操作方式, 因為相對比之下, 現在這種寫法更穩妥. XL2400 沒有單位元組命令, 只有普通的雙位元組命令讀寫, 其它的多位元組讀寫也和 Ci24R1 是一樣的.

XL2400的CE操作

void XL2400_CE_Low(void)
{
    XL2400_ReadToBuf(XL2400_CMD_R_REGISTER | XL2400_REG_CFG_TOP, cbuf, 2);
    *(cbuf + 1) &= 0xBF;
    XL2400_WriteFromBuf(XL2400_CMD_W_REGISTER | XL2400_REG_CFG_TOP, cbuf, 2);
}

void XL2400_CE_High(void)
{
    XL2400_ReadToBuf(XL2400_CMD_R_REGISTER | XL2400_REG_CFG_TOP, cbuf, 2);
    *(cbuf + 1) |= 0x40;
    XL2400_WriteFromBuf(XL2400_CMD_W_REGISTER | XL2400_REG_CFG_TOP, cbuf, 2);
}

XL2400 的初始化

void XL2400_Init(void)
{
    // Analog config
    XL2400_ReadToBuf(XL2400_CMD_R_REGISTER | XL2400_REG_ANALOG_CFG0, xbuf, 13);
    *(xbuf + 4) &= ~0x04;
    *(xbuf + 12) |= 0x40;
    XL2400_WriteFromBuf(XL2400_CMD_W_REGISTER | XL2400_REG_ANALOG_CFG0, xbuf, 13);
    // Switch to software CE control, wake up RF
    XL2400_WakeUp();
    // Enable Auto ACK Pipe 0
    XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_EN_AA, 0x3F);
    // Enable Pipe 0
    XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_EN_RXADDR, 0x3F);
    // Address Width, 5 bytes
    XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_SETUP_AW, 0xAF);
    // Retries and interval
    XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_SETUP_RETR, 0x33);
    // RF Data Rate 1Mbps
    XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_RF_SETUP, 0x22);
    // Number of bytes in RX payload, pipe 0 and pipe 1
    *(cbuf + 0) = XL2400_PLOAD_WIDTH;
    *(cbuf + 1) = XL2400_PLOAD_WIDTH;
    XL2400_WriteFromBuf(XL2400_CMD_W_REGISTER | XL2400_REG_RX_PW_PX, cbuf, 2);
    // Dynamic payload width: off
    XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_DYNPD, 0x00);
    // Other features
    //bit7&6=00 return status when send register address
    //bit5=0 long data pack off
    //bit4=1 FEC off
    //bit3=1 FEATURE on
    //bit2=0 Dynamic length off
    //bit1=0 ACK without payload
    //bit0=0 W_TX_PAYLOAD_NOACK off
    XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_FEATURE, 0x18);
    // Enable RSSI
    *(cbuf + 0) = 0x10;
    *(cbuf + 1) = 0x00;
    XL2400_WriteFromBuf(XL2400_CMD_W_REGISTER | XL2400_REG_RSSI, cbuf, 2);
}

XL2400 發送

發送沿用了官方例子, 在寫入發送內容, 拉高CE後, 輪詢狀態等待發送結果. 如果是MAX_RT或TX_DS_FLAG 則返回結果.

uint8_t XL2400_Tx(uint8_t *ucPayload, uint8_t length)
{
    uint8_t y = 100, status = 0;
    XL2400_ClearStatus();
    XL2400_WriteFromBuf(XL2400_CMD_W_TX_PAYLOAD, ucPayload, length);
    XL2400_CE_High();
    // Retry until timeout
    while (y--)
    {
        SYS_DelayUs(100);
        status = XL2400_ReadStatus();
        // If TX successful or retry timeout, exit
        if ((status & (MAX_RT_FLAG | TX_DS_FLAG)) != 0)
        {
            break;
        }
    }
    XL2400_CE_Low();
    return status;
}

XL2400 接收

也沿用了官方例子, 輪詢等待待接收結果狀態, 並讀出接收到的位元組

uint8_t XL2400_Rx(void)
{
    uint8_t i, status, rxplWidth;
    status = XL2400_ReadStatus();
    if (status & RX_DR_FLAG)
    {
        XL2400_CE_Low();
        rxplWidth = XL2400_ReadReg(XL2400_CMD_R_RX_PL_WID);
        XL2400_ReadToBuf(XL2400_CMD_R_RX_PAYLOAD, xbuf, rxplWidth);
        XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_STATUS, status);
        // UART1_TxChar('>');
        // for (i = 0; i < rxplWidth; i++)
        // {
        //     UART1_TxHex(*(xbuf + i));
        // }
    }
    return status;
}

每次在調用 之前, 需要設置一下RX狀態, 否則不會接收

void XL2400_SetRxMode(void)
{
    XL2400_CE_Low();
    XL2400_ClearStatus();
    XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_CFG_TOP, 0x7F);
    // XL2400_RxCalibrate();
    XL2400_CE_High();
    SYS_Delay(1);
}

XL2400通訊速率

時間有限沒有充分測試, 僅測試了1Mbps速率開啟ACK情況下的通訊情況. 接收不設間隔, 發送間隔為2 – 3 毫秒時達到最高速率, 大約每1.7秒發送256組, 每組32個位元組, 速率為2.7K 位元組每秒, 這樣看速度只有同等設置下nRF24L01的1/8, 可能和軟體模擬的SPI有關.