基於basys3的紅外解碼器 verilog

大二下學期做的期末設計,使用verilog編寫,對車載MP3紅外遙控器(NEC協議)進行解碼,解碼完整,並通過有趣的流水燈控制和七段數碼管控制來體現解碼效果,貼出來供大家參考。

這裏有這個作品視頻的鏈接:鏈接: http://pan.baidu.com/s/1nvRNRol 密碼: 8dmm

功能框架:


使用器件:

①basys3開發板(Artix-7  xc7a357);

②紅外接收模塊(一體化紅外接收頭、1.2K電阻),小器件,自己焊接就可以了

③車載MP3紅外遙控器(NEC協議)。


代碼挺多,這裏給出紅外解碼的部分,其餘LED和數碼管的控制模塊,在這裏就不放出來了

module JieMa(clk,rst,ir_in,ir_data_out);

 

input clk,rst,ir_in;

output reg [7:0] ir_data_out;

 

/********************邊沿檢測******************/

wire pos_edge;                   //ir_in信號的上升沿

wire neg_edge;                   //ir_in信號的下降沿

wire ir_change;              //ir_in信號發生變化 

reg reg0,reg1,reg2;        //預防亞穩態

 

always @ (posedge clk or posedge rst)

      begin

           if(rst)

                 begin

                      reg0<=1'b0;

                      reg1<=1'b0;

                      reg2<=1'b0;

                 end

           else

                 begin

                      reg0<= ir_in;

                      reg1<= reg0;

                      reg2<= reg1;

                 end

      end

assign pos_edge = reg1 & ~reg2;

assign neg_edge = ~reg1 & reg2;

assign ir_change = neg_edge | pos_edge;

/*********************************************/

 

/********************分頻計時******************/

reg [11:0] count1;

reg [8:0] count2;

wiredelay_9ms,delay_4_5ms,delay_0_56ms,delay_1_68ms;

always @ (posedge clk or posedge rst)

      begin

           if(rst)

                 count1<= 12'd0;

           elseif(ir_change)                      //ir信號發生跳變就重新計數

                 count1<= 12'd0;

           elseif(count1 == 12'd3000)  //成功計數15對應300ns    1500對應30us

                 count1<= 12'd0;

           else

                 count1<= count1 + 1'b1;

      end

always @ (posedge clk or posedge rst)

      begin

           if(rst)

                 count2<= 9'd0;

           elseif(ir_change)                      //ir信號發生跳變就重新計數

                 count2<= 9'd0;

           elseif(count1 == 12'd3000)  //count1成功計數30us,則count2+1

                 count2<= count2 + 1'b1;

           else

                 count2<= count2;

           end

assign delay_9ms =(count2>250)&(count2<350);     //300,取範圍值,增加穩定性

assign delay_4_5ms =(count2>120)&(count2<180);  //150

assign delay_0_56ms =(count2>7)&(count2<27);     //17

assign delay_1_68ms =(count2>46)&(count2<66);    //56

 

//delay_9ms=1,表示從第一次ir_in信號發生跳變開始,到下一次ir_in發生跳變爲止,此過程大概經歷了9ms

/*********************************************/

 

/******************三段式狀態機****************/

parameter start       = 3'b000,

                  begin_9ms =3'b001,

                  begin_4_5ms= 3'b010,

                  data_recive= 3'b011;

reg error;   

reg [5:0] data_count;

reg [31:0] get_data;

reg [2:0] state,next_state;

always @ (posedge clk or posedge rst)   //時序邏輯

      if(rst)

           state<= start;

      else

           state<= next_state;

          

always @ (*)          //必須全部電平敏感,狀態轉移,組合邏輯,阻塞式賦值

      case(state)

           start:

                 if(neg_edge)//IR信號發生跳變,由1變0

                      next_state= begin_9ms;

                 else

                      next_state= start;

                

           begin_9ms:

                 if(pos_edge)

                      begin

                            if(delay_9ms)//在上升沿到來時,是否經過了9ms,即低電平是否持續了9ms

                                  next_state= begin_4_5ms;

                            else

                                  next_state= start;

                      end

                 else

                      next_state= begin_9ms;

                     

           begin_4_5ms:

                 if(neg_edge)

                      begin

                            if(delay_4_5ms)//高電平是否持續了4.5ms

                                  next_state= data_recive;

                            else

                                  next_state= start;

                      end

                 else

                      next_state= begin_4_5ms;

                     

           data_recive://開始接收數據

                 if((data_count== 6'd32) & reg1 & reg2)                                                    //接受了32位數據與一位終止位

                      next_state= start;

                 elseif (error)                //接受數據過程中出錯

                      next_state= start;

                 else

                      next_state= data_recive;

                     

           default:

                 next_state= start;

      endcase

 

always @ (posedge clk or posedge rst)         //狀態中的輸出,時序邏輯

      begin

           if(rst)

                 begin

                      data_count <= 6'd0;

                      error                <= 1'b0;

                      get_data           <= 32'd0;

                 end

           elseif(state == start)                //一開始沒獲得任何數據

                 begin

                      data_count <= 6'd0;

                      error                <= 1'b0;

                      get_data           <= 32'd0;

                 end

           elseif(state == data_recive)

                 begin

                      if(pos_edge)

                            begin

                                  if(!delay_0_56ms)

 //上升沿到來,之前的低電平的持續時間不足0.56ms,說明出錯

                                       error<= 1'b1;

                                  else

                                       error<= 1'b0;

                            end

                      elseif(neg_edge)

                            begin

                                  if(delay_0_56ms)

//下降沿到來,之前的高電平的持續時間0.56ms,說明收到的是0

                                       get_data[0]<= 1'b0;

                                  elseif (delay_1_68ms)

//下降沿到來,之前的高電平的持續時間1.68ms,說明收到的是1

                                       get_data[0]<= 1'b1;

                                  else //收到的數據非0非1,說明出錯

                                       error<= 1'b1;

 

//上述各語句接收完1個位的數據,get_data[0]保存了最新接收到的數據

                                  get_data[31:1]<= get_data[30:0];

//數據左移

                                  data_count<= data_count+1'b1;

                            end

                 end

      end

/*********************************************/

 

/*************將接收到的數據輸出****************/

always @ (posedge clk or posedge rst)

      if(rst)

         ir_data_out <= 8'd0;

      elseif( (data_count == 6'd32) & reg1 & reg2)

//接受完32位數據,並且接受到最後的停止位

                 ir_data_out<=get_data[15:8];

//輸出數據碼,與實際紅外發送出來的數據是倒序相等的

      else

           ir_data_out<= ir_data_out;

/*********************************************/

endmodule


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章