FPGA之红外遥控

一、红外遥控简介

1.红外遥控系统

红外遥控系统由红外发射部分和红外接收部分组成。发射部分由遥控案件、编码以及调制电路、红外发光二极管等组成。接收部分由光敏二极管、解调电路等组成,最后将解调的信号输入FPGA内进行解码输出。

2.硬件介绍

使用的红外接收头要购买一体化红外接收头
在这里插入图片描述
使用的红外遥控器
在这里插入图片描述
红外遥控解码图为
在这里插入图片描述

3.红外遥控编码协议

红外遥控的编码协议种类繁多,如:NEC、Philips RC-5、Philips RC-6、Sony SIRC等,而使用最多的是 NEC 协议,我们使用的便是NEC协议。

NEC协议使用的是PPM(脉冲位置调制)进行编码,当按下遥控器的一个按键时,会发送一帧的数据,一帧数据由引导码、地址码、地址反码、数据码、数据反码以及一位结束位组成。
在这里插入图片描述
引导码:9ms高电平脉冲加4.5ms低电平。
结束位:562.5us脉冲表示消息传输的结束。
地址码、地址反码、数据码、数据反码:均为八位数据,每一对加起来都有八个0和八个1。

在这里插入图片描述

4.重复码

如果一直按按键,当发送完数据后,每隔110ms会发送一个重复码,重复码由9ms的高电平和2.25ms的低电平以及560us(结束为)组成。
在这里插入图片描述

5.FPGA接收

FPGA接收到的数据波形与发送的波形相反,发送高电平,就接收低电平,发送低电平,就接收高电平。

二、程序设计

1.实现功能

使用红外遥控器发送红外编码,由FPGA连接一体化红外接收头接收数据,将接收到的编码显示在数码管上。如果长按,板载led灯开始闪烁

2.红外接收模块

小提示:使用状态机进行状态跳转
RTL代码:

module infrared_rcv(
	input wire sys_clk,
	input wire sys_rst_n,
	input wire infrared_in,
	
	output reg [19:0]data,
	output reg repeat_en
);

	parameter	CNT_0_56MS_L=20000,
					CNT_0_56MS_H=35000,
					CNT_1_69MS_L=80000,
					CNT_1_69MS_H=90000,
					CNT_2_25MS_L=100000,
					CNT_2_25MS_H=125000,
					CNT_4_5MS_L=175000,
					CNT_4_5MS_H=275000,
					CNT_9MS_L=400000,
					CNT_9MS_H=490000;
	parameter	IDLE=5'b0_0001,
					S_T9=5'b0_0010,
					S_JUDGE=5'b0_0100,
					S_IFR_DATA=5'b0_1000,
					S_REPEAT=5'b1_0000;
	
	wire ifr_in_rise;//检测红外信号上升沿
	wire ifr_in_fall;

	reg infrared_in_d1;
	reg infrared_in_d2;
	reg [18:0]cnt;
	reg flag_0_56ms;
	reg flag_1_69ms;
	reg flag_2_25ms;
	reg flag_4_5ms;
	reg flag_9ms;
	reg [4:0]state;
	reg [5:0]data_cnt;
	reg [31:0]data_tmp;
	
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		infrared_in_d1<=1'b0;
	else
		infrared_in_d1<=infrared_in;
		
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		infrared_in_d2<=1'b0;
	else
		infrared_in_d2<=infrared_in_d1;
		
		//红外信号上升和下降沿
	assign ifr_in_rise=infrared_in_d1 && ~infrared_in_d2;
	
	assign ifr_in_fall=infrared_in_d2 && ~infrared_in_d1;
	
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		cnt<=1'b0;
	else 
		case(state)
			IDLE:
				cnt<=12'b0;
			S_T9:
				if(ifr_in_rise && flag_9ms)
					cnt<=1'b0;
				else
					cnt<=cnt+1'b1;
			S_JUDGE:
				if(ifr_in_fall && (flag_4_5ms || flag_2_25ms))
					cnt<=1'b0;
				else
					cnt<=cnt+1'b1;
			S_IFR_DATA:
				if(flag_0_56ms && ifr_in_rise)
					cnt<=1'b0;
				else if((flag_0_56ms || flag_1_69ms) && ifr_in_fall)
					cnt<=1'b0;
				else
					cnt<=cnt+1'b1;
			default:
				cnt<=1'b0;
		endcase
	
	//计数到0.56ms范围拉高标志信号
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		flag_0_56ms<=1'b0;
	else if(state==S_IFR_DATA && cnt>=CNT_0_56MS_L && cnt<=CNT_0_56MS_H)
		flag_0_56ms<=1'b1;
	else
		flag_0_56ms<=1'b0;
		
	//计数到1.69ms范围拉高标志信号
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		flag_1_69ms<=1'b0;
	else if(state==S_IFR_DATA && cnt>=CNT_1_69MS_L && cnt<=CNT_1_69MS_H)
		flag_1_69ms<=1'b1;
	else
		flag_1_69ms<=1'b0;
		
	//计数2.25ms
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		flag_2_25ms<=1'b0;
	else if(state==S_JUDGE && cnt>=CNT_2_25MS_L && cnt<=CNT_2_25MS_H)
		flag_2_25ms<=1'b1;
	else
		flag_2_25ms<=1'b0;
		
	//计数4.5ms
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		flag_4_5ms<=1'b0;
	else if(state==S_JUDGE && cnt>=CNT_4_5MS_L && cnt<=CNT_4_5MS_H)
		flag_4_5ms<=1'b1;
	else
		flag_4_5ms<=1'b0;
		
	//计数9ms
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		flag_9ms<=1'b0;
	else if(state==S_T9 && cnt>=CNT_9MS_L && cnt<=CNT_9MS_H)
		flag_9ms<=1'b1;
	else
		flag_9ms<=1'b0;
		
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		state<=IDLE;
	else 
		case(state)
			IDLE:
				if(ifr_in_fall)
					state<=S_T9;
				else
					state<=IDLE;
			S_T9:
				if(ifr_in_rise && flag_9ms)
					state<=S_JUDGE;
				else if(ifr_in_rise && !flag_9ms)
					state<=IDLE;
				else 
					state<=S_T9;
			S_JUDGE:
				if(ifr_in_fall && flag_2_25ms)
					state<=S_REPEAT;
				else if(ifr_in_fall && flag_4_5ms)
					state<=S_IFR_DATA;
				else if(ifr_in_fall && !flag_2_25ms && !flag_4_5ms)
					state<=IDLE;
				else
					state<=S_JUDGE;
			S_IFR_DATA:
				if(ifr_in_rise && !flag_0_56ms)
					state<=IDLE;
				else if(ifr_in_fall && !flag_0_56ms && !flag_1_69ms)
					state<=IDLE;
				else if(ifr_in_rise && data_cnt==6'd32)
					state<=IDLE;
			S_REPEAT:
				if(ifr_in_rise)
					state<=IDLE;
				else
					state<=S_REPEAT;
			default:
				state<=IDLE;
		endcase
		
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		data_tmp<=1'b0;
	else if(state==S_IFR_DATA && ifr_in_fall && flag_0_56ms)
		data_tmp[data_cnt]<=1'b0;
	else if(state==S_IFR_DATA && ifr_in_fall && flag_1_69ms)
		data_tmp[data_cnt]<=1'b1;
	else
		data_tmp<=data_tmp;
		
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		data_cnt<=1'b0;
	else if(ifr_in_rise && data_cnt==6'd32)
		data_cnt<=1'b0;
	else if(ifr_in_fall && state==S_IFR_DATA)
		data_cnt<=data_cnt+1'b1;
	else
		data_cnt<=data_cnt;
		
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		repeat_en<=1'b0;
	else if(state==S_REPEAT && data_tmp[23:16]==~data_tmp[31:24])
		repeat_en<=1'b1;
	else
		repeat_en<=1'b0;
		
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		data<=1'b0;
	else if(data_tmp[23:16]==~data_tmp[31:24] && data_tmp[7:0]==~data_tmp[15:8] && data_cnt==6'd32)
		data<={12'b0,data_tmp[23:16]};

endmodule 

3.led灯控制模块

module led_ctrl(
	input wire repeat_en,
	input wire sys_clk,
	input wire sys_rst_n,
	
	output reg led
);
	parameter CNT_MAX=2500_000;

	reg repeat_en_d1;
	reg repeat_en_d2;
	reg cnt_en;
	reg [21:0]cnt;
	
	wire repeat_en_rise;

	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)begin
		repeat_en_d1<=1'b0;
		repeat_en_d2<=1'b0;
	end
	else begin
		repeat_en_d1<=repeat_en;
		repeat_en_d2<=repeat_en_d1;
	end
	
	assign repeat_en_rise=repeat_en_d1 && ~repeat_en_d2;
	
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		cnt<=1'b0;
	else if(cnt_en)
		cnt<=cnt+1'b1;
	else 
		cnt<=1'b0;
	
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		cnt_en<=1'b0;
	else if(repeat_en_rise)
		cnt_en<=1'b1;
	else if(cnt==CNT_MAX-1)
		cnt_en<=1'b0;
	
	always @(posedge sys_clk or negedge sys_rst_n)
	if(!sys_rst_n)
		led<=1'b0;
	else if(cnt>0)
		led<=1'b1;
	else 
		led<=1'b0;

endmodule 

4.数码管控制模块

①二进制转8421BCD模块

module bcd_8421(

	input wire clk,
	input wire rst_n,
	input wire [19:0]data,
	
	output reg [3:0]unit,
	output reg [3:0]ten,
	output reg [3:0]hun,
	output reg [3:0]tho,
	output reg [3:0]t_tho,
	output reg [3:0]h_hun

);

	reg [4:0]cnt_shift;
	reg [43:0]data_shift;
	reg shift_flag;

	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		cnt_shift<=1'b0;
	else if(cnt_shift==5'd21 && shift_flag)
		cnt_shift<=1'b0;
	else if(shift_flag)
		cnt_shift<=cnt_shift+1'b1;
	else
		cnt_shift<=cnt_shift;
		
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		data_shift<=1'b0;
	else if(!cnt_shift)
		data_shift<={24'd0,data};
	else if(cnt_shift<=20 && (!shift_flag))
		begin
			data_shift[23:20]<=(data_shift[23:20]>4)? (data_shift[23:20]+2'd3):(data_shift[23:20]);
			data_shift[27:24]<=(data_shift[27:24]>4)? (data_shift[27:24]+2'd3):(data_shift[27:24]);
			data_shift[31:28]<=(data_shift[31:28]>4)? (data_shift[31:28]+2'd3):(data_shift[31:28]);
			data_shift[35:32]<=(data_shift[35:32]>4)? (data_shift[35:32]+2'd3):(data_shift[35:32]);
			data_shift[39:36]<=(data_shift[39:36]>4)? (data_shift[39:36]+2'd3):(data_shift[39:36]);
			data_shift[43:40]<=(data_shift[43:40]>4)? (data_shift[43:40]+2'd3):(data_shift[43:40]);
		end
	else if(cnt_shift<=5'd20 && shift_flag)
		data_shift<=data_shift<<1;
	else
		data_shift<=data_shift;
		
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		shift_flag<=1'b0;
	else
		shift_flag<=~shift_flag;
		
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		begin
			unit<=1'b0;
		   ten<=1'b0;
		   hun<=1'b0;
			tho<=1'b0;
		   t_tho<=1'b0;
		   h_hun<=1'b0;
		end
	else if(cnt_shift==5'd21)
		begin
			unit<=data_shift[23:20];
		   ten<=data_shift[27:24];
		   hun<=data_shift[31:28];
			tho<=data_shift[35:32];
		   t_tho<=data_shift[39:36];
		   h_hun<=data_shift[43:40];
		end

endmodule 

②数码管控制模块

module seg
#(
	parameter CNT_MAX=16'd49999 //49999
)
(

	input wire clk,
	input wire rst_n,
	input wire [5:0]point,
	input wire [19:0]data,
	input wire seg_en,
	input wire sign,
	
	output reg [5:0]sel,
	output reg [7:0]seg

);

	wire [3:0]unit;
   wire [3:0]ten;
   wire [3:0]hun;
   wire [3:0]tho;
   wire [3:0]t_tho;
	wire [3:0]h_hun;

	bcd_8421 bcd_8421(

		.clk(clk),
		.rst_n(rst_n),
		.data(data),
		
		.unit(unit),
		.ten(ten),
		.hun(hun),
		.tho(tho),
		.t_tho(t_tho),
		.h_hun(h_hun)

	);



	reg [23:0]data_reg;
	reg [15:0]cnt_1ms;
	reg flag_1ms;
	reg [2:0]cnt_sel;
	reg [5:0]sel_reg;
	reg [3:0]data_disp;
	reg dot_disp;
	
	//控制数码管显示
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		data_reg<=1'b0;
	//若显示的十万位为非零数据或需要显示小数点,六个数码管全显示
	else if(h_hun || point[5])
		data_reg<={h_hun,t_tho,tho,hun,ten,unit};
	//若显示的万位数为非零数据或需要显示小数点,数值显示在5个数码管上
	else if((t_tho || point[4]) && sign)//显示负号
		data_reg<={4'd10,t_tho,tho,hun,ten,unit};//定义4'd10为显示负号
	else if((t_tho || point[4]) && !sign)
		data_reg<={4'd11,t_tho,tho,hun,ten,unit};//定义4‘d11为不显示
	//若显示的千位数为非零数据或需要显示小数点,数值显示在4个数码管上
	else if((tho || point[3]) && sign)
		data_reg<={4'd11,4'd10,tho,hun,ten,unit};
	else if((tho || point[3]) && !sign)
		data_reg<={4'd11,4'd11,tho,hun,ten,unit};
	//若显示的百位数为非零数据或需要显示小数点,数值显示在3个数码管上
	else if((hun || point[2]) && sign)
		data_reg<={4'd11,4'd11,4'd10,hun,ten,unit};
	else if((hun || point[2]) && !sign)
		data_reg<={4'd11,4'd11,4'd11,hun,ten,unit};
	//若显示的十位数为非零数据或需要显示小数点,数值显示在2个数码管上
	else if((ten || point[2]) && sign)
		data_reg<={4'd11,4'd11,4'd11,4'd10,ten,unit};
	else if((ten || point[2]) && !sign)
		data_reg<={4'd11,4'd11,4'd11,4'd11,ten,unit};
	//若显示的个位数为非零数据或需要显示小数点,数值显示在1个数码管上
	else if((unit || point[1]) && sign)
		data_reg<={4'd11,4'd11,4'd11,4'd11,4'd10,unit};
	else 
		data_reg<={4'd11,4'd11,4'd11,4'd11,4'd11,unit};
	
	//计数器计数1ms
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		cnt_1ms<=1'b0;
	else if(cnt_1ms==CNT_MAX)
		cnt_1ms<=1'b0;
	else 
		cnt_1ms<=cnt_1ms+1'b1;
		
	//计数标志位
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		flag_1ms<=1'b0;
	else if(cnt_1ms==CNT_MAX-1'b1)
		flag_1ms<=1'b1;
	else
		flag_1ms<=1'b0;
		
	//cnt_sel:从0到5的循环,用于选择当前显示的数码管
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		cnt_sel<=1'b0;
	else if(cnt_sel==3'b101 && flag_1ms)
		cnt_sel<=1'b0;
	else if(flag_1ms)
		cnt_sel<=cnt_sel+1'b1;
	else
		cnt_sel<=cnt_sel;
		
	//数码管位选信号寄存器
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		sel_reg<=6'b000_000;
	else if(!cnt_sel && flag_1ms)
		sel_reg<=6'b000_001;
	else if(flag_1ms)
		sel_reg<=sel_reg<<1;
	else
		sel_reg<=sel_reg;
		
	//控制数码管的位选信号,使六个数码管轮流显示
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		data_disp<=1'b0;
	else if(seg_en && flag_1ms)
		case(cnt_sel)
			3'd0:data_disp<=data_reg[3:0];
			3'd1:data_disp<=data_reg[7:4];
			3'd2:data_disp<=data_reg[11:8];
			3'd3:data_disp<=data_reg[15:12];
			3'd4:data_disp<=data_reg[19:16];
			3'd5:data_disp<=data_reg[23:20];
			default:data_disp<=1'b0;
		endcase
	else
		data_disp<=data_disp;
		
	//dot_disp:小数点低电平点亮,需对小数点有效信号取反
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		dot_disp<=1'b1;
	else if(flag_1ms)
		dot_disp<=~point[cnt_sel];
	else
		dot_disp<=dot_disp;

	//控制数码管段选信号,显示数字
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		seg<=8'b1111_1111;
	else
		case(data_disp)
			4'd0:seg<={dot_disp,7'b100_0000};
			4'd1:seg<={dot_disp,7'b111_1001};
			4'd2:seg<={dot_disp,7'b010_0100};
			4'd3:seg<={dot_disp,7'b011_0000};
			4'd4:seg<={dot_disp,7'b001_1001};
			4'd5:seg<={dot_disp,7'b001_0010};
			4'd6:seg<={dot_disp,7'b000_0010};
			4'd7:seg<={dot_disp,7'b111_1000};
			4'd8:seg<={dot_disp,7'b000_0000};
			4'd9:seg<={dot_disp,7'b001_0000};
			4'd10:seg<=8'b1011_1111;
			4'd11:seg<=8'b1111_1111;
			default:seg<=8'b1100_0000;
		endcase

	//sel:数码管位选信号赋值
	always @(posedge clk or negedge rst_n)
	if(!rst_n)
		sel<=6'b000_000;
	else
		sel<=~sel_reg;
		
endmodule 

5.顶层代码

module infrared_rcv_top(
	input wire sys_clk,
	input wire sys_rst_n,
	input wire infrared_in,
	
	output wire led,
	output wire [5:0]sel,
	output wire [7:0]seg
);

	wire [19:0]data;
	wire repeat_en;

	infrared_rcv infrared_rcv_inst(
		.sys_clk(sys_clk),
		.sys_rst_n(sys_rst_n),
		.infrared_in(infrared_in),
		
		.data(data),
		.repeat_en(repeat_en)
	);
	
	led_ctrl led_ctrl_inst(
		.repeat_en(repeat_en),
		.sys_clk(sys_clk),
		.sys_rst_n(sys_rst_n),
		
		.led(led)
	);
	
	seg
	#(
		.CNT_MAX(16'd49999) //49999
	)
	seg_inst(

		.clk(sys_clk),
		.rst_n(sys_rst_n),
		.point(6'd0),
		.data(data),
		.seg_en(1'b1),
		.sign(1'b0),
		
		.sel(sel),
		.seg(seg)

	);

endmodule 

6.RTL视图

在这里插入图片描述

三、仿真测试模块

1.仿真测试模块代码

`timescale 1ns/1ns
`define clk_period 20

module infrared_rcv_top_tb;

	reg sys_clk;
	reg sys_rst_n;
	reg infrared_in;
	
	wire led;
	wire [5:0]sel;
	wire [7:0]seg;

	infrared_rcv_top infrared_rcv_top_inst(
		.sys_clk(sys_clk),
		.sys_rst_n(sys_rst_n),
		.infrared_in(infrared_in),
		
		.led(led),
		.sel(sel),
		.seg(seg)
	);
	
	initial sys_clk=1'b1;
	always #(`clk_period/2) sys_clk=~sys_clk;
	
	initial
    begin
        sys_rst_n   <=  1'b0;
        infrared_in <=  1'b1;
        #100
        sys_rst_n   <=  1'b1;
//引导码
        #1000
        infrared_in <=  1'b0; #9000000
        infrared_in <=  1'b1; #4500000
//地址码(发送地址码8’h99)
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//地址反码(地址反码为8’h66)
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据码(发送数据码8’h22)
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据反码(数据反码为8’hdd)
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据0
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #560000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//数据1
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #1690000
//重复码
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1; #42000000
        infrared_in <=  1'b0; #9000000
        infrared_in <=  1'b1; #2250000
        infrared_in <=  1'b0; #560000
        infrared_in <=  1'b1;
		  
	
endmodule 

2.仿真波形图

在这里插入图片描述

四、可能遇到的问题

仿真通过了但是按了遥控器之后没有数据显示:可能原因:选用的红外接收头有问题,正常可以使用的红外接收头引脚处还要接有某些电容电路,因此最好使用上面提到的模块进行实验。

  • 2
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
FPGA 红外遥控代码主要涉及到两个方面:红外信号的发送和接收。下面分别介绍这两个方面的代码实现。 ## 红外信号发送 红外信号发送需要用到一个红外发射二极管,它能够将FPGA输出的数字信号转换为红外信号并发射出去。以下是一个基于Verilog HDL的红外信号发送代码示例: ``` module ir_transmitter ( input clk, // 时钟信号 input rst, // 复位信号 output reg ir_out, // 红外发射信号 input btn // 按钮信号 ); reg [15:0] cnt; // 计数器,用于控制红外信号的发送 reg [3:0] state; // 状态机状态变量,用于控制红外信号发送的不同阶段 always @(posedge clk) begin if(rst) begin cnt <= 0; ir_out <= 0; state <= 0; end else begin case(state) 0: begin // 空闲状态 cnt <= 0; ir_out <= 0; if(btn == 1) begin state <= 1; end end 1: begin // 发送起始信号 ir_out <= 1; if(cnt >= 5000) begin cnt <= 0; state <= 2; end else begin cnt <= cnt + 1; end end 2: begin // 发送数据信号 if(cnt <= 100) begin ir_out <= 1; end else if(cnt <= 200) begin ir_out <= 0; end else begin cnt <= 0; state <= 3; end cnt <= cnt + 1; end 3: begin // 发送结束信号 ir_out <= 1; if(cnt >= 5000) begin cnt <= 0; state <= 0; end else begin cnt <= cnt + 1; end end default: begin cnt <= 0; ir_out <= 0; state <= 0; end endcase end end endmodule ``` 上述代码实现了一个红外信号发送器。当 FPGA 开发板上的按钮被按下时,会触发红外信号的发送。信号发送分为三个阶段:发送起始信号、发送数据信号和发送结束信号。在发送数据信号阶段,根据实际需求可以修改数据信号的发送逻辑。 ## 红外信号接收 红外信号接收需要用到一个红外接收头,它能够将接收到的红外信号转换为数字信号并输入到FPGA中。以下是一个基于Verilog HDL的红外信号接收代码示例: ``` module ir_receiver ( input clk, // 时钟信号 input rst, // 复位信号 input ir_in, // 红外接收信号 output reg [3:0] data_out // 接收到的数据 ); reg [3:0] state; // 状态机状态变量,用于控制红外信号接收的不同阶段 reg [15:0] cnt; // 计数器,用于控制红外信号的接收 always @(posedge clk) begin if(rst) begin state <= 0; cnt <= 0; data_out <= 0; end else begin case(state) 0: begin // 空闲状态 cnt <= 0; if(ir_in == 0) begin state <= 1; end end 1: begin // 接收起始信号 if(cnt >= 6000 && ir_in == 1) begin cnt <= 0; state <= 2; end else if(cnt >= 10000) begin cnt <= 0; state <= 0; end else begin cnt <= cnt + 1; end end 2: begin // 接收数据信号 if(cnt <= 100) begin data_out <= {data_out[2:0], ir_in}; end else if(cnt >= 10000) begin cnt <= 0; state <= 0; end cnt <= cnt + 1; end default: begin cnt <= 0; state <= 0; data_out <= 0; end endcase end end endmodule ``` 上述代码实现了一个红外信号接收器。当红外接收头接收到红外信号时,会触发红外信号的接收。信号接收分为三个阶段:接收起始信号、接收数据信号和接收结束信号。在接收数据信号阶段,根据实际需求可以修改数据信号的接收逻辑。接收到的数据存储在 `data_out` 变量中,可以根据实际需求处理这些数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值