STM32之红外遥控信号自学习实现
一、序言
很早前就想实现这个红外遥控自学习的这个实验,用于来自己控制房子里如空调等红外遥控设备的自动化,NEC的标准到具体的产品上可能就被厂家定义为不一样了,所以自学习就应该是接收到什么就发送什么,不用管内容是什么!
二、硬件实现原理

由上述原理图可知,当IE为高电平时发送红外光,为低电平时不发送红外光。
在NEC协议中,信息传输是基于38K载波,也就是说红外线是以载波的方式传递。
发送波形如下图所示:

NEC协议规定:
发送协议数据“0” = 发送载波560us + 不发送载波560us
发送协议数据“1” = 发送载波560us+ 不发送载波1680us
发送引导码 = 发送载波9000us + 不发送载波4500us
在红外接收端,如果接收到红外38K载波,则IR输出为低电平,如果不是载波包括固定低电平和固定高电平则输出高电平。在IR端接收的信号如下所示:

三、软件实现自学习
设计原理:

1、 根据接收波形记录电平和电平持续时间,以便于发送。
2、电平记录采用定时器捕获功能,从下降沿接收引导信号开始,每触发一次改变触发方式,从而使每个电平变化都能捕获到。
源码实现如下:
定时器捕获初始化设置(CubeMax自动配置生成):
void MX_TIM4_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {};
TIM_MasterConfigTypeDef sMasterConfig = {};
TIM_IC_InitTypeDef sConfigIC = {}; htim4.Instance = TIM4;
htim4.Init.Prescaler = ;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = ;
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_IC_Init(&htim4) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = ;
if (HAL_TIM_IC_ConfigChannel(&htim4, &sConfigIC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
} }
定时器捕获中断回调处理:
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
{
if(TIM4->CCER & (TIM_CCER_CC4P)) //下降沿触发
{
TIM4->CCER &= ~(TIM_CCER_CC4P); //切换
gu8BitVal = ;
}
else //上升沿触发
{
TIM4->CCER |= TIM_CCER_CC4P; //切换
gu8BitVal = ;
} if(gsInfrared.State == NONE_STATE)
{
gsInfrared.State = RECV_STATE;
}
else if(gsInfrared.State == RECV_STATE)
{
NowTimCnt = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_4);
gsInfrared.KeepTime[gsInfrared.SampleCount] = Round(NowTimCnt);
gsInfrared.BitValue[gsInfrared.SampleCount ++] = gu8BitVal;
} TIM4->CNT = ;
}
}
3、设置的定时器溢出时间为10ms,如果10毫秒内不再接收电平变化则默认接收结束,设置结束标志。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim4)
{
if(gsInfrared.State == RECV_STATE)
{
gsInfrared.State = END_STATE;
}
}
}
至此,实现了红外遥控的学习功能,获得的记录数据为记录长度和电平信号数组与电平信号维持的时间数组。


4、发送实现
设置定时器输出38KPWM信号,在记录电平为0是输出记录时间的38K载波信号,如果为1则不输出载波,实现如下:
PWM生成设置(CubeMax自动配置生成):
void MX_TIM5_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig = {};
TIM_OC_InitTypeDef sConfigOC = {}; htim5.Instance = TIM5;
htim5.Init.Prescaler = ;
htim5.Init.CounterMode = TIM_COUNTERMODE_UP;
htim5.Init.Period = ;
htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim5) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = ;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim5); }
发送实现,注意点就是记录为0时发载波,记录为1时不发载波:
void InfraredSend(void)
{
uint16_t Count = ; while(Count < gsInfrared.SampleCount && gsInfrared.State == END_STATE)
{
if(gsInfrared.BitValue[Count] == )
{
TIM5->CCR2 = ;
delay_us(gsInfrared.KeepTime[Count]);
TIM5->CCR2 = ;
}
else
{
TIM5->CCR2 = ;
delay_us(gsInfrared.KeepTime[Count]);
TIM5->CCR2 = ;
} Count ++;
} delay_us();
}
往PWM比较寄存器设置948即为设置38KPWM波,也可在初始化时固定948,在此函数内启停定时器即可;
至此,自学习功能的全部思路已实现,通过对各个不同类型的红外遥控进行功能测试,均成功。
PS:查看很多资料发现很多红外解码未判断低电平时间,个人感觉不是很好,应该是不仅高电平时间得符合,低电平时间也应该符合。
自己写了一个小函数验证了一下,这个函数只是验证,未经仔细推敲,还可优化,仅供参考这一思想。
误差设计:±200us(拍脑袋值)
void InFraredDataDeal(void)
{
uint32_t DataBuff = ;
uint16_t Count = ; if(gsInfrared.State == END_STATE)
{
gsInfraredData.State = ; do
{
switch(gsInfraredData.State)
{
case : //引导码识别
{ if(gsInfrared.KeepTime[] >= && gsInfrared.KeepTime[] <= && gsInfrared.BitValue[] == )
{
if(gsInfrared.KeepTime[] >= && gsInfrared.KeepTime[] <= && gsInfrared.BitValue[] == )
{
if(gsInfrared.KeepTime[] >= && gsInfrared.KeepTime[] <= && gsInfrared.BitValue[] == )
{
Count = ;
gsInfraredData.State = ;
}
}
else if(gsInfrared.KeepTime[] >= && gsInfrared.KeepTime[] <= && gsInfrared.BitValue[] == )
{
if(gsInfrared.KeepTime[] >= && gsInfrared.KeepTime[] <= && gsInfrared.BitValue[] == )
{
gsInfraredData.ReDataCount ++;
gsInfraredData.State = ;
}
}
else
{
gsInfraredData.State = ;
} }
else
{
gsInfraredData.State = ;
} }
break; case : //数据解析
{ if(gsInfrared.KeepTime[Count + ] >= && gsInfrared.KeepTime[Count + ] <= && gsInfrared.BitValue[Count + ] == )
{ if(gsInfrared.BitValue[Count] == )
{
if(gsInfrared.KeepTime[Count] >= && gsInfrared.KeepTime[Count] <= )
{
DataBuff <<= ;
DataBuff |= ;
}
else if(gsInfrared.KeepTime[Count] >= && gsInfrared.KeepTime[Count] <= && gsInfrared.BitValue[Count] == )
{
DataBuff <<= ;
DataBuff |= ;
}
else
{
gsInfraredData.State = ;
}
}
} if(Count < gsInfrared.SampleCount)
{
Count += ;
}
else
{
gsInfraredData.State = ;
} }
break; case : //成功解析
{
gsInfraredData.Data = DataBuff;
gsInfraredData.State = ; }
break; default:
{
gsInfraredData.State = ; //解析结束 }
break;
} }
while(gsInfraredData.State != ); gsInfrared.State = NONE_STATE;
gsInfrared.SampleCount = ;
} }
解析的话一般高位在前,所以左移,经测试帧格式为:引导码+用户码+用户码反码+命令码+命令码反码,能成功解析数据!解析的话根据具体协议,具体分析。
STM32之红外遥控信号自学习实现的更多相关文章
- 基于Arduino、STM32进行红外遥控信号接收
catalogue . 遥控器原理简介 . 红外遥控原理 . 常见红外遥控器红外线信号传输协议 . 遙控器的发展 . 实验过程 . 攻击面 . 基于STM32实现红外信号解码 1. 遥控器原理简介 0 ...
- 基于STM32的红外遥控重点解析
本文有两个内容:一.红外遥控协议的的讲解:二.解码程序解析(参考正点原子的代码) 红外的介绍.优点.缺点就不给大家说了,进入正题 一.红外遥控协议的的讲解 红外遥控的编码目前广泛使用的是:NEC Pr ...
- 解码红外遥控信号——使用遥控器的按键来调节LED的亮度
程序开始时,提示遥控键0~4的代码,然后程序通过设置LED的亮度来对被按下的按钮作出响应,以0关闭LED,1~4提供增加的亮度. 代码如下:(需要使用IRremote库,可在库管理中搜索该库进行下载后 ...
- 51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY
先看效果图: 显示 频道CH , 频率 100.0Mhz 欢迎信息,1602 内置日文平假名, 正好用来显示博主名称. 焊接前,已经万能面包板上试验成功. 焊接完成以后,1602 的D0 - D7 接 ...
- 红外遥控NEC协议使用总结
最近做了一个调试红外遥控三色灯的实习,花了一个多月的时间研究基于NEC协议的红外遥控,下面是这次实习技术方面的总结. 一.NEC协议特征: 8位地址和8位命令长度 每次传输两遍地址(用户码)和命令(按 ...
- 红外遥控系统原理及单片机软件解码程序,我的编写经历(C版本)
应该说现在每一块开发板都带有红外模块,并且大都配置了相应的程序.但其实自己动手写解码程序,更能锻炼自己所学,且不谈程序写的如何,这个过程中肯定是受益良多的.现在我就把我花一下午写出的解码程序与大家分享 ...
- 基于FPGA的红外遥控解码与PC串口通信
基于FPGA的红外遥控解码与PC串口通信 zouxy09@qq.com http://blog.csdn.net/zouxy09 这是我的<电子设计EDA>的课程设计作业(呵呵,这个月都拿 ...
- 46.Linux-分析rc红外遥控平台驱动框架,修改内核的NEC解码函数BUG(1)
内核版本 : Linux 3.10.14 rc红外接收类型: GPIO 类型的NEC红外编码 本章内容 1) rc体系结构分析 2) 分析红外platform_driver平台驱 ...
- 玩转X-CTR100 l STM32F4 l 红外遥控接收
我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] X-CTR100控制器具有红外接收头,例程 ...
随机推荐
- Java——容器(Collection)
Collection是一个接口,定义了一系列的方法. [常见方法]
- 设计模式学习笔记——Visitor 访问者模式
1.定义IVisitor接口,确定变化所涉及的方法 2.封装变化类.实现IVisitor接口 3.在实体类的变化方法中传入IVisitor接口,由接口确定使用哪一种变化来实现(封装变化) 4.在使用时 ...
- Zookeeper w3cschool教程
1.简介 ZooKeeper是一种分布式协调服务,用于管理大型主机.在分布式环境中协调和管理服务是一个复杂的过程.ZooKeeper通过其简单的架构和API解决了这个问题. ZooKeeper允许开发 ...
- 使用vue技术应当使用的技术和兼容性选择
假如你的前端框架使用了vue,那你可以大胆地使用以下技术,并忽略其他js和css的兼容性问题,因为 关于vue的兼容性 官方给出了规定 Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 ...
- 启用和配置 FILESTREAM
2017/08/23 在开始使用 FILESTREAM 之前,必须在 SQL Server 数据库引擎实例中启用 FILESTREAM. 本主题说明了如何使用 SQL Server 配置管理器来启用 ...
- 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_04 IO字节流_2_一切皆为字节
这里的视频就是字节的形式,为了看着方便转换成了MB.一个字节就是8个二进制 包括文本,都是以字节的形式存储的
- Postman Tests脚本的使用
直接在Tests中写js代码断言结果,Test Result展示运行结果,简单方便. 示例脚本: var jsonData = JSON.parse(responseBody); var num = ...
- kali安装教程
首先在vm里面新建虚拟机,直接选择典型,然后下一步. 1 2 然后到了这一步,选择中间的安装程序光盘镜像文件,然后去文件里面找你自己下载的镜像,这时候可能系统会出现无法检测此光盘镜像中的操作系 ...
- Vuex模块:不开启命名空间
模块不开启命名空间时,会共享全局命名空间. { state: { 模块1: "局部状态1", 模块2: "局部状态2" }, getters: { getter ...
- 在layui中,新的页面怎么获取另一个页面传过来的数据,并可以对数据进行判断,layui中的后台分页(table)。
例如:打开一个新页面的同时,传数据. layer.open({ type: 2, title: '新增项目', shadeClose: false, shade: [0.3], maxmin: tru ...