最近用到了一种常见的低成本红外遥控器:
这种遥控器的编码方式为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 位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可 用于校验)。
一个实际的通信例子如下:
根据通信协议,逻辑0和逻辑1的高电平时间时不同的,由此我们想到用单片机定时器的输入捕获功能来进行解码。思路如下:初始化定时器后配置为上升沿捕获,发送捕获中断后记录捕获值,再捕获下降沿,下降沿捕获到的值与上升沿的值之差即为高电平时间,根据高电平时间得到是逻辑0、逻辑1还是连续发送。
基于MSP432P401单片机的红外解码程序如下:
//红外遥控器 #define IR_RXD GPIO_PORT_P5, GPIO_PIN7 #define IR_Romate GPIO_PORT_P4, GPIO_PIN4 #define REMOTE_ID 0 uint8_t IRcount=0; uint16_t IRCapValue1=0; uint16_t IRCapValue2=0; uint16_t IRCapValue=0; void Romate_Init(void) { /* 定时器配置参数*/ Timer_A_ContinuousModeConfig continuousModeConfig = { TIMER_A_CLOCKSOURCE_SMCLK, // SMCLK Clock Source TIMER_A_CLOCKSOURCE_DIVIDER_6, // SMCLK/6 = 1MHz TIMER_A_TAIE_INTERRUPT_ENABLE, // Enable Timer ISR TIMER_A_SKIP_CLEAR // Skup Clear Counter }; /* Timer_A 捕获模式参数配置*/ Timer_A_CaptureModeConfig captureModeConfig1 = { TIMER_A_CAPTURECOMPARE_REGISTER_2, // CC Register 2 TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE,//上升沿和下降沿 TIMER_A_CAPTURE_INPUTSELECT_CCIxA, // CCIxB Input Select TIMER_A_CAPTURE_SYNCHRONOUS, // Synchronized Capture TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE, // Enable interrupt TIMER_A_OUTPUTMODE_OUTBITVALUE // Output bit value }; GPIO_setAsPeripheralModuleFunctionInputPin(IR_RXD,GPIO_PRIMARY_MODULE_FUNCTION); GPIO_setAsOutputPin(IR_Romate); GPIO_setOutputLowOnPin(IR_Romate); Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig1); Timer_A_configureContinuousMode(TIMER_A2_BASE, &continuousModeConfig); Interrupt_enableInterrupt(INT_TA2_N); Timer_A_startCounter(TIMER_A2_BASE, TIMER_A_CONTINUOUS_MODE); } //遥控器接收状态 //[7]:收到了引导码标志 //[6]:得到了一个按键的所有信息 //[5]:保留 //[4]:0表示捕获上升沿,1表示捕获下降沿 //[3:0]:溢出计时器 uint8_t Romsta; uint32_t RmtRec=0; //红外接收到的数据 uint8_t RmtCnt=0; //按键按下的次数 void TA2_N_IRQHandler(void) { /*溢出中断*/ if(Timer_A_getEnabledInterruptStatus(TIMER_A2_BASE)) { Timer_A_clearInterruptFlag(TIMER_A2_BASE); if(Romsta&0x80)//上次有数据被接收到了 { IRcount++; Romsta&=~0X10;//取消上升沿已经被捕获标记 if((Romsta&0X0F)==0X00) Romsta|=1<<6;//标记已经完成一次按键的键值信息采集 if((Romsta&0X0F)<14) Romsta++; else { Romsta&=~(1<<7);//清空引导标识 Romsta&=0XF0; //清空计数器 } } } /*捕获中断*/ if(Timer_A_getCaptureCompareEnabledInterruptStatus(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2)) { Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2); /*捕获到下降沿*/ if(Timer_A_getSynchronizedCaptureCompareInput(TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2,TIMER_A_READ_CAPTURE_COMPARE_INPUT) ==TIMER_A_CAPTURECOMPARE_INPUT_LOW) { IRCapValue2=Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2); IRCapValue=IRCapValue2-IRCapValue1+IRcount*65536; IRcount=0; /*接收到引导码*/ if(Romsta&0x80) { if(IRCapValue>300&&IRCapValue<800)//560为标准值,560us { RmtRec<<=1; //左移一位. RmtRec|=0; //接收到0 }else if(IRCapValue>1400&&IRCapValue<1800) //1680为标准值,1680us { RmtRec<<=1; //左移一位. RmtRec|=1; //接收到1 }else if(IRCapValue>2200&&IRCapValue<2600) //得到按键键值增加的信息 2500为标准值2.5ms { RmtCnt++; //按键次数增加1次 Romsta&=0XF0; //清空计时器 } } /*接收引导码*/ else if(IRCapValue>4200&&IRCapValue<4700) //4500为标准值4.5ms { Romsta|=1<<7; //标记成功接收到了引导码 RmtCnt=0; //清除按键次数计数器 RmtRec=0; } Romsta&=~(1<<4); } /*捕获到上升沿*/ else { IRCapValue1=Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2); Romsta|=0x10; IRcount=0; } } } //扫描遥控器 uint8_t RomateScan(void) { uint8_t sta=0; uint8_t t1,t2; if(Romsta&0x40) { t1=RmtRec>>24;//得到地址码 t2=(RmtRec>>16)&0xff;//得到地址反码 if((t1==(uint8_t)~t2)&&t1==REMOTE_ID)//检验遥控识别码(ID)及地址 { t1=RmtRec>>8; t2=RmtRec; if(t1==(uint8_t)~t2) sta=t1;//键值正确 } if((sta==0)||((Romsta&0X80)==0))//按键数据错误/遥控已经没有按下了 { Romsta&=~(1<<6);//清除接收到有效按键标识 RmtCnt=0; //清除按键次数计数器 } } return sta; }
一个用这种遥控器遥控小车的例子:
https://v.youku.com/v_show/id_XNDA4Nzk4OTEwNA==.html?spm=a2h3j.8428770.3416059.1