一、序言

很早前就想实现这个红外遥控自学习的这个实验,用于来自己控制房子里如空调等红外遥控设备的自动化,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之红外遥控信号自学习实现的更多相关文章

  1. 基于Arduino、STM32进行红外遥控信号接收

    catalogue . 遥控器原理简介 . 红外遥控原理 . 常见红外遥控器红外线信号传输协议 . 遙控器的发展 . 实验过程 . 攻击面 . 基于STM32实现红外信号解码 1. 遥控器原理简介 0 ...

  2. 基于STM32的红外遥控重点解析

    本文有两个内容:一.红外遥控协议的的讲解:二.解码程序解析(参考正点原子的代码) 红外的介绍.优点.缺点就不给大家说了,进入正题 一.红外遥控协议的的讲解 红外遥控的编码目前广泛使用的是:NEC Pr ...

  3. 解码红外遥控信号——使用遥控器的按键来调节LED的亮度

    程序开始时,提示遥控键0~4的代码,然后程序通过设置LED的亮度来对被按下的按钮作出响应,以0关闭LED,1~4提供增加的亮度. 代码如下:(需要使用IRremote库,可在库管理中搜索该库进行下载后 ...

  4. 51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY

    先看效果图: 显示 频道CH , 频率 100.0Mhz 欢迎信息,1602 内置日文平假名, 正好用来显示博主名称. 焊接前,已经万能面包板上试验成功. 焊接完成以后,1602 的D0 - D7 接 ...

  5. 红外遥控NEC协议使用总结

    最近做了一个调试红外遥控三色灯的实习,花了一个多月的时间研究基于NEC协议的红外遥控,下面是这次实习技术方面的总结. 一.NEC协议特征: 8位地址和8位命令长度 每次传输两遍地址(用户码)和命令(按 ...

  6. 红外遥控系统原理及单片机软件解码程序,我的编写经历(C版本)

    应该说现在每一块开发板都带有红外模块,并且大都配置了相应的程序.但其实自己动手写解码程序,更能锻炼自己所学,且不谈程序写的如何,这个过程中肯定是受益良多的.现在我就把我花一下午写出的解码程序与大家分享 ...

  7. 基于FPGA的红外遥控解码与PC串口通信

    基于FPGA的红外遥控解码与PC串口通信 zouxy09@qq.com http://blog.csdn.net/zouxy09 这是我的<电子设计EDA>的课程设计作业(呵呵,这个月都拿 ...

  8. 46.Linux-分析rc红外遥控平台驱动框架,修改内核的NEC解码函数BUG(1)

    内核版本          :  Linux 3.10.14 rc红外接收类型:  GPIO 类型的NEC红外编码 本章内容 1) rc体系结构分析 2) 分析红外platform_driver平台驱 ...

  9. 玩转X-CTR100 l STM32F4 l 红外遥控接收

    我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ]      X-CTR100控制器具有红外接收头,例程 ...

随机推荐

  1. Bugku 杂项 又一张图片,还单纯吗

    又一张图片,还单纯吗 下载后,用binwalk打开图片 使用foremost 2.png进行分离 得到图片 关于foremost foremost [-v|-V|-h|-T|-Q|-q|-a|-w-d ...

  2. 【CF1247E】Rock Is Push(DP,二分)

    题意:有一个n*m的方格,每一格可能为空也可能有石头,要从(1,1)走到(n,m),每次可以往右或往下走 每次走的时候都会将自己面前的所有石头向移动方向推一格,如果碰到了边界就推不过去 问方案数模1e ...

  3. nvm 管理 node 版本

    nvm 有 Mac 版本 num 亦有 windows 版本(可以搜索 nvm for windows) 安装后 运行 nvm v 可查看版本 运行 nvm install latest 安装最新版本 ...

  4. idea生成get/set方法

    如图:

  5. 170831-关于JdbcTemplate声明式事务-操作步骤-例子

    创建一个动态web工程 加入jar包 3.创建一份jdbc.properties文件 4.在spring配置文件中配置数据源 5.测试数据源: 6.配置jdbcTemplate: 7.创建Dao类 & ...

  6. RESTful风格编程

    参考文档:http://blog.didispace.com/springbootrestfulapi/ https://www.jianshu.com/p/91600da4df95 *)RESTfu ...

  7. this._super()

    https://learn.jquery.com/jquery-ui/widget-factory/extending-widgets/ https://api.jqueryui.com/jquery ...

  8. chrome flash 自动暂停问题

    chrome flash 尺寸小于398*298时,只要宽和高某一个值小于对应值就会自动暂停,出现这个圆形的播放按钮.(估计是当广告处理了...) 将尺寸调大即可.

  9. nginx坑记录

    问题1: 配置解析过程使用ngx_cycle->pool申请内存保存配置,结果造成野指针. 背景:需求开发过程,有一些结构需要在配置解析阶段保存,然后可以动态修改.看原来的代码配置解析都是使用c ...

  10. Java Bean 使用包装类型 还是基本类型

    参考:实体类中用基本类型好,还是用包装类型好_ - 牵牛花 - 博客园 int优缺点 优点: 1.用于Bean的时候,有默认值.比如自己拼接sql增加一个User时,会方便很多,不过现在都用ORM框架 ...