1、序言
很早前就想实现这个红外遥控自学习的这个实验,用于来自己控制房子里如空调等红外遥控设备的自动化,nec的标准到具体的产品上可能就被厂家定义为不一样了,所以自学习就应该是接收到什么就发送什么,不用管内容是什么!
2、硬件实现原理
由上述原理图可知,当ie为高电平时发送红外光,为低电平时不发送红外光。
在nec协议中,信息传输是基于38k载波,也就是说红外线是以载波的方式传递。
发送波形如下图所示:
nec协议规定:
发送协议数据“0” = 发送载波560us + 不发送载波560us
发送协议数据“1” = 发送载波560us+ 不发送载波1680us
发送引导码 = 发送载波9000us + 不发送载波4500us
在红外接收端,如果接收到红外38k载波,则ir输出为低电平,如果不是载波包括固定低电平和固定高电平则输出高电平。在ir端接收的信号如下所示:
3、软件实现自学习
设计原理:
1、 根据接收波形记录电平和电平持续时间,以便于发送。
2、电平记录采用定时器捕获功能,从下降沿接收引导信号开始,每触发一次改变触发方式,从而使每个电平变化都能捕获到。
源码实现如下:
定时器捕获初始化设置(cubemax软件自动配置生成):
void mx_tim4_init(void){tim_clockconfigtypedef sclocksourceconfig = {0};tim_masterconfigtypedef smasterconfig = {0};tim_ic_inittypedef sconfigic = {0};htim4.instance = tim4;htim4.init.prescaler = 71;htim4.init.countermode = tim_countermode_up;htim4.init.period = 10000;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 = 0;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 = 1; }else //上升沿触发 { tim4->ccer |= tim_ccer_cc4p; //切换 gu8bitval = 0; }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 = 0; }}
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 = {0}; tim_oc_inittypedef sconfigoc = {0}; htim5.instance = tim5; htim5.init.prescaler = 0; htim5.init.countermode = tim_countermode_up; htim5.init.period = 1896; 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 = 0; 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 = 0;while(count ccr2 = 948; delay_us(gsinfrared.keeptime[count]); tim5->ccr2 = 0; }else { tim5->ccr2 = 0; delay_us(gsinfrared.keeptime[count]); tim5->ccr2 = 0; } count ++; } delay_us(20000);}
往pwm比较寄存器设置948即为设置38kpwm波,也可在初始化时固定948,在此函数内启停定时器即可;
至此,自学习功能的全部思路已实现,通过对各个不同类型的红外遥控进行功能测试,均成功。
ps:查看很多资料发现很多红外解码未判断低电平时间,个人感觉不是很好,应该是不仅高电平时间得符合,低电平时间也应该符合。
自己写了一个小函数验证了一下,这个函数只是验证,未经仔细推敲,还可优化,仅供参考这一思想。
误差设计:±200us(拍脑袋值)
void infrareddatadeal(void){uint32_t databuff = 0;uint16_t count = 0;if(gsinfrared.state == end_state) { gsinfrareddata.state = 0;do {switch(gsinfrareddata.state) {case 0: //引导码识别 {if(gsinfrared.keeptime[0] >= 8800 gsinfrared.keeptime[0] = 4300 gsinfrared.keeptime[1] = 360 gsinfrared.keeptime[2] = 2300 gsinfrared.keeptime[1] = 360 gsinfrared.keeptime[2] = 360 gsinfrared.keeptime[count + 1] = 1480 gsinfrared.keeptime[count] <= 1880) { databuff <= 360 gsinfrared.keeptime[count] <= 760 gsinfrared.bitvalue[count] == 1) { databuff <<= 1; databuff |= 0; }else { gsinfrareddata.state = 3; } } }if(count < gsinfrared.samplecount) { count += 2; }else { gsinfrareddata.state = 2; } }break;case 2: //成功解析 { gsinfrareddata.data = databuff; gsinfrareddata.state = 3; }break;default: { gsinfrareddata.state = 3; //解析结束 }break; } }while(gsinfrareddata.state != 3); gsinfrared.state = none_state; gsinfrared.samplecount = 0; }}
解析的话一般高位在前,所以左移,经测试帧格式为:引导码+用户码+用户码反码+命令码+命令码反码,能成功解析数据!解析的话根据具体协议,具体分析。
外媒:中国电动汽车业将迎来更大发展
智能显示器比看起来更智能
微信回应崩了 微信或将推出深度清理新功能
美国商务部向福建晋华集成实施禁售令
笔记本太重怎么办?
STM32之红外遥控信号自学习实现
免费下载 | CJJ/T 261-2017《城市照明合同能源管理技术规程》
简述python类实例及构造函数基础
如何利用区块链技术进行垃圾管理
这款iPhone7Plus手机壳很给力?还能当移动电源使
锂离子电池监视器bq76PL536-Q1的主营性能特点及应用电路
半导体产业未来将会是怎样的发展趋势
“突破性能和功耗极限--新一代自动驾驶处理器助力自动驾驶产业化”的演讲
Java设计模式(二十一):中介者模式
全新一代宋EV 500凭借越级实力,刷新了人们对纯电SUV的新认知
格芯与谷歌联合发布一个开源的PDK
中国电信总经理是谁 柯瑞文已正式升任中国电信总经理
同步传输和异步传输到底有什么区别
光伏逆变器有哪些保护功能?
低功耗蓝牙模块不知道怎么选型?看这里!