FPGA32 红外解码(仿真)

  • I NEC协议
  • II 解码过程
  • III 代码
    • 1 解码模块
    • 2 testbench
  • I V前仿真

I NEC协议

FPGA32 红外解码(仿真)_第1张图片

II 解码过程

FPGA32 红外解码(仿真)_第2张图片

III 代码

1 解码模块

module ir_decode(
	Clk,
	Rst_n,
	
	iIR,      //信号输入引脚
	
	Get_Flag, //解码一次完成标志
	irData,   //解码得到的数据
	irAddr    //解码得到的地址
);

	input Clk;
	input Rst_n;
	input iIR;
	
	output Get_Flag; 
	output [15:0]irData;
	output [15:0]irAddr;

		
	reg s_IR0,s_IR1;
//边沿检测器	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		s_IR0 <= 1'b0;
		s_IR1 <= 1'b0;
	end
	else begin
		s_IR0 <= iIR;
		s_IR1 <= s_IR0;
	end
	
	reg s_IR0_Temp,s_IR1_Temp;
	wire ir_pedge,ir_nedge;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		s_IR0_Temp <= 1'b0;
		s_IR1_Temp <= 1'b0;
	end
	else begin
		s_IR0_Temp <= s_IR1;
		s_IR1_Temp <= s_IR0_Temp;
	end	
	
	assign ir_pedge = !s_IR1_Temp && s_IR0_Temp;
	assign ir_nedge = s_IR1_Temp && !s_IR0_Temp;


//因为遥控器质量的不同,晶振的准确度也有所不同。 
// 为了能够成功检测到电平时间,计数范围要拉宽

//9ms是本次项目计数的最大值了,那我们就取10ms
//10ms ÷ 2x10^(-8)s = 5x10^5
//那么所以计数器的最大值为 5x10^5 次
//所占最大位宽为19位	
	reg [18:0]cnt;//time counter

	reg T9ms_ok;
	reg T4_5ms_ok;
	reg T_56ms_ok;
	reg T1_69ms_ok;
	
//9.5 MS 检测模块
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		T9ms_ok <= 1'b0;
	else if(cnt > 19'd325000 && cnt <19'd495000)
		T9ms_ok <= 1'b1;
	else
		T9ms_ok <= 1'b0;

//4.56 MS 检测模块		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		T4_5ms_ok <= 1'b0;
	else if(cnt > 19'd152500 && cnt <19'd277500)
		T4_5ms_ok <= 1'b1;
	else
		T4_5ms_ok <= 1'b0;

//0.56MS 检测模块	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		T_56ms_ok <= 1'b0;
	else if(cnt > 19'd20000 && cnt <19'd35000)
		T_56ms_ok <= 1'b1;
	else
		T_56ms_ok <= 1'b0;

//1.69MS 检测模块		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		T1_69ms_ok <= 1'b0;
	else if(cnt > 19'd75000 && cnt <19'd90000)
		T1_69ms_ok <= 1'b1;
	else
		T1_69ms_ok <= 1'b0;


//累积计数模块,只会向上加和清零,是否积满受上边检测模块的控制		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)	
		cnt <= 19'd0;
	else if(Cnt_en == 1'b1)
		cnt <= cnt + 1'b1;
	else
		cnt <= 19'd0;

//超时判断模块,无论是检测哪个,一旦计时超过10ms就判定为超时,出错了!	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)	
		timeout <= 1'b0;
	else if(cnt >= 19'd500000)
		timeout <= 1'b1;
	else 
		timeout <= 1'b0;
	
	
	
	reg [3:0]state;
	reg Cnt_en;     //0时计数器清0 1时计数器正常计数
//
	localparam 
		IDEL        = 4'b0001,
		LEADER_T9   = 4'b0010,
		LEADER_T4_5 = 4'b0100,
		DATE_GET    = 4'b1000;
		
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		state <= IDEL;
		Cnt_en <= 1'b0;
	end
	else if(!timeout)begin
		case(state)
			IDEL: //空闲状态 等待下次下降沿
				if(ir_nedge)begin
					Cnt_en <= 1'b1;
					state <= LEADER_T9;
				end
				else begin
					state <= IDEL;
					Cnt_en <= 1'b0;
				end
			
			LEADER_T9: //9ms低电平状态 等待下次上升沿
				if(ir_pedge)begin
					if(T9ms_ok)begin
						Cnt_en <= 1'b0;
						state <= LEADER_T4_5;
					end
					else begin
						state <= IDEL;	
					end
				end
				else begin
					state <= LEADER_T9;
					Cnt_en <= 1'b1;
				end
					
			LEADER_T4_5: //4.5ms高电平状态 等待下次下降沿
				if(ir_nedge)begin
					if(T4_5ms_ok)begin
						Cnt_en <= 1'b0;
						state <= DATE_GET;
					end
					else begin
						state <= IDEL;	
					end
				end
				else begin
					state <= LEADER_T4_5;
					Cnt_en <= 1'b1;
				end
					
			DATE_GET: //准备接收数据状态 并对nec协议中的0和1进行处理,去掉前0.56ms,配合下面处理数据的模块来使用
				if(ir_pedge && !T_56ms_ok)//错误
					state <= IDEL;
				else if(ir_nedge && (!T_56ms_ok && !T1_69ms_ok))//错误
					state <= IDEL;			
				else if(Get_Data_Done)  //一次数据接收完成(32bits)
					state <= IDEL;	
				else if(ir_pedge && T_56ms_ok)begin
					Cnt_en <= 1'b0;
				end
				else if(ir_nedge && (T_56ms_ok || T1_69ms_ok))begin
					Cnt_en <= 1'b0;				
				end
				else
					Cnt_en <= 1'b1;
			default:;
		endcase
	end
	else begin    //超时错误
		Cnt_en <= 1'b0;
		state <= IDEL;	
	end

//···············································
	reg [31:0]data_tmp;
	
	assign irAddr = data_tmp[15:0];
	assign irData = data_tmp[31:16];//16位地址 八位数据 八位数据反码
	
	reg Get_Data_Done;
	reg timeout;
	reg [5:0]data_cnt;
	
	//当进入状态机的DATA_GET状态时,就需要处理数据了
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		Get_Data_Done <= 1'b0;
		data_cnt <= 6'd0;
		data_tmp <= 32'd0;
	end
	else if(state == DATE_GET)begin
		if(ir_pedge && (data_cnt == 6'd32))begin //共收到32位数据说明一次接收已经完成
			data_cnt <= 6'd0;
			Get_Data_Done <= 1'b1;
		end
		else begin  //每来一次上升沿 就说明在DATE_GET状态中已经精准接收到了协议中前0.56ms的部分
					//下面你的任务就吃检测后半部分的时长,具体分析是0还是1 然后追加到数组的最后
			if(ir_nedge)             
				data_cnt <= data_cnt + 1'b1;//用于数组追加
			if(ir_nedge && T_56ms_ok)
				data_tmp[data_cnt] <= 1'b0;
			else if(ir_nedge && T1_69ms_ok)
				data_tmp[data_cnt] <= 1'b1;
			Get_Data_Done <= 1'b0;
		end	
	end
	
	assign Get_Flag = Get_Data_Done;

endmodule

2 testbench

地址:1 发送:aa 反码 55

`timescale 1ns/1ns

`define clk_period 20

module ir_decode_tb;
	
	reg Clk;
	reg Rst_n;
	reg iIR;
	
	wire Get_Flag;
	wire [15:0]irData;
	wire [15:0]irAddr;
	
	integer i;

	ir_decode ir_decode(
		.Clk(Clk),
		.Rst_n(Rst_n),
		
		.iIR(iIR),
		
		.Get_Flag(Get_Flag),
		.irData(irData),
		.irAddr(irAddr)
	);
	
	initial Clk = 1'b1;
	always#(`clk_period/2)Clk = ~Clk;

	initial begin
		Rst_n = 1'b0;
		iIR = 1'b1;
		#(`clk_period*10+1'b1);
		Rst_n = 1'b1;
		#2000;
		iIR = 1'b1;
		send_data(1,8'haa);
		#60000000;
		$stop	;
	end


	
	task send_data;
		input [15:0]addr;
		input [7:0]data;
		begin
			iIR = 0;#9000000;
			iIR = 1;#4500000;
			for(i=0;i<=15;i=i+1)begin
				bit_send(addr[i]);		
			end
			for(i=0;i<=7;i=i+1)begin
				bit_send(data[i]);		
			end
			for(i=0;i<=7;i=i+1)begin
				bit_send(~data[i]);		
			end
			iIR = 0;#560000;
			iIR = 1;		
		end
	endtask
	
	task bit_send;
		input one_bit;
		begin
			iIR = 0; #560000;
			iIR = 1;
			if(one_bit)
				#1690000;
			else
				#560000;
		end	
	endtask

endmodule

I V前仿真

在这里插入图片描述

你可能感兴趣的:(FPGA从硬件描述到删核跑路)