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) begin
if(sys_rst_n == 1'b0)
state <= IDLE;
else case(state)
IDLE :begin
if(inf_in_fall == 1'b1) //引导信号下降沿到来
state <= TIME_9MS;
else
state <= IDLE;
end
TIME_9MS:begin
if((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 :begin
if((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;
end
DATA :begin
if((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)) //下降沿到来,但是高电平不足560us
state <= IDLE;
else if((inf_in_rise == 1'b1)&&(cnt_data == 6'd32)) //结束信号是拉高,计数到32个数据
state <= IDLE;
else
state <= DATA;
end
REPEAT :begin
if(inf_in_rise == 1'b1)
state <= IDLE;
else
state <= REPEAT;
end
default :begin
state <= IDLE;
end
endcase
end
/*
*电平翻转记录
*/
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
begin
inf_in_dly1 <= 1'b0;
inf_in_dly2 <= 1'b0;
end
else
begin
inf_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) begin
if(sys_rst_n == 1'b0)
cnt <= 19'd0;
else case(state)
IDLE : cnt <= 19'd0;
TIME_9MS :begin
if((inf_in_rise == 1'b1)&&(flag_9ms == 1'b1))
cnt <= 19'd0;
else
cnt <= cnt + 1'b1;
end
ARBIT :begin
if((inf_in_fall == 1'b1) && ((flag_4_5ms == 1'b1)||(flag_2_25ms == 1'b1))) //仲裁(引导信号还是重复信号)
cnt <= 19'd0;
else
cnt <= cnt + 1'b1;
end
DATA :begin
if((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/1
cnt <= 19'd0;
else
cnt <= cnt + 1'b1;
end
default : cnt <= 19'd0;
endcase
end
/*
*时间标志位控制
*/
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(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;
else
flag_9ms <= 1'b0;
end
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(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;
else
flag_4_5ms <= 1'b0;
end
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(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;
else
flag_560us <= 1'b0;
end
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(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;
else
flag_1_69ms <= 1'b0;
end
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(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;
else
flag_2_25ms <= 1'b0;
end
/*
*接收数据计数
*/
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(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;
else
cnt_data <= cnt_data;
end
/*
*接收的数据
*/
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(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;
else
data_reg <= data_reg;
end
/*
*数据倒排(LSB)
*/
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(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]};
else
data <= data;
end
/*
*重复信号使能控制
*/
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(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;
else
repeat_en <= 1'b0;
end
endmodule
仿真代码:
`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 begin
sys_clk = 1'b1;
sys_rst_n = 1'b0;
inf_in <= 1'b1;
#30
sys_rst_n <= 1'b1;
#1000
//引导码
inf_in <= 1'b0;
#9000_000
inf_in <= 1'b1;
#4500_000
//地址码(8'h57 0101_0111 1110_1010)
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
//地址反码(1110_1010 0001_0101)
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
//数据码(8'h22 0010_0010 0100_0100)
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
//数据反码(0100_0100 1011_1011)
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#560_000 //逻辑0
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
#1690_000 //逻辑1
//结束位
inf_in <= 1'b0;
#560_000
//高电平保持
inf_in <= 1'b1;
#4200_0000
//重复码
inf_in <= 1'b0;
#9000_000
inf_in <= 1'b1;
#2250_000
//结束位
inf_in <= 1'b0;
#560_000
inf_in <= 1'b1;
end
always #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