红外遥控解码设计与验证VHDL

本文介绍了一种红外遥控解码的设计与验证方法,基于VHDL编程,涉及NEC协议的解析。实验中使用Quartus ii 18.0和AC620开发板,通过检测特定时序来识别0/1数据,实现红外信号的解码。文中还详细描述了VHDL代码实现的状态机逻辑,并提供了仿真和板级验证的结果。

实验器材

Quartus ii 18.0
小梅哥AC620开发板
红外遥控器

实验背景

红外线遥控器利用波长为0.76μm ~ 1.5 μm 的近红外线来传送信号。红外线的特点是不干扰其他电器设备工作,也不会影响周边环境。比如不同的电视遥控器只能控制对应的电视,这是因为不同的电视遥控器对应一个不同的地址。不同的家用电器有不同的编码方式,统称为红外遥控器编码传输协议,使用最多的为NEC协议。

实验原理

红外发射部分电路包括矩阵键盘,红外发光二极管,编码以及调制电路,这些都已经集成在红外遥控器上(遥控器示意图如下图所示)。接收部分包括光敏二极管,解调以及解码电路。在本实验中,我们仅需要对其输出的信号进行解码操作。
遥控

NEC协议

HT6221为Holtek公司生产的一款基于NEC红外通信协议的遥控编码芯片,采用Pulse Position Modulation(PPM)进行编码。HT6221芯片的红外遥控发送一次数据的数据帧定义如下图所示:一帧数据:帧头,16位地址码,8位数据码,8位数据反码以及1bit结束位(可忽略)组成。
数据帧

数据发送:

引导码由9ms高电平和4.5ms的低电平构成,代码一个数据帧的帧头;
地址码由16位地址构成,低8位在前,高8位在后(对于一个红外遥控器,地址为固定值)。所以NEC协议理论上能最多支持65536个不同的用户。
数据码由数据原码和数据反码构成(可以通过比较这两个8位数据检测数据接收是否正确)。所以理论上支持256种指令。

数据发送0/1:
数据发送1: 560μs高电平+1.69ms低电平
数据发送0: 560μs高电平+560μs低电平
0/1

数据接收:

对于数据接收端,接收到信号之后再输出的波形和输入端发送的波形反相。因此对于FPGA中接收端输出的波形为: 9ms低+4.5ms高 + 0.56ms 低+ 1.69ms高(1)/ 0.56ms高(0)。本模块就是检测此波形然后输出数据(由于红外传感器的品质不同,因此本模块的检测时间为一个区间范围

接收01
当按键长按时输出的波形如下图所示,本模块只进行短按时数据波形设计。
long

VHDL代码实现

由于红外遥控器按键的时序和接收端不同,因此需要先对接收到的红外信号进行时钟同步(采用两级FF):

process(clk,nrst)
begin
	if(nrst = '0')then
		IR_temp1	<= '0';
		IR_temp2	<= '0';
	elsif( rising_edge(clk)) then
		IR_temp1 <= iIR;
		IR_temp2	<= IR_temp1;
	end if;
end process;

对同步的输入信号进行边沿检测(和上面代码一致):

process(clk,nrst)
begin
	if(nrst = '0')then
		edge_temp1	<= '0';
		edge_temp2	<= '0';
	elsif( rising_edge(clk)) then
		edge_temp1 <= IR_temp2;
		edge_temp2 <= edge_temp1;
	end if;
end process;

pose_edge <= (not edge_temp2) and edge_temp1;
fall_edge <= edge_temp2 and (not edge_temp1);

时钟计数器(用于9ms, 4.5ms, 1.69ms, 0.56ms的计数)

process(clk,nrst)
begin
	if(nrst = '0')then
		cnt <= 0;
	elsif(rising_edge(clk))then
		if(cnt_en = '1') then
			cnt <= cnt + 1;
		else
			cnt <= 0;
		end if;
	end if;
end process;

计数时间超时(当计数器的时间已经超过10ms说明出现错误)timeout标志信号

process(clk,nrst)
begin
	if(nrst = '0')then
		timeout <= '0';
	elsif(rising_edge(clk))then
		if(cnt > 500000) then			-- cnt >10 ms超时信号置1
			timeout <= '1';
		else
		
<think>根据用户需求,需要提供使用VHDL实现红外遥控的方法和代码示例。参考站内引用,其中提到红外编码格式、接收头选择、FPGA硬件设计、时序分析等技术点。结合红外遥控的常见协议(如NEC协议),以下将分步骤说明实现方法并提供关键部分的VHDL代码示例。 ### 1. 红外遥控基本原理 红外遥控通常使用载波调制,常见载波频率为38kHz(NEC协议)。信号格式包含: - **引导码**:9ms高电平+4.5ms低电平(NEC协议) - **数据码**:32位(16位地址+16位命令),采用脉冲位置调制(PPM) - **重复码**:9ms高电平+2.25ms低电平(用于长按) ### 2. VHDL实现步骤 #### (1) 红外接收模块设计 - 使用红外接收头(如VS1838B)将38kHz载波解调为数字信号。 - FPGA通过GPIO引脚接收解调后的信号。 - 关键:检测下降沿作为数据起始标志。 #### (2) 状态机设计 定义状态机处理红外信号: ```vhdl type state_type is (IDLE, LEADER_CODE, DATA_BIT, REPEAT_CODE); signal current_state : state_type := IDLE; ``` 状态转移: - `IDLE`:等待下降沿,检测到后进入`LEADER_CODE`。 - `LEADER_CODE`:验证引导码时长(9ms高+4.5ms低)。 - `DATA_BIT`:接收32位数据(每位560μs低电平起始,后续高电平表示0/1)。 - `REPEAT_CODE`:处理重复码(长按情况)。 #### (3) 时序测量 使用计数器测量高低电平持续时间: ```vhdl signal counter : integer range 0 to 1000000 := 0; -- 假设时钟50MHz(20ns周期) process(clk) begin if rising_edge(clk) then if ir_signal = '1' then counter <= counter + 1; -- 计数高电平 else counter <= 0; -- 遇到低电平复位计数器(或根据状态处理) end if; end if; end process; ``` #### (4) 数据解码 在`DATA_BIT`状态下,每位的判定: - 560μs低电平后,高电平时长决定数值: - 560μs高电平 → 逻辑0 - 1.68ms高电平 → 逻辑1 ### 3. VHDL代码示例(关键部分) ```vhdl library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity ir_decoder is Port ( clk : in STD_LOGIC; -- 系统时钟(50MHz) ir_input : in STD_LOGIC; -- 红外接收头输入 data_out : out STD_LOGIC_VECTOR(31 downto 0); -- 解码数据 valid : out STD_LOGIC -- 数据有效标志 ); end ir_decoder; architecture Behavioral of ir_decoder is type state_type is (IDLE, LEADER_HIGH, LEADER_LOW, DATA_BIT, REPEAT); signal state : state_type := IDLE; signal counter : integer := 0; signal bit_counter : integer range 0 to 31 := 0; signal shift_reg : STD_LOGIC_VECTOR(31 downto 0) := (others => '0'); begin process(clk) begin if rising_edge(clk) then case state is when IDLE => valid <= '0'; if ir_input = '0' then -- 检测下降沿(实际需消抖) counter <= 0; state <= LEADER_HIGH; end if; when LEADER_HIGH => -- 测量引导码高电平 if ir_input = '1' then counter <= counter + 1; else -- 高电平结束,判断是否≈9ms(50MHz下450000计数) if counter > 400000 and counter < 500000 then counter <= 0; state <= LEADER_LOW; else state <= IDLE; -- 无效引导码 end if; end if; when LEADER_LOW => -- 测量引导码低电平 if ir_input = '0' then counter <= counter + 1; else -- 低电平结束,判断是否≈4.5ms(225000计数) if counter > 200000 and counter < 250000 then counter <= 0; bit_counter <= 31; -- 准备接收32位数据(高位先收) state <= DATA_BIT; else state <= IDLE; end if; end if; when DATA_BIT => if ir_input = '0' then counter <= 0; else counter <= counter + 1; end if; -- 检测低电平结束(数据位开始) if ir_input'event and ir_input = '1' then -- 根据高电平时长判断数据位 if counter > 28000 then -- 约1.68ms(84000计数) shift_reg(bit_counter) <= '1'; -- 逻辑1 else shift_reg(bit_counter) <= '0'; -- 逻辑0 end if; if bit_counter = 0 then data_out <= shift_reg; valid <= '1'; state <= IDLE; else bit_counter <= bit_counter - 1; end if; end if; -- 重复码处理省略... end case; end if; end process; end Behavioral; ``` ### 注意事项 1. **消抖处理**:红外信号需添加消抖逻辑(如连续检测到多次相同电平)。 2. **时钟频率适配**:计数器阈值需根据实际系统时钟调整(示例基于50MHz)。 3. **协议兼容性**:不同遥控器协议(如RC5、Sony)需修改状态机逻辑。 ### 测试建议 - 使用仿真工具(如ModelSim)模拟红外信号输入。 - 实际测试时用逻辑分析仪抓取时序。 §§相关问题§§ 1. 如何处理红外遥控信号中的干扰和误码? 2. 如何扩展此解码器支持多种红外协议(如NEC、RC5)? 3. VHDL实现中如何优化资源占用和功耗? </think>以下是使用VHDL实现红外遥控解码的详细方法和代码示例,基于NEC协议(最常见的红外协议): ### 一、实现原理 1. **NEC协议时序**(标准38kHz载波): - **引导码**:9ms高电平 + 4.5ms低电平 - **数据位**:32位(地址码16位 + 命令码16位) - **逻辑0**:560μs低电平 + 560μs高电平 - **逻辑1**:560μs低电平 + 1.68ms高电平 - **重复码**:9ms高电平 + 2.25ms低电平(长按键)[^1] 2. **FPGA处理流程**: ```mermaid graph TD A[红外接收头] --> B[信号整形] B --> C[状态机解码] C --> D[数据校验] D --> E[输出按键值] ``` ### 二、VHDL核心代码示例 #### 1. 实体定义(Entity) ```vhdl library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity IR_Receiver is Port ( clk : in STD_LOGIC; -- 系统时钟(50MHz) ir_input : in STD_LOGIC; -- 红外信号输入 data_out : out STD_LOGIC_VECTOR(31 downto 0); -- 32位解码数据 valid : out STD_LOGIC -- 数据有效标志 ); end IR_Receiver; ``` #### 2. 状态机架构(Architecture) ```vhdl architecture Behavioral of IR_Receiver is -- 状态定义 type state_type is ( IDLE, -- 空闲状态 LEADER_HIGH, -- 检测引导码高电平 LEADER_LOW, -- 检测引导码低电平 DATA_BIT, -- 数据位处理 REPEAT -- 重复码处理 ); signal state : state_type := IDLE; signal counter : integer := 0; -- 时钟计数器 signal bit_index : integer := 0; -- 当前数据位索引 signal data_reg : STD_LOGIC_VECTOR(31 downto 0) := (others => '0'); -- 时间常数(50MHz时钟) constant LEADER_HIGH_MIN : integer := 450000; -- 9ms (9000us) constant LEADER_HIGH_MAX : integer := 500000; -- 容差范围 constant LEADER_LOW_MIN : integer := 225000; -- 4.5ms (4500us) begin process(clk) begin if rising_edge(clk) then case state is -- 状态1:等待引导码 when IDLE => valid <= '0'; if ir_input = '0' then -- 检测下降沿 counter <= 0; state <= LEADER_HIGH; end if; -- 状态2:测量引导码高电平 when LEADER_HIGH => counter <= counter + 1; if ir_input = '1' then if counter > LEADER_HIGH_MIN and counter < LEADER_HIGH_MAX then counter <= 0; state <= LEADER_LOW; else state <= IDLE; -- 无效引导码 end if; end if; -- 状态3:测量引导码低电平 when LEADER_LOW => counter <= counter + 1; if ir_input = '0' then if counter > LEADER_LOW_MIN then counter <= 0; bit_index <= 31; -- 准备接收32位数据(高位先收) state <= DATA_BIT; else state <= IDLE; end if; end if; -- 状态4:数据位解码 when DATA_BIT => if ir_input = '1' then counter <= counter + 1; else -- 根据高电平时长判断逻辑值 if counter > 28000 then -- 1.68ms (逻辑1) data_reg(bit_index) <= '1'; else -- 560μs (逻辑0) data_reg(bit_index) <= '0'; end if; if bit_index > 0 then bit_index <= bit_index - 1; counter <= 0; else valid <= '1'; data_out <= data_reg; state <= IDLE; -- 返回空闲状态 end if; end if; when others => state <= IDLE; end case; end if; end process; end Behavioral; ``` ### 三、关键实现技术 1. **时序精度控制**: - 使用系统时钟计数器测量脉冲宽度 - 添加±10%容差范围应对信号抖动[^1] 2. **错误处理机制**: ```vhdl -- 在DATA_BIT状态添加超时检测 if counter > 33600 then -- >1.8ms (超时阈值) state <= IDLE; -- 复位状态机 end if; ``` 3. **重复码处理扩展**: ```vhdl -- 检测重复码(长按键) when REPEAT => if counter > 112500 then -- 2.25ms valid <= '1'; -- 重复上一次有效数据 state <= IDLE; end if; ``` ### 四、实际应用优化 1. **消抖处理**: ```vhdl -- 添加消抖滤波器 signal filter_reg : STD_LOGIC_VECTOR(7 downto 0) := (others => '1'); signal clean_ir : STD_LOGIC; begin clean_ir <= '1' when filter_reg = "11111111" else '0'; process(clk) begin if rising_edge(clk) then filter_reg <= filter_reg(6 downto 0) & ir_input; end if; end process; ``` 2. **多设备支持**: - 通过地址码区分设备:`data_out(31 downto 16)`为设备地址 - 可配置地址掩码实现多设备控制[^2] ### 五、测试验证方法 1. **仿真测试序列**: ```vhdl -- 生成测试信号(发送按键0x00FF) ir_input <= '1', '0' after 10 ms, -- 引导码高 '1' after 19 ms, -- 引导码低 '0' after 23.5 ms; -- 数据位开始... ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值