FPGA 24 工程模块 红外遥控(NEC协议)解码
FPGA 24 紅外遙控(NEC協(xié)議)解碼
主要功能 :設(shè)計了一個紅外 NEC協(xié)議的解碼模塊
實現(xiàn)(設(shè)計)流程:通過遙控器發(fā)送的紅外信號,外圍紅外信號接收傳感器對數(shù)據(jù)進(jìn)行接收,得到一個在基頻上的高低電平的(非方波)的輸入信號IIR,fpga內(nèi)部設(shè)計該模塊,實現(xiàn)對該信號進(jìn)行解碼,設(shè)計一個狀態(tài)機(jī),最終判斷數(shù)據(jù)解析是否完整接收,進(jìn)而判斷數(shù)據(jù)是否正確。接收正確以后,數(shù)據(jù)解析出來的地址和數(shù)據(jù),以及本次解析完成的標(biāo)志信號。
實驗?zāi)康?: ①解決非方波信號協(xié)議的數(shù)據(jù)解碼 ② 狀態(tài)機(jī)判斷和時間計數(shù)器在狀態(tài)機(jī)中的靈活使用。③標(biāo)志信號和always 塊的相互分離,本次實驗中,狀態(tài)機(jī)數(shù)據(jù)接收的32個bit信號,我們是在外面用了一個always 塊來處理數(shù)據(jù)接收的情況的,時間計數(shù)器的使能和不使能在實驗中用的也是非常的靈活,這個是我們需要掌握的一些比較好的設(shè)計方法,讓自己的代碼更具有可讀性.
實驗現(xiàn)象 : 按下紅外遙控上的按鍵,然后在QuartusⅡ軟件中使用Iln system sources and probeseditor中觀察解碼結(jié)果,根據(jù)解碼結(jié)果與紅外遙控實際發(fā)出的數(shù)值進(jìn)行比較從而判斷解碼的正確性。
HT6221芯片是一款基于NEC紅外通信協(xié)議的遙控編碼芯片,基于HT6221芯片的紅外遙控發(fā)送一次數(shù)據(jù)的數(shù)據(jù)幀定義如下圖所示:
一幀數(shù)據(jù)由引導(dǎo)碼、地址碼和數(shù)據(jù)碼以及數(shù)據(jù)反碼組成.
其中,引導(dǎo)碼由9ms的載波波形和4.5ms的低電平組成,代表一個數(shù)據(jù)幀的幀頭;
地址碼共16位,低位在前,高位在后,因此,該協(xié)議理論上支持最局65536個個同的用戶;
8位數(shù)據(jù)碼及其反碼也是低位在前,高位在后。因此,理論上該協(xié)議支持高達(dá)256個用戶指令。
該協(xié)議采用脈沖之間不同時長的時間間隔來區(qū)分“1”和“O”,下圖為其編碼協(xié)議中“1”.
但是(注這里很重要): 而在實際接收時,接收頭接收到信號后【輸出的波形剛好與此波形反相】。
所以:這里有兩種處理方式,①在輸入的fpga信號端加入一個非門,最后來回改發(fā)送的信號編寫狀態(tài)機(jī)的解析協(xié)議
② 對原始信號取反,直接對其反相信號進(jìn)行解碼(本次實驗使用的是這種方式.)
即實際的接收數(shù)據(jù)會變成如下所示:
實際接收到信號如下所示:
使用signal_tap-II 真實采樣到的數(shù)據(jù)波形:
IDEL : 空閑狀態(tài)(IDEL),等待IR接收信號下降沿的到來。表示引導(dǎo)碼信號開始到來.進(jìn)入到LEADER_T9 狀態(tài).
LEADER_T9 : 識別9ms 的低電平引導(dǎo)碼,識別成功則繼續(xù)識別4.5ms的高電平引導(dǎo)碼狀態(tài)LEADER_T4_5 ,否則返回空閑態(tài)。
LEADER_T4_5 : 識別4.5ms的高電平引導(dǎo)碼,識別成功則進(jìn)入讀碼(DATE_GET )狀態(tài),否則返回空閑態(tài)。
DATE_GET : 讀碼狀態(tài),若32個碼字已經(jīng)讀完或者讀取過程中發(fā)生了錯誤,則返回空閑態(tài)(IDEL)。
ir_decode.文件
module ir_decode(Clk,Rst_n,iIR,Get_Flag,irData,irAddr );input Clk; //時鐘input Rst_n; //復(fù)位input iIR; //紅外模塊信號輸入output Get_Flag; //解碼成功標(biāo)志信號output [15:0]irData; //接收的數(shù)據(jù) 數(shù)據(jù)核數(shù)據(jù)反碼output [15:0]irAddr; //接收的地址 低8位核高8位reg [18:0]cnt;//time counterreg [3:0]state;// 定義一個時鐘到達(dá)的計數(shù)器標(biāo)志位reg T9ms_ok;reg T4_5ms_ok;reg T_56ms_ok;reg T1_69ms_ok;reg Get_Data_Done;reg Cnt_en;reg timeout;reg [5:0]data_cnt;reg [31:0]data_tmp;assign irAddr = data_tmp[15:0];assign irData = data_tmp[31:16];//狀態(tài)機(jī)狀態(tài)參數(shù)localparam IDEL = 4'b0001,LEADER_T9 = 4'b0010,LEADER_T4_5 = 4'b0100,DATE_GET = 4'b1000;reg s_IR0,s_IR1;//消除亞穩(wěn)態(tài)always@(posedge Clk or negedge Rst_n)if(!Rst_n)begins_IR0 <= 1'b0;s_IR1 <= 1'b0;endelse begins_IR0 <= iIR;s_IR1 <= s_IR0;endreg s_IR0_Temp,s_IR1_Temp;// 獲取上升沿和下降沿always@(posedge Clk or negedge Rst_n)if(!Rst_n)begins_IR0_Temp <= 1'b0;s_IR1_Temp <= 1'b0;endelse begins_IR0_Temp <= s_IR1;s_IR1_Temp <= s_IR0_Temp;// s_IR1_Temp:當(dāng)前時刻t0 s_IR0_Temp:后一個時刻t1endwire ir_pedge,ir_nedge;assign ir_pedge = !s_IR1_Temp && s_IR0_Temp; //上升沿:當(dāng)前時刻是低電平,后一時刻是高電平assign ir_nedge = s_IR1_Temp && !s_IR0_Temp; //下降沿:當(dāng)前時刻是高電平,后一時刻是低電平//時間計數(shù)器 cnt_en 使能信號always@(posedge Clk or negedge Rst_n)if(!Rst_n) cnt <= 19'd0;else if(Cnt_en == 1'b1)cnt <= cnt + 1'b1;elsecnt <= 19'd0;// T9ms_ok 標(biāo)志位always@(posedge Clk or negedge Rst_n)if(!Rst_n)T9ms_ok <= 1'b0;else if(cnt > 19'd325000 && cnt <19'd495000) // 8.5ms ~ 9.5ms T9ms_ok <= 1'b1;elseT9ms_ok <= 1'b0;// T4_5ms_ok標(biāo)志位 4ms ~ 5msalways@(posedge Clk or negedge Rst_n)if(!Rst_n)T4_5ms_ok <= 1'b0;else if(cnt > 19'd152500 && cnt <19'd277500) //4ms ~ 5msT4_5ms_ok <= 1'b1;elseT4_5ms_ok <= 1'b0;// T_56ms_ok標(biāo)志位 0.5ms ~ 0.6msalways@(posedge Clk or negedge Rst_n)if(!Rst_n)T_56ms_ok <= 1'b0;else if(cnt > 19'd20000 && cnt <19'd35000) // 0.5ms ~ 0.6msT_56ms_ok <= 1'b1;elseT_56ms_ok <= 1'b0;// T1_69ms_ok標(biāo)志位 1.6ms ~ 1.8msalways@(posedge Clk or negedge Rst_n)if(!Rst_n)T1_69ms_ok <= 1'b0;else if(cnt > 19'd75000 && cnt <19'd90000)T1_69ms_ok <= 1'b1;elseT1_69ms_ok <= 1'b0;//計數(shù)器 timeout 超時處理always@(posedge Clk or negedge Rst_n)if(!Rst_n) timeout <= 1'b0;else if(cnt >= 19'd500000)timeout <= 1'b1;else timeout <= 1'b0;// always@(posedge Clk or negedge Rst_n)if(!Rst_n)beginstate <= IDEL; //默認(rèn)空閑狀態(tài)Cnt_en <= 1'b0;endelse if(!timeout //沒有發(fā)出超時信號begin case(state)IDEL:if(ir_nedge)begin // ir_nedge :下降沿到來,根據(jù)引導(dǎo)碼的編碼方式// 它是先是高電平,隨后變成低電平的一個信號,所以檢測下降沿Cnt_en <= 1'b1; // 如果是檢測到下降沿,則Cnt_en=1,計時器開始計時state <= LEADER_T9; // 開始計數(shù),進(jìn)入 LEADER_T9 (9ms 低電平信號)狀態(tài)endelse begin //位檢測到上升沿,保持該狀態(tài)不變state <= IDEL;Cnt_en <= 1'b0;endLEADER_T9:if(ir_pedge)begin // 判斷是否檢測到上升沿,當(dāng)檢測到上升沿時,表示要么進(jìn)入下一狀態(tài),// 要么就是數(shù)據(jù)從出錯if(T9ms_ok)begin //檢測到幀頭信號9ms的低電平時間在某個區(qū)間內(nèi) T9ms_ok 就會等于 1Cnt_en <= 1'b0; // Cnt_en=0 ,主要目的是計數(shù)器清零state <= LEADER_T4_5; //進(jìn)入到下一個狀態(tài)endelse begin //否則沒數(shù)據(jù)檢測錯誤state <= IDEL; endendelse begin //還未檢測到上升沿state <= LEADER_T9; //狀態(tài)保持Cnt_en <= 1'b1; //計數(shù)器繼續(xù)計數(shù)endLEADER_T4_5: if(ir_nedge)begin // 判斷是否檢測到下降沿,當(dāng)檢測到下降沿時,表示要么進(jìn)入下一狀態(tài)(數(shù)據(jù)接收狀態(tài)),if(T4_5ms_ok)begin//檢測到幀頭信號接收正確的標(biāo)志位Cnt_en <= 1'b0;// Cnt_en=0 ,計數(shù)器清零state <= DATE_GET;//進(jìn)入到下一個狀態(tài)(數(shù)據(jù)接收狀態(tài))endelse beginstate <= IDEL; //否則沒數(shù)據(jù)檢測錯誤endendelse begin //還未檢測到上升沿state <= LEADER_T4_5;Cnt_en <= 1'b1;endDATE_GET:if(ir_pedge && !T_56ms_ok) //當(dāng)我們接收到上升沿(也就是說是之前是低電平560ms),且低電平時間不等于560us,那么數(shù)據(jù)接收錯誤state <= IDEL;else if(ir_nedge && (!T_56ms_ok && !T1_69ms_ok)) //高電平時間 既不是高電平560us、1.69ms ,那么數(shù)據(jù)接收錯誤state <= IDEL; else if(Get_Data_Done) //數(shù)據(jù)接收完成,進(jìn)行空閑狀態(tài)state <= IDEL; else if(ir_pedge && T_56ms_ok)begin // ir_pedge && T_56ms_ok 表示前面發(fā)送的是560us 低電平信號,進(jìn)入高電平信號的判斷Cnt_en <= 1'b0; //正確接受到560us的低電平信號,時間計數(shù)器清零.endelse if(ir_nedge && (T_56ms_ok || T1_69ms_ok))begin //ir_nedge && (T_56ms_ok || T1_69ms_ok) 高電平信號,且正常接收到 560us 的高電平或者 1.69ms 的高電平 Cnt_en <= 1'b0; //本次bit數(shù)據(jù)接收完成,時間計數(shù)器清零 endelseCnt_en <= 1'b1;default:;endcaseendelse begin //超時狀態(tài)的話,讓狀態(tài)機(jī)復(fù)位Cnt_en <= 1'b0;state <= IDEL; end// 數(shù)據(jù)計數(shù)器模塊 always@(posedge Clk or negedge Rst_n)if(!Rst_n)begin//復(fù)位信號 Get_Data_Done <= 1'b0;data_cnt <= 6'd0;data_tmp <= 32'd0;endelse if(state == DATE_GET)begin //狀態(tài)機(jī)狀態(tài) DATE_GET 時候 ,進(jìn)入數(shù)據(jù)判斷任務(wù)狀態(tài)if(ir_pedge && (data_cnt == 6'd32))begin //檢測到上升沿的時候,且數(shù)據(jù)計數(shù)到33個上升沿的時候,表明數(shù)據(jù)已經(jīng)接收完成data_cnt <= 6'd0;Get_Data_Done <= 1'b1; //發(fā)送 Get_Data_Doneendelse begin //注:下降沿到來,表示數(shù)據(jù)的高電平時間發(fā)送完成if(ir_nedge) //只要檢測到一個下降沿,數(shù)據(jù)計數(shù)器位+1 ,接收最后一個(第33個)下降沿的時候,變成 data_cnt = 32data_cnt <= data_cnt + 1'b1;if(ir_nedge && T_56ms_ok) //檢測到下降沿,且計數(shù)器時間位 0.56us ,數(shù)據(jù)為0data_tmp[data_cnt] <= 1'b0;else if(ir_nedge && T1_69ms_ok) //檢測到下降沿,且計數(shù)器時間位 0.56us ,數(shù)據(jù)為0data_tmp[data_cnt] <= 1'b1;Get_Data_Done <= 1'b0;end endassign Get_Flag = Get_Data_Done;endmoduleir_decode_tb.v 仿真測試文件
`timescale 1ns/1ns`define clk_period 20module ir_decode_tb;reg Clk;reg Rst_n;reg iIR;wire Get_Flag;wire [15:0]irData;wire [15:0]irAddr;integer i;ir_decode ir_decode(.Clk(Clk),.Rst_n(Rst_n),.iIR(iIR),.Get_Flag(Get_Flag),.irData(irData),.irAddr(irAddr));initial Clk = 1'b1;always#(`clk_period/2)Clk = ~Clk;initial beginRst_n = 1'b0;iIR = 1'b1;#(`clk_period*10+1'b1);Rst_n = 1'b1;#2000;iIR = 1'b1;send_data(1,8'h12); //調(diào)用 send_data任務(wù)#60000000;send_data(3,8'heb); //調(diào)用 send_data任務(wù)#60000000;$stop ;endtask send_data;input [15:0]addr;input [7:0]data;beginiIR = 0;#9000000; //發(fā)送幀頭保持9msiIR = 1;#4500000; //發(fā)送高電平保持4.5msfor(i=0;i<=15;i=i+1)begin //發(fā)送地址,調(diào)用 bit_send task任務(wù)bit_send(addr[i]); endfor(i=0;i<=7;i=i+1)begin //發(fā)送數(shù)據(jù)bit_send(data[i]); endfor(i=0;i<=7;i=i+1)begin //發(fā)送數(shù)據(jù)反碼bit_send(~data[i]); endiIR = 0;#560000; //發(fā)送停止位數(shù)延時0.56msiIR = 1; //發(fā)送停止位的高電平endendtasktask bit_send; input one_bit;beginiIR = 0; #560000; //發(fā)送數(shù)據(jù)0,延時0.56msiIR = 1;if(one_bit) //發(fā)送1,高電平維持1.69ms#1690000;else //發(fā)送0,高電平維持0.56ms#560000;end endtaskendmodule總結(jié)
以上是生活随笔為你收集整理的FPGA 24 工程模块 红外遥控(NEC协议)解码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android管理交换机,适用于Andr
- 下一篇: html5 指南针,html5指南针实现