小眾的2.4G射頻收發晶元, 和 Ci24R1, XN297L 一樣, 都屬於 nRF24L01 派生的 SOP8 版本. 在寄存器和操作上類似於nRF24L01, 但是寄存器中存在大量多位元組的設置, 沒有中斷, 完全靠輪詢工作, 這是這個型號的特點. 在相容性上, 和XN297L管腳佈局一致但是寄... ...
目錄
- 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, 收發的通信成功率太低, 主要遇到的問題是SPI讀取時, 有30%概率會讀到全為0xFF的內容, 猜測是XL2400的驅動能力較弱, 無法拉低讀周期的電平?
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 https://github.com/IOsetting/FwLib_STC8/tree/master/demo/gpio/xl2400
- Gitee https://gitee.com/iosetting/fw-lib_-stc8/tree/master/demo/gpio/xl2400
在SPI目錄下也有硬體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 的初始化
XL2400的初始化, 有一部分和nRF24L01一致, 另一部分是特有的
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();
// 開啟所有 Pipe 的 Auto ACK
XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_EN_AA, 0x3F);
// 啟用所有 Pipe
XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_EN_RXADDR, 0x3F);
// 地址寬度 5 bytes
XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_SETUP_AW, 0xAF);
// 重試次數和間隔
XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_SETUP_RETR, 0x33);
// 無線速率 1Mbps
XL2400_WriteReg(XL2400_CMD_W_REGISTER | XL2400_REG_RF_SETUP, 0x22);
// 接收通道0和通道1的接收位元組數
*(cbuf + 0) = XL2400_PLOAD_WIDTH;
*(cbuf + 1) = XL2400_PLOAD_WIDTH;
XL2400_WriteFromBuf(XL2400_CMD_W_REGISTER | XL2400_REG_RX_PW_PX, cbuf, 2);
// 關閉動態接收大小
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);
// 開啟 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個位元組, 速率為4.8K 位元組每秒, 這樣看速度只有同等設置下nRF24L01的1/5, 可能和軟體模擬的SPI有關.