2 q% Q( v3 J: X' K! ^( i3 O1.红外遥控简介 红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。 由于红外线遥控不具有像无线电遥控那样穿过障碍物去控制被控对象的能力,所以,在设计红外线遥控器时,不必要像无线电遥控器那样,每套(发射器和接收器)要有不同的遥控频率或编码(否则,就会隔墙控制或干扰邻居的家用电器),所以同类产品的红外线遥控器,可以有相同的遥控频率或编码,而不会出现遥控信号“串门”的情况。这对于大批量生产以及在家用电器上普及红外线遥控提供了极大的方面。由于红外线为不可见光,因此对环境影响很小,再由红外光波动波长远小于无线电波的波长,所以红外线遥控不会影响其他家用电器,也不会影响临近的无线电设备。红外遥控通讯系统一般由红外发射装置和红外接收设备两部分组成: 红外发射装置 红外发射装置(红外遥控器)是由键盘电路、红外编码电路、电源电路和红外发射电路组成。红外发射电路的主要元件为红外发光二极管(目前使用的红外线波长多为940nm)。红外遥控器常用载波的方式传送二进制编码,常用的载波频率为38kHz,红外遥控器将遥控信号(二进制脉冲码)调制在38kHz的载波上,经缓冲放大后送至红外发光二极管,转化为红外信号发射出去。 二进制脉冲码目前最广泛使用的是:NEC Protocol的PWM(脉冲宽度调制)和Philips RC-5 Protocol的PPM(脉冲位置调制)。本例程遥控器使用的是NEC协议,其特征如下 u 8位地址和8位指令长度 u 地址和命令2次传输(确保可靠性) u PWM脉冲位置调制,以发射红外载波的占空比代表0和1 u 载波频率为38kHz u 位时间为1.125ms或2.25ms NEC码的位定义:一个脉冲对应560us的连续载波,一个逻辑1传输需要2.25ms (560us脉冲+1680us低电平),一个逻辑0传输需要1.125ms(560us脉冲+560us低电平)。 而红外接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样在接收头端收到的信号为:逻辑1应该是560us低电平+1680us高电平,逻辑0应该是560us低电平+560us高电平。所以可以通过计算高电平时间判断接收到的数据是0还是1。 NEC 码位定义时序图如下图:
$ J3 j4 p* ~: \1 c) E7 R- X0 l* b; d
8 Z6 E8 a: |, u- p/ a$ ^4 r1 y( XNEC 遥控指令的数据格式为:引导码、地址码、地址反码、控制码、控制反码。引导码由一个9ms的低电平和一个4.5ms的高电平组成,地址码、地址反码、控制码、控制反码均是8位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。数据格式如下:
8 @0 f# B/ e+ Z& X
, a5 M: C& V; z! ?+ ZNEC 码还规定了连发码(由9ms低电平+2.5ms高电平+0.56ms低电平+97.94ms 高电平组成),如果在一帧数据发送完毕之后,红外遥控器按键仍然没有放开,则发射连发码,可以通过统计连发码的次数来标记按键按下的长短或次数。 红外接收设备 红外接收设备是由红外接收电路、红外解码、电源和应用电路组成。红外遥控接收器的主要作用是将遥控发射器发来的红外光信好转换成电信号,再放大、限幅、检波、整形,形成遥控指令脉冲,输出至遥控微处理器。 由于红外接收头在没有脉冲的时候为高电平,当收到脉冲的时候为低电平,所以可以通过外部中断的下降沿触发中断,在中断内通过计算高电平时间来判断接收到的数据是0还是1。 . l- S/ m5 J7 X# l$ z+ Y
2.硬件设计
, O* Z: x( f0 u: hD1指示灯用来提示系统运行状态,红外遥控器用来发射红外键值的编码信号,通过红外接收头进行解码,并将解码后的数据通过串口1打印输出 u 指示灯D1 u USART1串口 u 红外外遥控器和红外接收头 u TIM7(提供us延时) S0 V2 e0 F1 B. w
# [* _6 h. L8 t, N2 e9 m# X
3.软件设计 3.1 STM32CubeMX设置 RCC设置外接HSE,时钟设置为72M >> PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平 >> USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位 >> PG15设置为GPIO中断模式、引脚设为上拉(红外接收头在没有脉冲的时候为高电平)、下降沿触发中断,NVIC中开启中断并设置优先级
, Z' }1 I7 G1 A K! |! I/ O>> 激活TIM7,预分频因子设为72-1,向上计数,自动重载值为65535;因此计数器CNT_CLK = 1MHz,计数器周期为1us
1 v) {; b; q$ }
A1 L) l. H! @" p1 @>>输入工程名,选择路径(不要有中文),选择MDK-ARMV5;勾选Generated periphera initialization as a pair of‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
; w, Y+ ?' [7 q! V, N2 G. @3.2 MDK-ARM软件编程 >> 在tim.c文件下实现微秒延时(us)函数
/ C$ G; \6 {1 T1 k6 q- void delay_us(uint16_t us){+ H% `) n# C' W8 D, K2 D$ j
- uint16_t differ = 0xffff-us-5;. L a8 e9 Z0 b' B
- //设定TIM7计数器起始值
% e9 P7 C* Q m4 Y4 T" y, g - __HAL_TIM_SET_COUNTER(&htim7,differ);
- u" U3 y/ e+ j# a! g" i' ^ - HAL_TIM_Base_Start(&htim7); //启动定时器
5 t2 ~! U" S' h6 m' y# H: t -
6 V: `. R) |4 P/ Y* R$ R0 C - while(differ < 0xffff-5){ //判断
( D& q9 x9 |$ j/ H, H. J - //查询计数器的计数值
1 P5 ]( {3 ~! S - differ = __HAL_TIM_GET_COUNTER(&htim7); " m: W; R2 S+ @0 o/ w* `7 B7 z4 [
- }
* n. Y8 \4 N1 {) {7 c# u5 x - HAL_TIM_Base_Stop(&htim7);
+ h, _6 u' R2 U& o - }
复制代码
! d6 u/ z& O) q( t$ c/ T>> 创建按键驱动文件irremote.c 和相关头文件irremote.h
& @* b! _7 p+ \! K8 v- /*高电平持续时间函数*/
4 e* T3 j8 N! E$ k) f {- v - uint8_t IR_HighLevelPeriod(void){
& H8 k- q( V8 i9 |; F" e- p - uint8_t t=0;
, Z6 a& e# {: ?3 `3 e - while(HAL_GPIO_ReadPin(GPIOG,GPIO_PIN_15)==1){ //高电平, C3 m" {% d/ @4 Q
- t++;3 S, Y6 x0 T" H3 _! y4 w; V
- delay_us(20);
/ s% ?( n7 A2 L' b- O - if(t>=250) return t; //超时溢出
5 Y+ B# i2 R/ Z/ ?1 m$ l - }! |3 J1 `: H; O! u! B
- return t;
, O2 m9 N" o7 O5 Y) L7 ]5 P- O) a7 L - }
* |+ J/ p. w Z2 K, K - /*红外遥控外部中断回调函数*/
" t( S; S. h! J+ t& {$ q - //在中断回调函数中完成红外解码4 }) r0 E; Q' U7 T8 G/ o( N x# m
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ , i5 J3 d) y! A8 k( Q3 F% H1 D' d
- uint8_t Tim=0,Ok=0,Data,Num=0;' F6 j$ R4 @9 R% k/ d+ z# z2 g
- while(1){
$ K6 h# @8 y: S; W - if(HAL_GPIO_ReadPin(GPIOG,GPIO_PIN_15)==1){
) o0 ~* O4 n; X- h - //获得此次高电平时间9 }" e8 X3 g0 c7 Y: K2 A
- Tim = IR_HighLevelPeriod();
" C1 V6 k2 [) E; S& r @ - * r( O7 p% V6 W8 d* l, T
- if(Tim>=250) 7 I5 k% y' V! S7 `- {* {
- break; //无用的信号
9 F+ U* w1 ]6 A0 C1 y _- v - if(Tim>=200 && Tim<250)
0 W, {, E- h, E5 N2 a* d - Ok=1; //收到起始信号
( x2 R+ g+ `- F/ A" r4 U) m - else if(Tim>=60 && Tim<90)
9 L V$ W5 f% s8 J1 ], q - Data=1; //收到数据1* n; X( L2 m, j; R, l
- else if(Tim>=10 && Tim<50)& s; Z9 }" |0 Z! S9 N0 p2 l* b5 `
- Data=0; //收到数据0
$ u# k) e$ k& w* X - ( ~& O1 G5 q5 Y# G- q; V. y
- if(Ok==1){0 ]2 R1 x; e' w3 g* r9 O" [1 q
- receive_Code <<= 1;8 k/ N% p& C9 T$ Z/ m0 t0 V
- receive_Code += Data;
, c9 | j: z$ m3 Q0 o3 G. s" z; [% j! O - if(Num>=32){
2 W0 c, ?1 F9 x' b$ P - receive_Flag=1; p1 o+ y5 j# R& ]9 @2 _ P$ V0 v( V
- break;
7 u/ [- y, `& V# F% z3 P; b - }) \3 G# V, k! m% }+ Y3 Q7 O1 |
- }
& {4 s; X0 j& W - Num++;2 ?% Y9 Z8 T1 Z6 c& v9 d% V X
- }' T( U) [/ J+ N
- }: [% ^. h4 z1 X& y. K- |( N' f0 P
- }
复制代码
6 m7 h8 Y5 L( U2 z>> 在main.c文件下编写红外遥控测试代码 - int main(void){
$ N9 x5 \7 i( L5 B. ? - HAL_Init();
% E- a( v" j' X/ m; ~/ N' \ - SystemClock_Config();
+ \; L; f' o. k3 C* p; f6 F+ q& c( K - MX_GPIO_Init();: o+ n) P) i/ K% i8 \
- MX_TIM7_Init();& I3 u& t* w, C, W, r
- MX_USART1_UART_Init();7 t- p- u. T' L" D% Y
- /* USER CODE BEGIN 2 */
8 X Q- {/ ~/ E7 J _+ H - printf("IR Remote testing...please press the controller!!!\r\n");
; z1 ?% D" s4 U' B d6 Z - /* USER CODE END 2 */ o/ U; ^( Y5 f" W, @3 ~
- while (1){% u: q# v. L7 H
- if(receive_Flag == 1){7 ~; l- K* y) {; l8 \6 _% n
- receive_Flag = 0;6 c; Q. y1 }# o
- printf("IR Received Code: %0.8x\r\n",receive_Code);
) f# i6 w9 g4 g: t& R: P - receive_Code = 0;
5 K& K% [2 {+ i' }+ C) p - }
) `# V5 n" D: t6 C- j& ]! {/ v - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
. e7 }( w7 |" d/ O& g9 B - HAL_Delay(200);$ _; p5 B4 e6 E% r0 _6 w1 v1 X
- }
7 _- j$ ~9 A. u) v: r - }
复制代码 2 S+ `6 j8 K8 A! h0 f
' S( B* c& y* {+ b& d0 e
1 Y2 @' p1 M+ O4.下载验证
7 |- E6 C" |4 ?" J. J8 }/ @/ K) w* Z) ^
编译无误下载到开发板后,可以看到D1指示灯不断闪烁,当按下红外遥控器按键时,串口将打印出解码后的数据(地址码+地址反码+控制码+控制反码)
, [+ U# M' V5 j9 K! n: S( V g1 `4 ]* k( E/ T& l, J
文章出处: 安迪西 嵌入式攻城狮 + ~7 L' h. r. U# z) `
# M1 y5 l4 j( A% R Y1 L& \8 D2 U
2 P9 N# J4 q9 }/ A% Q7 E* x9 L3 K |