红外遥控解码

1.红外遥控特点以及硬件介绍

1.1红外遥控特点

红外线遥控器就是利用波长 0.76μm~1.5μm 之间的近红外线来传送控制信号的。红外线的特点是不干扰其他电器设备工作,也不会影响周边环境,若对发射信号进行编码,可实现多路红外遥控功能。
鉴于家用电器的品种多样化和用户的使用特点,生产厂家对红外遥控器的信号传输进行了严格的规范编码,这些编码各不相同,从而形成不同的编码方式,统一称为红外遥控器编码传输协议。 到目前为止红外遥控协议已多达十种, 但使用最为广泛的为 NEC 协议。

1.2红外遥控硬件

红外发射部分电路包括矩阵键盘、红外发光二极管、编码以及调制电路等,红外接收部分包括光敏二极管、解调以及解码电路等。使用一体化接收头时只需对其输出的信号进行解码操作。
在这里插入图片描述
在这里插入图片描述

2.红外遥控协议分析(NEC协议)

基于 HT6221 芯片的红外遥控发送一次数据的数据帧定义如下图所示:一帧数据由帧头、地址码(有的资料上是说地址码加地址反码)、数据码、数据反码以及 1bit 结束位(可忽略)组成。
在这里插入图片描述
其中,引导码由 9ms 高电平的头码和 4.5ms 低电平的间隙组成,其代表一个数据帧的帧头;地址码共 16 位,低位在前,高位在后。因此,NEC 协议理论上支持最高 65536 个不同的用户;8 位数据码及其反码也是低位在前,高位在后。因此,理论上该协议支持高达 256 个用户指令。该协议采用脉冲之间不同时长的时间间隔来区分“1”和“0”,下图为其编码协议中“1”和“0”的编码波形。
在这里插入图片描述
而在实际接收时,接收头接收到信号后输出的波形刚好与此波形反相。因此,本模块的设计实际就是对下图 1 以及下图 2 波形的提取。数据 0 是 0.56ms 的低电平和 0.56ms 的高电平,数据 1 是 0.56ms 的低电平和 1.69ms 的高电平。可见 0 和 1 的区别在于高电平持续时间的长短不同,根据这个区别就可以见别出 0 和 1 了。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3.红外遥控接口模块设计

3.1接口设计

在这里插入图片描述

引脚功能
sclk时钟
rst_n复位信号
ir_data[7:0]解码后的数据
ir_addr[15:0]解码后的地址,若为8位地址则取低八位
repeat_en长按重复信号,单周期
dec_done解码完成标志

3.2模块关键功能分析

解码的关键是对引导码(9ms低电平,4.5ms高电平)和32位地址码、数据码、数据反码的识别(0:0.56ms低电平和0.56ms高电平)(1:0.56ms低电平和1.69ms的高电平)。
在这里插入图片描述

所以需要计数器对这几个时间进行计数。因为每个厂家晶振精度不一样,因此计数器的值是一个范围。
异步信号需打拍。

4.程序设计

4.1.状态机设计

在这里插入图片描述

此程序改编自野火教程。
增加了cnt计数器溢出(9ms)状态机复位。
增加了data_cnt在传输异常复位到IDLE状态时的清零过程。防止错误累加。

// FPGA   : 小梅哥AC620
// EDA 	  : Quartus II 13.0sp1 (64-bit) and ModelSim SE-64 10.5 
// Author : FPGA小白758 https://blog.csdn.net/q1594?spm=1010.2135.3001.5343
// File   : infrared_rcv.v
// Create : 2022-05-12 14:58:41
// Revise : 2022-05-14 19:23:43
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
module	infrared_rcv(
	input	wire				sclk			,	//系统时钟
	input	wire				rst_n			,	//复位信号
	input	wire				infrared_in		,	//一体化接收头接受到的数据

	output	reg 	[ 7:0]		ir_data			,	//解码得到的数据码
	output	reg 	[15:0]		ir_addr			,	//解码得到的16位地址码或者地址码(低八位)和地址反码(高八位)
	output	reg					repeat_en 		,	//重复码
	output	reg 				dec_done			//解码完成标志信号
);

//parameter	define
parameter	CNT_560US_L			=	20_000		;
parameter	CNT_560US_H 		=	35_000		; 	//0.56ms计数
parameter	CNT_1690US_L 		=	80_000		;
parameter	CNT_1690US_H		=	90_000 		; 	//1.69ms计数
parameter	CNT_2250US_L 		=	100_000		;
parameter	CNT_2250US_H 		=	125_000		; 	//2.25ms计数
parameter	CNT_4500US_L 		=	175_000		;
parameter	CNT_4500US_H 		=	275_000		; 	//4.5ms计数
parameter	CNT_9MS_L 			=	400_000		;
parameter	CNT_9MS_H 			=	490_000 	; 	//9ms计数


//state
parameter	IDLE 				=	5'b0_0001 	; 	//空闲状态
parameter	S_T9 				=	5'b0_0010 	; 	//检测引导码低电平
parameter	S_JUDGE 			=	5'b0_0100 	; 	//判断是重复码还是引导码高电平
parameter	S_IFR_DATA 			=	5'b0_1000 	; 	//接受数据
parameter	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_560us 						;	//0.56ms计数完成标志信号
reg				flag_1690us 					;	//1.69ms计数完成标志信号
reg 			flag_2250us 					;	//2.25ms计数完成标志信号
reg				flag_4500us						;	//4.5ms计数完成标志信号
reg				flag_9ms 						;	//9ms计数完成标志信号
reg		[4:0]	state 							;	//状态机
reg		[5:0]	data_cnt 						; 	//数据计数器
reg 	[31:0]	data_tmp 						;	//数据寄存器
reg 			dec_done_reg 					;	//传输完成前一拍

//打拍
always @(posedge sclk) begin
	{infrared_in_d2,infrared_in_d1} <= {infrared_in_d1,infrared_in};
	dec_done <= dec_done_reg;
end

//检测上升沿和下降沿
assign ifr_in_rise = (infrared_in_d1 & ~infrared_in_d2);
assign ifr_in_fall = (~infrared_in_d1 & infrared_in_d2);

//状态跳转
always @(posedge sclk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		state <= IDLE;
	end
	else case(state)
		IDLE 	: 	if(ifr_in_fall == 1'b1)//检测到下降沿到来,继续检测是否有9ms的低电平
						state <= S_T9;
					else begin
						state <= IDLE;
					end
		S_T9 	:	if((ifr_in_rise == 1'b1) && (flag_9ms == 1'b1))//检测到上升沿到来且下降沿时间保持为9ms
						state <= S_JUDGE;
					else if((ifr_in_rise == 1'b1 && flag_9ms == 1'b0) || (cnt > CNT_9MS_H)) begin//检测到上升沿到来且低电平保持时间不是9ms
						state <= IDLE;
					end
					else begin
						state <= S_T9;
					end
		S_JUDGE : 	if(ifr_in_fall == 1'b1 && flag_2250us == 1'b1)begin  //下降沿到来且上升沿保持2.25ms 跳转重复码状态
						state <= S_REPEAT; 			
					end
					else if((ifr_in_fall == 1'b1) && (flag_4500us == 1'b1))begin //下降沿到来上升沿保持时间4.5ms.开始接收数据
						state <= S_IFR_DATA;
					end
					else if((ifr_in_fall == 1'b1 && (flag_2250us == 1'b0 && flag_4500us == 1'b0))  || (cnt > CNT_9MS_H))begin//下降沿到来时间均不满足,回到IDLE
						state <= IDLE;
					end
					else begin
						state <= S_JUDGE;
					end
		S_IFR_DATA:	if((ifr_in_rise == 1'b1 && flag_560us == 1'b0) || (cnt > CNT_9MS_H))begin //上升沿到来,低电平保持时间不是0.56ms,跳出
						state <= IDLE;
					end
					else if((ifr_in_fall == 1'b1) && (flag_560us == 1'b0 && flag_1690us == 1'b0)) begin//下降沿到来,高电平保持时间不是0.56ms或者1.69ms,跳出
						state <= IDLE;
					end
					else if ((ifr_in_rise == 1'b1) && (data_cnt == 6'd32)) begin //上升沿到来,数据接收完毕,跳出
						state <= IDLE;
					end
		S_REPEAT  : if((ifr_in_rise == 1'b1) || (cnt > CNT_9MS_H))begin
						state <= IDLE;
					end
					else begin
						state <= S_REPEAT;
					end
		default 	: 	state <= IDLE;
	endcase
end

//状态输出

//cnt
always @(posedge sclk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		cnt <= 'd0;
	end
	else if(state == IDLE)begin
		cnt <= 'd0;
	end
	else if (ifr_in_rise == 1'b1 || ifr_in_fall == 1'b1) begin
		cnt <= 'd0;
	end
	else begin
		cnt <= cnt + 1'b1;
	end
end


//时间计数器拉高标志信号,范围拉高
always @(posedge sclk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		flag_560us 		<= 	1'b0;
		flag_1690us 	<= 	1'b0;
		flag_2250us		<=	1'b0;
		flag_4500us 	<=	1'b0;
		flag_9ms 		<=	1'b0;
	end
	else if (state == S_IFR_DATA && cnt >= CNT_560US_L && cnt <= CNT_560US_H) begin
		flag_560us <= 1'b1;
	end
	else if (state == S_IFR_DATA && cnt >= CNT_1690US_L && cnt <= CNT_1690US_H) begin
		flag_1690us <= 1'b1;
	end
	else if (state == S_JUDGE && cnt >= CNT_2250US_L && cnt <= CNT_2250US_H)begin
		flag_2250us <= 1'b1;
	end
	else if(state == S_JUDGE && cnt >= CNT_4500US_L && cnt <= CNT_4500US_H)begin
		flag_4500us <= 1'b1;
	end
	else if (state == S_T9 && cnt >= CNT_9MS_L && cnt <= CNT_9MS_H)begin
		flag_9ms <= 1'b1;
	end
	else begin
		flag_560us 		<= 	1'b0;
		flag_1690us 	<= 	1'b0;
		flag_2250us		<=	1'b0;
		flag_4500us 	<=	1'b0;
		flag_9ms 		<=	1'b0;
	end
end

//data_cnt
always @(posedge sclk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		data_cnt <= 'd0;
	end
	else if (ifr_in_rise == 1'b1 && data_cnt == 6'd32) begin
		data_cnt <= 'd0;
	end
	else if(ifr_in_fall == 1'b1 && state == S_IFR_DATA) begin
		data_cnt <= data_cnt + 1'b1;
	end
	else if(state == S_IFR_DATA)begin
		data_cnt <= data_cnt;
	end
	else begin
		data_cnt <= 'd0;
	end
end

//data_tmp
always @(posedge sclk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		data_tmp <= 32'b0;
	end
	else if (state == S_IFR_DATA && ifr_in_fall == 1'b1 && flag_560us == 1'b1) begin
		data_tmp[data_cnt] <= 1'b0;
	end
	else if (state == S_IFR_DATA && ifr_in_fall == 1'b1 && flag_1690us == 1'b1) begin
		data_tmp[data_cnt] <= 1'b1;
	end
end

//repeat_en
always @(posedge sclk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		repeat_en <= 1'b0;
	end
	else if (state == S_REPEAT && (data_tmp[23:16] == ~data_tmp[31:24]) && ifr_in_rise == 1'b1) begin
		repeat_en <= 1'b1;
	end
	else begin
		repeat_en <= 1'b0;
	end
end

//ir_addr 、ir_data
always @(posedge sclk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		ir_addr <= 'd0;
		ir_data <= 'd0;
	end
	else if (dec_done_reg == 1'b1) begin
		ir_addr <= data_tmp[15:0];
		ir_data <= data_tmp[23:16];
	end
end

//dec_done
always @(posedge sclk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		dec_done_reg <= 1'b0;
	end
	else if (state == S_IFR_DATA && data_cnt == 'd32 && data_tmp[23:16] == ~data_tmp[31:24] && cnt == 'd0) begin
		dec_done_reg <= 1'b1;
	end
	else begin
		dec_done_reg <= 1'b0;
	end
end
endmodule
  • 3
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于STM32红外遥控器系统设计与实现是一个利用STM32微控制器来控制红外遥控器操作的系统。该系统使用红外发射器和接收器,实现了对各种电子设备的遥控操作。 首先,设计阶段需要确定系统的硬件和软件需求。硬件方面,选择STM32微控制器作为主控芯片,并添加红外发射器和接收器作为输入输出设备。软件方面,需要设计一个用户友好的界面,实现按键输入和红外信号解析等功能。可以使用Keil或者STM32CubeMX等开发平台进行软件开发。 接下来,根据硬件需求,进行系统的硬件设计和制作。这包括布局电路板,焊接元件,连接外部设备等。关键是正确连接和配置红外发射器和接收器,确保它们能够正常工作。 在软件设计阶段,首先需要编写STM32的驱动程序,包括GPIO、USART、IR红外协议等驱动。然后设计用户界面,包括按键解析、菜单选择等功能。同时,需要编写红外信号解析的程序,实现对红外遥控指令的接收和解析。 在实现阶段,将软件烧录到STM32芯片中,并进行调试。首先测试按键输入是否能够在界面上显示,并能够正确响应。然后测试红外遥控器能否发送正确的红外信号,并能够通过红外接收器接收并解析。 最后,进行系统的优化和完善。对界面进行美化和优化,提高系统的响应速度和稳定性。调整红外信号解析算法,提高红外信号的接收和解析准确性。 总结来说,基于STM32红外遥控器系统设计与实现主要涉及硬件设计、软件开发和系统调试。通过正确连接和配置红外发射器和接收器,实现用户界面的设计和红外信号解析的功能,可以很好地完成红外遥控器系统的设计与实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值