红外遥控器 数据格式,按下及松开判断

2023-12-27 11:30

本文主要是介绍红外遥控器 数据格式,按下及松开判断,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。

同类产品的红外线遥控器,可以有相同的遥控频率或编码,而不会出现遥控信号“串门”的情况。

红外遥控的编码目前广泛使用的是:NEC Protocol 的PWM(脉冲宽度调制)和Philips

RC-5 Protocol 的PPM(脉冲位置调制)。

本次适配的遥控器也为NEC协议。

NEC协议特征:

1、8位地址和8位指令长度;

2、 地址和命令2次传输(确保可靠性)

3、PWM脉冲宽度调制,以发射红外载波的占空比代表“0”和“1”;

4、载波频率为38Khz;

5、位时间为1.125ms或2.25ms;

NEC码位定义:

一个脉冲对应560us的连续载波,一个逻辑1传输需要2.25ms(560us脉冲+1680us低电平),一个逻辑0的传输需要1.125ms(560us脉 冲+560us低电平)。而遥控接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到的信号为:逻辑1应该是560us低+1680us高,逻辑0应该是560us低+560us高。

NEC遥控器指令的数据格式:

同步码头、地址码、地址反码、控制码、控制反码。同步码由一个9ms的低电平和一个4.5ms的高电平组成,地址码、地址反码、控制码、控制反码均是8位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。

NEC码规定的连发码(由9ms低电平+2.5m高电平+0.56ms低电平+97.94ms高电平组成),如果在一帧数据发送完毕之后,按键仍然没有放开,则发射重复码,即连发码,可以通过统计连发码的次数来标记按键按下的长短/次数。

同步码为9ms低电平,4.5ms高电平组成,所以可以通过判断9ms后的高电平持续时间来判断是否有连发。

硬件连接:

APMF107输入引脚

红外接收头位于按键板

程序设计思路:

红外接收头接受到红外信号,通过PC3输入引脚进行接收,由于红外波形是一个不断产生高低电平的脉冲,可以通过中断的方式进行数据的接收处理,不同码位对应有不同的时间,逻辑0和逻辑1的高电平持续时间不同,可以通过定时器计数来判断码位以及发送的是逻辑0还是逻辑1.

这里有两种处理方式,第一种为使用定时器中断以及定时器的输入捕获功能进行处理,第二种为使用定时器计数功能和外部中断触发的方式。由于PC3输入引脚不支持定时器的复用和映射功能,所以本次适配采用第二种方式,采用定时器2以及外部中断3。

初始化配置定时器和中断,初始化GPIO_PC3上拉输入,设置IO口与中断的映射关系。空闲状态为高电平,所以中断触发为下降沿触发,在触发中断后如果波形为空闲状态就设为上升沿触发,波形为起始码接收状态,接收下降沿,计算脉宽时间,在9ms范围就为有效波形,更新接受状态准备接收4.5ms,中断设为下降沿触发,准备下次捕获。在4.5ms则表示起始位接收完成,在2,5ms表示数据发送一次后发送的连发码。更新状态准备接受地址码,判断脉宽的周期得到传输的逻辑0还是1,将对应的位进行赋值。地址码占两个字节正码和反码,所以判断赋值的位数是否是16位来标志地址码的接受是否完成,然后将状态更新为接收控制码,与地址码一样计算脉宽周期然后赋值,赋值的位数为32位此次数据接收完成。

在有按键按下时,需要通过串口向上层SOC发送按键的索引以及按键的状态(按下和松开)。定义一个全局变量,按键标志位,什么时候按下,在数据接收完成后标志位置1表示按键已经按下。什么时候松开呢?定义一个静态局部变量初始为空闲状态,用来保存前一次的状态,当当前的状态由其他状态切换到空闲状态,读取定时器7的计数保存下这个时间,当前状态和前一次状态都为空闲,并且保存的计数时间不为0,再读取定时器7计数的时间,用后面的时间减去前面的时间,如果这个时间大于一个设定的值,就代表按键已经松开,标志位置0.

定义一个枚举,保存对应按键的索引,通过键值的判断,赋值对应的索引。按键状态的上报与判断松开的方式同理,只上报按键状态发生改变的那一次。放解析处理部分的代码。

//按键键值//红外波形的状态typedef enum {IR_STATE_IDLE=0,	//0IR_STATE_START,	    //1IR_STATE_STARTEND,  //2IR_STATE_ADDR,		//3IR_STATE_DATA       //4}IR_State_enum;//键值索引枚举//初始化 
void apm_remote_init(void) 
-->gpio(pc3)、定时器(tmr2)、外部中断3//中断服务程序————接收处理红外信号 
void apm_remote_nec_handle(void)
{if(EINT_ReadIntFlag(EINT_LINE_3)) //外部中断{if(IR_State == IR_STATE_IDLE){  //如果波形状态为空闲,开启定时器2计数TMR_ConfigCounter(TMR2,0);TMR_Enable(TMR2);ir_previous_time = TMR_ReadCounter(TMR2);apm_eint3_rising_config(); //上升沿触发update_cnt = 0;IR_State = IR_STATE_START; //波形为起始码接收状态}else{ir_current_time = TMR_ReadCounter(TMR2); //读取当前捕获值//计算时间间隔if(update_cnt == 0){//计算当前时间    //时间间隔=当前时间-前一时间ir_interval_time = abs(ir_current_time - ir_previous_time);}else{ir_interval_time = abs(0x186A0 * update_cnt - ir_previous_time);ir_interval_time += ir_current_time;}ir_previous_time = ir_current_time;//将当前时间设置为前一个时间update_cnt = 0; //计数器的范围返回0状态//接收下降沿,计算高电平脉宽为9msif(IR_State == IR_STATE_START){//检查高电平是否在指定范围内7.2ms<IR<10.8ms ,否则不是有效波形,放弃接收if((ir_interval_time > 7200) && (ir_interval_time < 10800)){//是有效波形,将状态更新为准备接收4ms低电平IR_State = IR_STATE_STARTEND;}else{//不是有效波形,返回空闲状态,按键没有按下IR_State = IR_STATE_IDLE;}//将中断设为下降沿触发,准备下次捕获apm_eint3_falling_config();}else if(IR_State == IR_STATE_STARTEND) //计算起始间隙位的低电平位宽(4.5ms),重复码低电平2.25ms{//判断低电平是否在指定范围3.6ms<IR<5.4msif((ir_interval_time > 3600) && (ir_interval_time < 5400)){//有效起始位irbitscnt = 0; //第0位 irData = 0; IR_Repeat_cnt = 0;IR_State = IR_STATE_ADDR; //起始位接收完成,更新状态准备接收地址码}//检查重复码的低电平是否在指定范围内1.8ms<IR<2.7mselse if((ir_interval_time > 1800) && (ir_interval_time < 2700)){//如果是连发码的有效电平,连发次数累加IR_Repeat_cnt++;IR_State = IR_STATE_IDLE; //将波形更新为空闲,进行下次接收起始码或连发码}else //如果低电平时间不是起始码4.5ms,也不是连发码2.25ms,则不是有效波形{IR_State = IR_STATE_IDLE; //更新状态}}//上升沿捕获,计算地址位(用户码)脉宽周期else if(IR_State == IR_STATE_ADDR){//逻辑0的传输需要1.125msif((ir_interval_time > 900) && (ir_interval_time < 1340)){irData >>= 1;irbitscnt++;}//逻辑1的传输需要2.25mselse if((ir_interval_time > 1790) || (ir_interval_time < 2690)) {irData >>= 1;irData |= 0x8000;irbitscnt++;}else  //不是有效波形{IR_State = IR_STATE_IDLE;}//地址位占两个字节,地址码和地址反码,判断接收完成是否16位if(irbitscnt == 16){if((irData>>8) == SYS_HEAD_CODE){remoteid = irData>>8;irData = 0;IR_State = IR_STATE_DATA;//用户码数据正确,将状态更新接收控制码}else //用户码错误,返回空闲状态{IR_State = IR_STATE_IDLE;}}}//上升沿捕获,计算键值的脉宽周期(控制码和控制反码)else if(IR_State == IR_STATE_DATA){//和地址码一样,判断逻辑0和逻辑1if((ir_interval_time > 900) && (ir_interval_time < 1340)) {irData >>= 1;irbitscnt++;}else if((ir_interval_time > 1790) || (ir_interval_time < 2690)){irData >>= 1;irData |= 0x8000;irbitscnt++;}else{IR_State = IR_STATE_IDLE;}if(irbitscnt == 32){irData ^= 0xFF00;  if(((irData >> 8) - (irData & 0x00FF)) <= 1){recv_irkey = (uint8_t)(irData & 0x00FF);IR_keyFlag = 1; //数据接收完成,按键按下//控制码和控制反码接收完成,本次数据接收处理完成,将状态更新为空闲状态,接着判断是否有连发码或按键切换IR_State = IR_STATE_IDLE;}else{IR_State = IR_STATE_IDLE;//键值解析错误,重置接收}}}}}
}//松开判断函数 
u8 remote_keystate(void)
{static uint8_t pre_ir_state = IR_STATE_IDLE;static uint32_t timeTick_ori = 0;uint32_t timeTick_cur = 0;if(IR_State != pre_ir_state && IR_State == IR_STATE_IDLE) {  //从其他状态切换到空闲timeTick_ori = get_u32CntTick_num(); //另一个定时器的计数次数}if(IR_State ==IR_STATE_IDLE && pre_ir_state == IR_STATE_IDLE && timeTick_ori != 0) {timeTick_cur = get_u32CntTick_num(); //再次获取最新次数if((timeTick_cur - timeTick_ori) >= 100) { //当相差大于100时判定按键已经松开了,根据实际情况调整			
//空闲状态超时,判断松开timeTick_ori = 0;IR_keyFlag = 0;}}pre_ir_state = IR_State;return IR_keyFlag;
}//红外键值检测上报 
void apm_remote_val(void)  
key_event_report(msg.index, SET);//上报按键

这篇关于红外遥控器 数据格式,按下及松开判断的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/542976

相关文章

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

zoj 1721 判断2条线段(完全)相交

给出起点,终点,与一些障碍线段。 求起点到终点的最短路。 枚举2点的距离,然后最短路。 2点可达条件:没有线段与这2点所构成的线段(完全)相交。 const double eps = 1e-8 ;double add(double x , double y){if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;return x + y ;

POJ1269 判断2条直线的位置关系

题目大意:给两个点能够确定一条直线,题目给出两条直线(由4个点确定),要求判断出这两条直线的关系:平行,同线,相交。如果相交还要求出交点坐标。 解题思路: 先判断两条直线p1p2, q1q2是否共线, 如果不是,再判断 直线 是否平行, 如果还不是, 则两直线相交。  判断共线:  p1p2q1 共线 且 p1p2q2 共线 ,共线用叉乘为 0  来判断,  判断 平行:  p1p

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

【408DS算法题】039进阶-判断图中路径是否存在

Index 题目分析实现总结 题目 对于给定的图G,设计函数实现判断G中是否含有从start结点到stop结点的路径。 分析实现 对于图的路径的存在性判断,有两种做法:(本文的实现均基于邻接矩阵存储方式的图) 1.图的BFS BFS的思路相对比较直观——从起始结点出发进行层次遍历,遍历过程中遇到结点i就表示存在路径start->i,故只需判断每个结点i是否就是stop

linux 判断某个命令是否安装

linux 判断某个命令是否安装 if ! [ -x "$(command -v git)" ]; thenecho 'Error: git is not installed.' >&2exit 1fi

shell循环sleep while例子 条件判断

i=1# 小于5等于时候才执行while [ ${i} -le 5 ]doecho ${i}i=`expr ${i} + 1`# 休眠3秒sleep 3doneecho done 参考 http://c.biancheng.net/cpp/view/2736.html

(二)Vue.js 条件判断 20170818

条件判断 (一)v-if  使用 概念:v-if  其实说白了就是类似于java里面的判断语句,在vue.js中经常跟 template一起使用  1.jsp 代码 <template v-if="false"><label>符亮星</label><br/><label>职业爱好:编码制造方便</label></template> 设置为false时就会隐藏掉 结果图

如何判断一个数组中是否包含一个字符或字符串

第一种方法:遍历数组 String[] arr1 = {"1","2","3","4","6","7"}; for (int i = 0; i < arr1.length; i++) { if("5".equals(arr1[i])) { System.out.println("包含"); }else { System.out.println("不包含"); } } 第二种方法:先把数组