STC8H開發(十六): GPIO驅動XL2400無線模組
- 2022 年 8 月 21 日
- 筆記
- Circuit/Radio, Embed/Mobile, FwLib_STC8, sdcc, STC8H, XL2400, XN297
目錄
- STC8H開發(一): 在Keil5中配置和使用FwLib_STC8封裝庫(圖文詳解)
- STC8H開發(二): 在Linux VSCode中配置和使用FwLib_STC8封裝庫(圖文詳解)
- STC8H開發(三): 基於FwLib_STC8的模數轉換ADC介紹和演示用例說明
- STC8H開發(四): FwLib_STC8 封裝庫的介紹和使用注意事項
- STC8H開發(五): SPI驅動nRF24L01無線模組
- STC8H開發(六): SPI驅動ADXL345三軸加速度檢測模組
- STC8H開發(七): I2C驅動MPU6050三軸加速度+三軸角速度檢測模組
- STC8H開發(八): NRF24L01無線傳輸音頻(對講機原型)
- STC8H開發(九): STC8H8K64U模擬USB HID外設
- STC8H開發(十): SPI驅動Nokia5110 LCD(PCD8544)
- STC8H開發(十一): GPIO單線驅動多個DS18B20數字溫度計
- STC8H開發(十二): I2C驅動AT24C08,AT24C32系列EEPROM存儲
- STC8H開發(十三): I2C驅動DS3231高精度實時時鐘晶片
- STC8H開發(十四): I2C驅動RX8025T高精度實時時鐘晶片
- STC8H開發(十五): GPIO驅動Ci24R1無線模組
- 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
示例程式碼
程式碼下載地址
- GitHub //github.com/IOsetting/FwLib_STC8/tree/master/demo/gpio/xl2400
- Gitee //gitee.com/iosetting/fw-lib_-stc8/tree/master/demo/gpio/xl2400
在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有關.