1.IDE:Quartus II
2.设备:Cyclone II EP2C8Q208C8N
3.实验:IRDA(仿真接收一个来自0x57地址的数据0x22 (十进制34))
4.时序图:
5.步骤
6.代码:
irda_receive.v
module irda_receive
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire irda_in , //irda接收端引脚输入output reg [19:0] data , //数据输出
output reg repeat_en //重复使能
);/**状态*/
parameter IDLE = 5'b00001 ; //空闲
parameter TIME_9MS = 5'b00010 ; //引导或者重复的9ms低电平
parameter ARBIT = 5'b00100 ; //地址
parameter DATA = 5'b01000 ; //数据
parameter REPEAT = 5'b10000 ; //重复/**时间范围*/
parameter CNT_560US_MIN = 19'd20000 ;
parameter CNT_560US_MAX = 19'd35000 ;
parameter CNT_1_69MS_MIN = 19'd80000 ;
parameter CNT_1_69MS_MAX = 19'd90000 ;
parameter CNT_2_25MS_MIN = 19'd100000 ;
parameter CNT_2_25MS_MAX = 19'd125000 ;
parameter CNT_4_5MS_MIN = 19'd175000 ;
parameter CNT_4_5MS_MAX = 19'd275000 ;
parameter CNT_9MS_MIN = 19'd400000 ;
parameter CNT_9MS_MAX = 19'd490000 ; /**寄存器*/
reg [4:0] state ; //状态
reg inf_in_dly1 ; //用于电平跳转判断(下一时刻)
reg inf_in_dly2 ; //用于电平跳转判断(上一时刻)
wire inf_in_fall ; //下降沿标志位
wire inf_in_rise ; //上升沿标志位reg [18:0] cnt ; //计数器reg flag_9ms ; //9ms标志位
reg flag_4_5ms ; //4.5ms标志位
reg flag_560us ; //560us标志位
reg flag_1_69ms ; //1.69ms标志位
reg flag_2_25ms ; //2.25ms标志位reg [5:0] cnt_data ; //记录接收的数据个数
reg [31:0] data_reg ; //数据记录/**状态跳转*/
always @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)state <= IDLE;else case(state)IDLE :begin if(inf_in_fall == 1'b1) //引导信号下降沿到来state <= TIME_9MS;elsestate <= IDLE;endTIME_9MS:beginif((inf_in_rise == 1'b1)&&(flag_9ms == 1'b1)) //引导信号到来后持续低电平再拉高,低电平时间达到9ms(进入接收地址码状态)state <= ARBIT; else if((inf_in_rise == 1'b1)&&(flag_9ms == 1'b0)) //引导信号到来后持续低电平再拉高,低电平时间未达到9ms(恢复空闲状态)state <= IDLE;else //引导信号到来后持续低电平未检测到高电平时期(还未拉高,等待中,保持状态不变)state <= TIME_9MS;end ARBIT :beginif((inf_in_fall==1'b1)&&(flag_2_25ms == 1'b1)) //下降沿到来接收到重复码(高电平时间未2.25ms,则为重复码,高电平时间为4.5ms则为引导码)state <= REPEAT;else if((inf_in_fall==1'b1)&&(flag_4_5ms == 1'b1)) state <= DATA ;else if((inf_in_fall==1'b1)&&(flag_4_5ms == 1'b0)&&(flag_2_25ms == 1'b0)) //下降沿到来,高电平不满足2.25ms和4.5ms state <= IDLE;else //保持原状态state <= ARBIT;endDATA :beginif((inf_in_rise == 1'b1) && (flag_560us == 1'b0)) //数据信号低电平不满足“0”要求state <= IDLE;else if((inf_in_fall == 1'b1)&&(flag_560us == 1'b0)&&(flag_1_69ms == 1'b0)) //下降沿到来,但是高电平不足560usstate <= IDLE;else if((inf_in_rise == 1'b1)&&(cnt_data == 6'd32)) //结束信号是拉高,计数到32个数据state <= IDLE;elsestate <= DATA;end REPEAT :beginif(inf_in_rise == 1'b1)state <= IDLE;elsestate <= REPEAT;enddefault :beginstate <= IDLE; endendcase
end/**电平翻转记录*/
always @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)begininf_in_dly1 <= 1'b0;inf_in_dly2 <= 1'b0;endelsebegininf_in_dly1 <= irda_in; //记录当前电平inf_in_dly2 <= inf_in_dly1; //记录上一时刻电平end
end/**下降沿上升沿标志位赋值*/
assign inf_in_fall = ((inf_in_dly1 == 1'b0)&&(inf_in_dly2 == 1'b1)) ? 1'b1 : 1'b0; //上一时刻高电平,当前时刻低电平(下降沿标志位拉高)
assign inf_in_rise = ((inf_in_dly1 == 1'b1)&&(inf_in_dly2 == 1'b0)) ? 1'b1 : 1'b0; //上一时刻低电平,当前时刻高电平(上升沿标志位拉高)/**cnt控制*/
always @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)cnt <= 19'd0;else case(state)IDLE : cnt <= 19'd0;TIME_9MS :beginif((inf_in_rise == 1'b1)&&(flag_9ms == 1'b1))cnt <= 19'd0;elsecnt <= cnt + 1'b1;endARBIT :beginif((inf_in_fall == 1'b1) && ((flag_4_5ms == 1'b1)||(flag_2_25ms == 1'b1))) //仲裁(引导信号还是重复信号)cnt <= 19'd0;elsecnt <= cnt + 1'b1;endDATA :beginif((inf_in_rise == 1'b1)&&(flag_560us == 1'b1))cnt <= 19'd0;else if((inf_in_fall == 1'b1)&&((flag_560us == 1'b1)||(flag_1_69ms == 1'b1))) // 0/1cnt <= 19'd0;elsecnt <= cnt + 1'b1; enddefault : cnt <= 19'd0;endcase
end/**时间标志位控制*/
always @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)flag_9ms <= 1'b0;else if((state == TIME_9MS)&&(cnt >= CNT_9MS_MIN)&&(cnt <= CNT_9MS_MAX))flag_9ms <= 1'b1;elseflag_9ms <= 1'b0;
endalways @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)flag_4_5ms <= 1'b0;else if((state == ARBIT)&&(cnt >= CNT_4_5MS_MIN)&&(cnt <= CNT_4_5MS_MAX))flag_4_5ms <= 1'b1;elseflag_4_5ms <= 1'b0;
endalways @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)flag_560us <= 1'b0;else if((state == DATA)&&(cnt >= CNT_560US_MIN)&&(cnt <= CNT_560US_MAX))flag_560us <= 1'b1;elseflag_560us <= 1'b0;
endalways @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)flag_1_69ms <= 1'b0;else if((state == DATA)&&(cnt >= CNT_1_69MS_MIN)&&(cnt <= CNT_1_69MS_MAX))flag_1_69ms <= 1'b1;elseflag_1_69ms <= 1'b0;
endalways @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)flag_2_25ms <= 1'b0;else if((state == ARBIT)&&(cnt >= CNT_2_25MS_MIN)&&(cnt <= CNT_2_25MS_MAX))flag_2_25ms <= 1'b1;elseflag_2_25ms <= 1'b0;
end/**接收数据计数*/
always @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)cnt_data <= 6'd0;else if((inf_in_rise == 1'b1)&&(cnt_data == 6'd32))cnt_data <= 6'd0;else if((inf_in_fall == 1'b1)&&(state == DATA))cnt_data <= cnt_data + 1'b1;elsecnt_data <= cnt_data;
end/**接收的数据*/
always @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)data_reg <= 32'b0;else if((state == DATA)&&(inf_in_fall == 1'b1)&&(flag_560us == 1'b1))data_reg[cnt_data] <= 1'b0;else if((state == DATA)&&(inf_in_fall == 1'b1)&&(flag_1_69ms == 1'b1))data_reg[cnt_data] <= 1'b1;elsedata_reg <= data_reg;
end/**数据倒排(LSB)*/
always @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)data <= 20'b0;else if((cnt_data == 6'd32)&&(~data_reg[23:16] == data_reg[31:24])&&(~data_reg[15:8] == data_reg[7:0]))data <= {12'b0,data_reg[23:16]};elsedata <= data;
end/**重复信号使能控制*/
always @ (posedge sys_clk or negedge sys_rst_n) beginif(sys_rst_n == 1'b0)repeat_en <= 1'b0;else if((state ==REPEAT)&&(~data_reg[23:16] == data_reg[31:24]))repeat_en <= 1'b1;elserepeat_en <= 1'b0;
endendmodule
仿真代码:
`timescale 1ns/1ns
module tb_irda_receive();reg sys_clk ;
reg sys_rst_n ;
reg inf_in ;wire [19:0] data ;
wire repeat_en ;initial beginsys_clk = 1'b1;sys_rst_n = 1'b0;inf_in <= 1'b1;#30sys_rst_n <= 1'b1;#1000
//引导码 inf_in <= 1'b0;#9000_000inf_in <= 1'b1;#4500_000
//地址码(8'h57 0101_0111 1110_1010)inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0
//地址反码(1110_1010 0001_0101)inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1
//数据码(8'h22 0010_0010 0100_0100)inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0
//数据反码(0100_0100 1011_1011)inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #560_000 //逻辑0inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1inf_in <= 1'b0;#560_000inf_in <= 1'b1; #1690_000 //逻辑1
//结束位inf_in <= 1'b0;#560_000
//高电平保持 inf_in <= 1'b1;#4200_0000
//重复码inf_in <= 1'b0;#9000_000inf_in <= 1'b1;#2250_000
//结束位inf_in <= 1'b0;#560_000inf_in <= 1'b1; endalways #10 sys_clk = ~ sys_clk;/**实例化*/
irda_receive irda_receive_inst
(
.sys_clk (sys_clk ) ,
.sys_rst_n (sys_rst_n) ,
.irda_in (inf_in ) , //irda接收端引脚输入.data (data ) , //数据输出
.repeat_en (repeat_en) //重复使能
);endmodule