verilog实现的红外解码(详细注释)

module hs0038_irq(clk_100k, rstn, irq, data, rd_suc)/*synthesis noprune*/;
	input clk_100k;		//T=0.01ms
	input rstn;
	input irq;		
	output [31:0] data;	//16位地址码,16位操作码
	output rd_suc;		//成功标志,维持0.01ms的高电平
	
	parameter T9ms=10'd899;
	parameter T4ms5=10'd449;
	parameter Tms84=7'd83;		//0.84ms
	parameter error=8'd19;		//0.2ms

	reg [1:0] irq_tmp;
	wire irq_up;
	wire irq_down;
	
	//捕捉红外信号的上下沿
	always @(negedge clk_100k or negedge rstn)
	begin
		if (!rstn)
		begin
			irq_tmp <= 2'd0;
		end
		else
		begin
			irq_tmp[0] <= irq;
			irq_tmp[1] <= irq_tmp[0];
		end
	end

	assign irq_up = ~irq_tmp[1] & irq_tmp[0];	//上升沿为1
	assign irq_down = irq_tmp[1] & ~irq_tmp[0];	//下降沿为1


/**********************************************************/
	reg irq_suc;
	reg [31:0] irq_buf;//提取出的32位数据,地址码,其反码,操作码,其反码
	reg [9:0] irq_cnt;
	reg [3:0] step;	//状态机,解析红外的处理状态
	reg [7:0] i;	//引导码后的数据位计数
	
	//上下沿的计数
	always @(negedge clk_100k or negedge rstn)
	begin
		if (!rstn)
		begin
			irq_cnt <= 10'd0;
			step <= 4'd0;
			irq_buf <= 32'd0;
			i <= 8'd0;
			irq_suc <= 1'b0;
		end
		else
		begin
			case (step)
				4'd0 :	//开始等待捕捉引导码的上升沿
					begin	
						if (irq_up)	//第一次上升沿,过滤掉第一个上升沿
						begin
							step <= step + 1'd1;
							irq_cnt <= 10'd0;
						end
					end
						
				4'd1 :		//引导码上升沿后开始计数
					begin
						irq_cnt <= irq_cnt + 1'd1;
						if (irq_down)	//下降沿截止计数
							step <= step + 4'd1;
					end

				4'd2 :		//判断引导码的高电平合法性
					begin
						if (irq_cnt <= (T9ms+error) && irq_cnt >= (T9ms-error))//引导码的9ms高电平
						begin
							step <= step + 4'd1;
							irq_cnt <= 10'd0;
						end
						else
							step <= 4'd0;
					end

				4'd3 :		//引导码的下降沿开始计数至上升沿
					begin
						irq_cnt <= irq_cnt + 1'd1;
						if (irq_up)
							step <= step + 4'd1;
					end

				4'd4 :		//判断引导码的低电平4.5ms
					begin
						if (irq_cnt <= (T4ms5+error) && irq_cnt >= (T4ms5-error))//引导码确认完成
						begin
							step <= step + 4'd1;
							i <= 8'd0;
						end
						else
							step <= 4'd0;
					end

				4'd5 :		//引导码正确后开始提取数据
					begin
						if (irq_down)
						begin
							step <= step + 4'd1;
							irq_cnt <= 10'd0;
						end
					end

				4'd6 :		//提取每个下降沿后0.84ms时的IRQ状态,为高是表示数据0,为低时表示数据1
					begin
						irq_cnt <= irq_cnt + 1'd1;
						if (irq_cnt == Tms84)	//捕捉数据部分每个下降沿后0.84ms的值
						begin
							irq_buf[i] <= ~irq;
							i <= i + 8'd1;
							if (i==8'd31)	//所有数据提取完
								step <= step + 4'd1;
							else			//捕捉下个位的下降沿
								step <= 4'd5;
						end
					end

				4'd7 :		//提取完数据发送成功标志
					begin
						step <= step + 4'd1;
						irq_suc <= 1'b1;
					end

				4'd8 :
					begin
						irq_suc <= 1'b0;
						step <= 4'd0;
					end

				default : ;
			endcase
		end
	end

	assign rd_suc = irq_suc;
	assign data = irq_buf;
	
endmodule

    有必要说明一下,module后面的注释语句/*synthesis noprune*/是避免综合时候系统优化掉一些变量,导致在仿真里面看不到现象。
    我自己调试的时候因为红外信号进来的没有取反,所以引导码是9ms低电平,4.5ms高电平,自己没注意导致调试费了一些时间.....需要在上层把红外信号取反之后送进来,这样就能正常工作了,注释很详细,不多解释了...
    以后我会抽时间把自己调试的小功能程序分享出来,留作备用以及纪念。

你可能感兴趣的:(FPGA)