基于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


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