日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

FPGA 24 工程模块 红外遥控(NEC协议)解码

發布時間:2023/12/8 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FPGA 24 工程模块 红外遥控(NEC协议)解码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

FPGA 24 紅外遙控(NEC協議)解碼

主要功能 :設計了一個紅外 NEC協議的解碼模塊

實現(設計)流程:通過遙控器發送的紅外信號,外圍紅外信號接收傳感器對數據進行接收,得到一個在基頻上的高低電平的(非方波)的輸入信號IIR,fpga內部設計該模塊,實現對該信號進行解碼,設計一個狀態機,最終判斷數據解析是否完整接收,進而判斷數據是否正確。接收正確以后,數據解析出來的地址和數據,以及本次解析完成的標志信號。

實驗目的 : ①解決非方波信號協議的數據解碼 ② 狀態機判斷和時間計數器在狀態機中的靈活使用。③標志信號和always 塊的相互分離,本次實驗中,狀態機數據接收的32個bit信號,我們是在外面用了一個always 塊來處理數據接收的情況的,時間計數器的使能和不使能在實驗中用的也是非常的靈活,這個是我們需要掌握的一些比較好的設計方法,讓自己的代碼更具有可讀性.

實驗現象 : 按下紅外遙控上的按鍵,然后在QuartusⅡ軟件中使用Iln system sources and probeseditor中觀察解碼結果,根據解碼結果與紅外遙控實際發出的數值進行比較從而判斷解碼的正確性。

HT6221芯片是一款基于NEC紅外通信協議的遙控編碼芯片,基于HT6221芯片的紅外遙控發送一次數據的數據幀定義如下圖所示:

一幀數據由引導碼、地址碼和數據碼以及數據反碼組成.

其中,引導碼由9ms的載波波形和4.5ms的低電平組成,代表一個數據幀的幀頭;

地址碼共16位,低位在前,高位在后,因此,該協議理論上支持最局65536個個同的用戶;

8位數據碼及其反碼也是低位在前,高位在后。因此,理論上該協議支持高達256個用戶指令。

該協議采用脈沖之間不同時長的時間間隔來區分“1”和“O”,下圖為其編碼協議中“1”.

但是(注這里很重要): 而在實際接收時,接收頭接收到信號后【輸出的波形剛好與此波形反相】。

所以:這里有兩種處理方式,①在輸入的fpga信號端加入一個非門,最后來回改發送的信號編寫狀態機的解析協議

② 對原始信號取反,直接對其反相信號進行解碼(本次實驗使用的是這種方式.)

即實際的接收數據會變成如下所示:

實際接收到信號如下所示:

使用signal_tap-II 真實采樣到的數據波形:

IDEL : 空閑狀態(IDEL),等待IR接收信號下降沿的到來。表示引導碼信號開始到來.進入到LEADER_T9 狀態.

LEADER_T9 : 識別9ms 的低電平引導碼,識別成功則繼續識別4.5ms的高電平引導碼狀態LEADER_T4_5 ,否則返回空閑態。

LEADER_T4_5 : 識別4.5ms的高電平引導碼,識別成功則進入讀碼(DATE_GET )狀態,否則返回空閑態。

DATE_GET : 讀碼狀態,若32個碼字已經讀完或者讀取過程中發生了錯誤,則返回空閑態(IDEL)。

ir_decode.文件

module ir_decode(Clk,Rst_n,iIR,Get_Flag,irData,irAddr );input Clk; //時鐘input Rst_n; //復位input iIR; //紅外模塊信號輸入output Get_Flag; //解碼成功標志信號output [15:0]irData; //接收的數據 數據核數據反碼output [15:0]irAddr; //接收的地址 低8位核高8位reg [18:0]cnt;//time counterreg [3:0]state;// 定義一個時鐘到達的計數器標志位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];//狀態機狀態參數localparam IDEL = 4'b0001,LEADER_T9 = 4'b0010,LEADER_T4_5 = 4'b0100,DATE_GET = 4'b1000;reg s_IR0,s_IR1;//消除亞穩態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:當前時刻t0 s_IR0_Temp:后一個時刻t1endwire ir_pedge,ir_nedge;assign ir_pedge = !s_IR1_Temp && s_IR0_Temp; //上升沿:當前時刻是低電平,后一時刻是高電平assign ir_nedge = s_IR1_Temp && !s_IR0_Temp; //下降沿:當前時刻是高電平,后一時刻是低電平//時間計數器 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 標志位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標志位 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標志位 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標志位 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;//計數器 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; //默認空閑狀態Cnt_en <= 1'b0;endelse if(!timeout //沒有發出超時信號begin case(state)IDEL:if(ir_nedge)begin // ir_nedge :下降沿到來,根據引導碼的編碼方式// 它是先是高電平,隨后變成低電平的一個信號,所以檢測下降沿Cnt_en <= 1'b1; // 如果是檢測到下降沿,則Cnt_en=1,計時器開始計時state <= LEADER_T9; // 開始計數,進入 LEADER_T9 (9ms 低電平信號)狀態endelse begin //位檢測到上升沿,保持該狀態不變state <= IDEL;Cnt_en <= 1'b0;endLEADER_T9:if(ir_pedge)begin // 判斷是否檢測到上升沿,當檢測到上升沿時,表示要么進入下一狀態,// 要么就是數據從出錯if(T9ms_ok)begin //檢測到幀頭信號9ms的低電平時間在某個區間內 T9ms_ok 就會等于 1Cnt_en <= 1'b0; // Cnt_en=0 ,主要目的是計數器清零state <= LEADER_T4_5; //進入到下一個狀態endelse begin //否則沒數據檢測錯誤state <= IDEL; endendelse begin //還未檢測到上升沿state <= LEADER_T9; //狀態保持Cnt_en <= 1'b1; //計數器繼續計數endLEADER_T4_5: if(ir_nedge)begin // 判斷是否檢測到下降沿,當檢測到下降沿時,表示要么進入下一狀態(數據接收狀態),if(T4_5ms_ok)begin//檢測到幀頭信號接收正確的標志位Cnt_en <= 1'b0;// Cnt_en=0 ,計數器清零state <= DATE_GET;//進入到下一個狀態(數據接收狀態)endelse beginstate <= IDEL; //否則沒數據檢測錯誤endendelse begin //還未檢測到上升沿state <= LEADER_T4_5;Cnt_en <= 1'b1;endDATE_GET:if(ir_pedge && !T_56ms_ok) //當我們接收到上升沿(也就是說是之前是低電平560ms),且低電平時間不等于560us,那么數據接收錯誤state <= IDEL;else if(ir_nedge && (!T_56ms_ok && !T1_69ms_ok)) //高電平時間 既不是高電平560us、1.69ms ,那么數據接收錯誤state <= IDEL; else if(Get_Data_Done) //數據接收完成,進行空閑狀態state <= IDEL; else if(ir_pedge && T_56ms_ok)begin // ir_pedge && T_56ms_ok 表示前面發送的是560us 低電平信號,進入高電平信號的判斷Cnt_en <= 1'b0; //正確接受到560us的低電平信號,時間計數器清零.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數據接收完成,時間計數器清零 endelseCnt_en <= 1'b1;default:;endcaseendelse begin //超時狀態的話,讓狀態機復位Cnt_en <= 1'b0;state <= IDEL; end// 數據計數器模塊 always@(posedge Clk or negedge Rst_n)if(!Rst_n)begin//復位信號 Get_Data_Done <= 1'b0;data_cnt <= 6'd0;data_tmp <= 32'd0;endelse if(state == DATE_GET)begin //狀態機狀態 DATE_GET 時候 ,進入數據判斷任務狀態if(ir_pedge && (data_cnt == 6'd32))begin //檢測到上升沿的時候,且數據計數到33個上升沿的時候,表明數據已經接收完成data_cnt <= 6'd0;Get_Data_Done <= 1'b1; //發送 Get_Data_Doneendelse begin //注:下降沿到來,表示數據的高電平時間發送完成if(ir_nedge) //只要檢測到一個下降沿,數據計數器位+1 ,接收最后一個(第33個)下降沿的時候,變成 data_cnt = 32data_cnt <= data_cnt + 1'b1;if(ir_nedge && T_56ms_ok) //檢測到下降沿,且計數器時間位 0.56us ,數據為0data_tmp[data_cnt] <= 1'b0;else if(ir_nedge && T1_69ms_ok) //檢測到下降沿,且計數器時間位 0.56us ,數據為0data_tmp[data_cnt] <= 1'b1;Get_Data_Done <= 1'b0;end endassign Get_Flag = Get_Data_Done;endmodule

ir_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); //調用 send_data任務#60000000;send_data(3,8'heb); //調用 send_data任務#60000000;$stop ;endtask send_data;input [15:0]addr;input [7:0]data;beginiIR = 0;#9000000; //發送幀頭保持9msiIR = 1;#4500000; //發送高電平保持4.5msfor(i=0;i<=15;i=i+1)begin //發送地址,調用 bit_send task任務bit_send(addr[i]); endfor(i=0;i<=7;i=i+1)begin //發送數據bit_send(data[i]); endfor(i=0;i<=7;i=i+1)begin //發送數據反碼bit_send(~data[i]); endiIR = 0;#560000; //發送停止位數延時0.56msiIR = 1; //發送停止位的高電平endendtasktask bit_send; input one_bit;beginiIR = 0; #560000; //發送數據0,延時0.56msiIR = 1;if(one_bit) //發送1,高電平維持1.69ms#1690000;else //發送0,高電平維持0.56ms#560000;end endtaskendmodule

總結

以上是生活随笔為你收集整理的FPGA 24 工程模块 红外遥控(NEC协议)解码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。