大二下学期做的期末设计,使用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