CC2530無線RF,串列埠透傳
1.前言
本文將分析一個利用CC2530實現無線串列埠,文中將會列舉部分程式碼並對CC2530的具體操作進行分析。本文的具體的內容包括以下幾個部分:
- CC2530是符合802.15.4標準的無線收發晶片,但是本文並沒有遵守802.15.4協議規則,在傳送過程中忽略了網路ID、源地址和目標地址等引數,在接收的過程中禁止了幀過濾。通過傳送和接收過程的處理使得CC2530無線部分的使用盡可能的簡單清晰,通過最少的程式碼說明問題。
- 無線晶片的除錯具有一定的難度,一般存在傳送裝置和接收裝置。為了通過最簡單的程式碼說明無線晶片的使用,本文中僅編寫一種裝置程式碼同時實現傳送和接收功能。裝置的功能也相對簡單,CC2530從串列埠接收資料並把資料通過RF部分“無損”傳送,於此同時CC2530把從RF部分接收的資料通過串列埠“無損”傳送,通過這樣的方式實現無線串列埠。
- 串列埠資料屬於“流”型資料包,RF部分屬於“幀”型資料包。在串列埠資料處理與分析中,一般採用特定的串列埠頭和長度的方式解析資料,但是本文采用通過串列埠時間間隔的方式接收資料,這種方法等同於modbus-RTU串列埠資料處理方法。通過這種檢測位元組資料時間間隔的方法使得CC2530的串列埠部分可以接收無特殊格式要求的資料,真正實現無線串列埠功能。
1.1實驗準備
為了實現無線串列埠功能,需要準備兩套CC2530模組和一個模擬器。如果條件允許可以增加一個模擬器,模擬器可以是CC Debugger也可以是SmartRF04EB,同時也可以準備一套CC2531 USBDongle做為嗅探器,抓取RF傳送資料做除錯分析。
1.2 實驗結果
本文主要實現了無線串列埠功能,通過串列埠除錯助手傳送位元組資料。例如通過串列埠向裝置A傳送Hello CC2530,裝置B可收到Hello CC2530,並把該字串通過串列埠除錯助手列印至螢幕。裝置B傳送Hello RF,裝置A同樣可以收到資料並列印至螢幕。
圖1.2.1(a-b) 裝置A和裝置B串列埠除錯介面
圖中中括號包含的數字為RSSI結果,RSSI表示接收訊號強度,例如圖中的-28。RSSI結果的單位為dBm,dBm為絕對單位且參考的標準為1mW。
2.程式碼
RF部分的暫存器較多,需要耐心閱讀資料手冊和相關工具才可以完成設定。雖然RF部分的暫存器較多,但是還是藉助smartRF工具、資料手冊和示例程式碼,依然可以總結出使用CC2530無線部分的一般方法。
初始化部分包括接收資料包幀過濾控制,發射功率控制和通道選擇;藉助smartRF工具生成若干推薦值;開啟接收終端並進入接收狀態。
2.1 主函式
void main(void)
{
P1SEL &= ~0x13; //功能:通用I/O,預設為通用I/O P1.0 P1.1 P1.4設定為通用IO
P1DIR |= 0x13; //方向:輸出 P1.0 P1.1 P1.4設定為輸出
// P1DIR |= ( 1<< 4) | (1<<1);
TX =0;
RX =1;
EA = 0; // 暫時關閉全域性中斷
SLEEPCMD &= ~0x04;
while( !(SLEEPSTA & 0x40) );
CLKCONCMD &= ~0x47; // 設定系統時鐘為32MHz
SLEEPCMD |= 0x04;
WDCTL = 0x00; //將超時時間設定為1s,在IDLE模式寫CLR暫存器不會產生影響,因此直接賦值只會改變INT和MODE。
WDCTL |= 0x08; //將看門狗定時器設定為看門狗模式
uart0_init(); // 38400
timer1_init();
timer3_init(); // 1s
rf_init(); // RF
EA = 1;
LED1 = 1;
uart0_sendbuf("20181025",8);
delay(1000);
uart0_sendbuf(serial_rxbuf,4);
while(1)
{
WDCTL = 0xa0; //在看門狗模式寫INT暫存器和MODE模式不會產生影響,因此直接賦值只會改變CLR
WDCTL = 0x50;
rx();
if(Time_1s > 900)//超過十五分鐘未接收到資料,重新初始化串列埠及RF
{
Time_1s = 0;
//uart0_init(); //38400
rf_init();
}
// tx();
// uart0_sendbuf(serial_rxbuf,4);
delay(10);
}
}
分析:
初始化IO口,設定為通用IO、輸出模式,分別為LED燈、PA、LNA。
初始化看門狗,做產品並非做實驗,軟體開門狗必須使用,以防宕機。
初始化串列埠,定時器1,定時器3,RF。定時器1用於串列埠接收,定時器3用於計時。
whilexu迴圈中實時監測是否接收到串列埠資料,收到則立即RF傳送。以及判斷shif是否連續15分鐘內都沒接收到RF資料,若無則重新初始化RF。(此機制是因為長時間射頻收發,會出現各種干擾導致接收不到RF資料,但可正常發射,程式正常執行。15分鐘為實際專案需求,根據實際情況選擇。)
2.2 RF傳送及接收
void rf_send( char *pbuf , int len)
{
int i=0;
RFST = 0xE3; // RF接收使能 ISRXON
// 等待發送狀態不活躍 並且 沒有接收到SFD
while( FSMSTAT1 & (( 1<<1 ) | ( 1<<5 )));
RFIRQM0 &= ~(1<<6); // 禁止接收資料包中斿
IEN2 &= ~(1<<0); // 清除RF全域性中斷
RFST = 0xEE; // 清除傳送緩衝區 ISFLUSHTX
RFIRQF1 = ~(1<<1); // 清除傳送完成標忿
// 填充緩衝匿填充過程需要增勢位元組,CRC校驗自動填充
RFD = len + 2;
for (int i = 0; i < len; i++)
{
RFD = *pbuf++;
}
RFST = 0xE9; // 傳送資料包 ISTXON
while (!(RFIRQF1 & (1<<1))) // 等待發送完房 RFIRQF1 = ~(1<<1); // 清除傳送完成標誌位
{
i++;
if( i > 50 )//增加退出機制,受干擾會死在此迴圈中
{
i=0;
break;
}
WDCTL = 0xa0; //在看門狗模式寫INT暫存器和MODE模式不會產生影響,因此直接賦值只會改變CLR
WDCTL = 0x50;
delay(100);
}
RFIRQM0 |= (1<<6); // RX接收中斷
IEN2 |= (1<<0);
}
分析:
除主函式中while的死迴圈,其他任何地方的while死迴圈都要特別注意,比如此處實際除錯中發現會程式卡死在等待發送完成,因此增加了退出機制。然而退出機制的時間判斷亦不可隨意設定,過短會導致每次傳輸資料長度收限制。本人因對程式時間概念不重視,導致此bug困惑許久。實測此延時時間至少可傳送100個數據。
void rf_receive_isr()
{
int rf_rx_len = 0;
int rssi = 0;
char crc_ok = 0;
rf_rx_len = RFD - 2; //長度去除兩位元組附加結果
rf_rx_len &= 0x7F;
for (int i = 0; i < rf_rx_len; i++)
{
rf_rx_buf[i] = RFD; //連續讀取接收緩衝區內容
}
rssi = RFD - 73; //讀取RSSI結果
crc_ok = RFD; //讀取CRC校驗結果 BIT7
RFST = 0xED; //清除接收緩衝區
if( crc_ok & 0x80 )
{
LED1 ^= 1;
Time_1s = 0;
uart0_sendbuf( rf_rx_buf , rf_rx_len);
comtx(rssi );
}
else
{
uart0_sendbuf("\r\nCRC Error\r\n",12);
}
}
分析:
RF接收函式,接收到的資料自帶兩位硬體CRC校驗,即crc_ok。校驗通過認為是有效資料,將計時清零,LED燈反轉,串列埠傳送出接收到的資料,併發送出rssi。
3.備註
PA:功率放大器 發射前置高電平,發射結束立即置低電平。
LNA: 低噪聲放大器 發射前置低電平,發射結束立即置高電平。
(不可操作失誤,否則導致資料接收異常)