#FPGA(IRDA)

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

相关推荐
北城笑笑1 小时前
FPGA 14 ,硬件开发板分类详解,FPGA开发板与普通开发板烧录的区别
fpga开发·fpga
2202_754421541 小时前
一个计算频率的模块
驱动开发·fpga开发
小灰灰的FPGA2 小时前
低速接口项目之串口Uart开发(七)——如何在FPGA项目中实现自适应波特率串口功能
fpga开发
fei_sun1 天前
【Verilog】第一章作业
fpga开发·verilog
深圳市雷龙发展有限公司longsto1 天前
基于FPGA(现场可编程门阵列)的SD NAND图片显示系统是一个复杂的项目,它涉及硬件设计、FPGA编程、SD卡接口、NAND闪存控制以及图像显示等多个方面
fpga开发
9527华安1 天前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
able陈1 天前
为什么verilog中递归函数需要定义为automatic?
fpga开发
fei_sun1 天前
【Verilog】第二章作业
fpga开发·verilog
碎碎思1 天前
如何使用 Vivado 从源码构建 Infinite-ISP FPGA 项目
fpga开发·接口隔离原则
江山如画,佳人北望1 天前
fpga-状态机的设计及应用
fpga开发