前兩天用軟件實現了EV1527及PT2622射頻編碼功能,周末在家閑來無事,我就琢磨用軟件來實現射頻編碼接收并對PT2622和EV1527格式的編碼進行解析,說干就干,周天上午一早就開始,晚上也是邊看電視邊做,經過一天的努力,終于在睡覺前完整了主要程序的編寫,周一又花了些時間來檢查,最后終于搞定。
這次我用的是315M無線接收模塊,就是這種的模塊:
按照資料說明這個模塊需要5V供電,我本來還擔心3.3V下面可能不工作,不過實踐證明,是可行的。將這個模塊的DATA管腳接到開發板的PA8,PA8是TIM1的CH1,對于射頻遙控編碼的采集我用了定時器的PWM捕獲功能,這點和紅外遙控編碼采集方式類似,不同之處在于,紅外遙控編碼用的是下降沿觸發采集,而射頻遙控編碼采用的上升沿觸發進行采集。還有一點特別重要:紅外遙控編碼接收模塊HX1838在平時沒有收到紅外信號的時候是高電平,當收到信號過后才產生脈沖,但是射頻采用電磁波進行傳輸,而平時我們所在的空間中存在各種電磁波,所以即便沒有信號的時候,也會出現不規則的波形輸入,我們需要做的就是將有用的信號從各種干擾信號中提取出來,這一點是與紅外遙控編碼接收的最大不同。
將有用的射頻遙控編碼信號從雜波中提取出來還是比較容易的,射頻遙控的一個字碼是由同步編碼+地址碼+數據碼構成,我們只需要甄別出同步碼,然后從同步碼開始進行波形采集即可。射頻編碼一般一次至少發送4個以上的字碼,由于無線傳輸過程中可能出現干擾信號,導致信號失真,因此我們必須對收到的多個字碼進行驗證,保證至少有兩個以上的連續字碼相同,這一點也是和紅外遙控編碼提取的最大不同。
經過過濾雜波、驗證有效的射頻遙控編碼之后,我們就可以得到一個有效的射頻編碼原始數據,接下來我們就需要判斷是EV1527還是PT2622以及其它類型的編碼,除了EV1527和PT2622之外的編碼暫時不支持解碼,只保留了原始采集的時長數據,而EV1527和PT2622的編碼都是由50個高低電平來表示的,怎么樣進行區分呢?
PT2622是用兩個脈沖來表示一個位,有0,1,F三種狀態:兩個窄脈沖表示0,兩個寬脈沖表示1,一個窄脈沖+一個寬脈沖表示F;而EV1527用一個脈沖來表示0和1:窄脈沖表示0,寬脈沖表示1。所以在PT2622編碼中不可能出現一個寬脈沖+窄脈沖的組合,通過這個特征就可以很方便將兩種編碼進行區分。進行了編碼區分之后,接下來的事情就比較簡單了,只需要根據兩種編碼格式的規則進行解析,得到真實的二進制編碼即可。
根據上述原理,我編寫了一個類RFRecv,這個類里面封裝了射頻編碼采集、解碼的功能;同時又對之前編寫的PT2622和EV1527編碼程序進行了封裝,寫了一個類RFSend,用于實現對原始編碼時長數據發送、EV1527和PT2622進行編碼發送的功能。
在軟件包的“Projects\RF-Recv”文件夾包含了射頻接收的完整工程,可以直接編譯、燒寫和調試。程序代碼如下:
#include "WProgram.h"
#include "RFRemote.h"
//創建射頻遙控接收實例,射頻接收模塊接到TIM1的CH1,即:PA8
RFRecv rfRecv;
void setup()
{
//初始化默認串口
Serial.begin();
rfRecv.enableRFIn();
Serial.println("RFRemote start...");
}
void loop()
{
uint16_t* rawBuf;
int16_t len = rfRecv.available();
//判斷射頻遙控編碼采集是否完成
if(len > 0)
{
//取采集的原始編碼
awBuf = rfRecv.getRawCode();
//將接收到的原始編碼通過默認串口輸出
Serial.print("Frame Length:");
Serial.print(len);
Serial.println();
for(uint16_t i=0; i
{
Serial.print(rawBuf[i]);
if(i != len - 1)
{
Serial.print(",");
}
}
Serial.println();
if(rfRecv.decode())
{
Serial.println("RF decode success...");
uint8_t codeType = rfRecv.getCodeType();
uint32_t adValue = rfRecv.getADValue();
//二進制方式顯示解碼結果
Serial.print("RF adValue:");
Serial.println(adValue, 16);
if(codeType == 1)
{
Serial.println("Code Type: PT2622" );
//12位數據中,地址為占8位,數據占4位
Serial.print("Address: " );
Serial.println(PT2622::parseAddress(adValue, 8), 16);
Serial.print("Data: " );
Serial.println(PT2622::parseData(adValue, 8), 16);
}
else if(codeType == 2)
{
Serial.println("Code Type: EV1527" );
//24位數據中,地址占20為,數據占4位
Serial.print("Address: " );
Serial.println(EV1527::parseAddress(adValue), 16);
Serial.print("Data: " );
Serial.println(EV1527::parseData(adValue), 16);
}
else
Serial.println("Other code type..." );
}
else
{
Serial.println("RF decode error...");
}
//準備取下一個遙控編碼
rfRecv.resume();
}
}
int main()
{
//初始化Rainbow
boardInit();
setup();
while(1) loop();
}
這個程序的功能是接收射頻遙控編碼,并進行解碼和顯示,運行的效果如下:
在軟件包的“Projects\EV1527”文件夾包含了發射EV1527遙控編碼的完整工程,可以直接編譯、燒寫和調試。程序代碼如下:
#include "WProgram.h"
#include "RFRemote.h"
//定義射頻編碼發送對象,使用PA0作為輸出端口
RFSend rfSend(PA0);
void setup()
{
//初始化默認串口
Serial.begin();
Serial.println("EV1527 encode start...");
}
void loop()
{
rfSend.ev1527Send(0x0FE018, 7);
delay(3000);
}
int main()
{
//初始化Rainbow
boardInit();
setup();
while(1) loop();
}
將315M無線發射模塊的DATA和PA0相連,軟件將每隔3秒鐘通過無線發射模塊發送指定的地址碼和數據。PT2622編碼調用方式類似,可以參考“Projects\PT2622”這個工程。