通常红外遥控为了提高抗干扰性能和降低电源消耗,红外遥控器常用载波的方式传送二进制编码,常用的载波频率为38kHz,这是由发射端所使用的455kHz晶振来决定的。在发射端要对晶振进行整数分频,分频系数一般取12,所以455kHz÷12≈37.9kHz≈38kHz。也有一些遥控系统采用36kHz、40 kHz、56 kHz等,一般由发射端晶振的振荡频率来决定。所以,通常的红外遥控器是将遥控信号(二进制脉冲码)调制在38KHz的载波上,经缓冲放大后送至红外发光二极管,转化为红外信号发射出去的。
二进制脉冲码的形式有多种,其中最为常用的是NEC Protocol 的 PWM码(脉冲宽度调制)和 Philips RC-5 Protocol 的 PPM码(脉冲位置调
制码,脉冲串之间的时间间隔来实现信号调制)。如果要开发红外接收设备,一定要知道红外遥控器的编码方式和载波频率,我们才可以选取一体化红外接收头和制定解码方案。
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 高。所以可以通过计算高电平时间判断接收到的数据是0还是1。
NEC码位定义时序图如图
NEC 遥控指令的数据格式为:引导码、地址码、地址反码、控制码、控制反码。引导码由一个 9ms 的低电平和一个 4.5ms 的高电平组成,
地址码、地址反码、控制码、控制反码均是8 位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。数据格式如下:
NEC码还规定了连发码(由 9ms 低电平+2.5m 高电平+0.56ms 低电平+97.94ms 高电平组成),如果在一帧数据发送完毕之后,红外遥控器按
键仍然没有放开,则发射连发码,可以通过统计连发码的次数来标记按键按下的长短或次数。
由于红外接收头在没有脉冲的时候为高电平,当收到脉冲的时候为低电平,所以可以通过外部中断的下降沿触发中断,在中断内通过计算高电平时间来判断接收到的数据是0还是1。
hongwai.c
#include "hw.h"
#include "SysTick.h"
u32 hw_jsm; //全局变量接受码
u32 hw_jsbz; //全局变量接收标志
void hw_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
EXTI_InitTypeDef EXTI_InitStructure; //外部中断结构体
NVIC_InitTypeDef NVIC_InitStructure; //定义NVIC结构体
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//外部中断时钟
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource8); //映射外部中断PA8
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; //输入模式
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;//管脚设置PA8
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度为100M
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化结构体
EXTI_ClearITPendingBit(EXTI_Line8); //清除外部中断线标志
EXTI_InitStructure.EXTI_Line=EXTI_Line8; //PA8
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿触发
EXTI_InitStructure.EXTI_LineCmd=ENABLE; //使能中断线
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //EXTI0中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =1; //子优先级,由于要使用串口打印所以优先级要比串口要高
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}
u8 HW_jssj(void) //红外接受数据高电平时间
{
u8 t;
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8) == 1){
t++;
myDelay_us(20);
if(t>= 250){
return t;
}
}
return t;
}
void EXTI9_5_IRQHandler(void)
{
u8 Tim = 0;
u8 OK = 0;
u8 Data;
u8 Num = 0;
while(1){
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8) == 1){ //读取GPIO输入引脚状态
Tim = HW_jssj();
if(Tim >= 250){ //超过5ms
break;
}
if(Tim>200&&Tim<250){ //引导码:4-5ms之间
OK = 1;
}else if(Tim >=60&&Tim<90){ //逻辑1(1680us):高电平时间在1.2-1.8ms
Data = 1;
}else if(Tim >=10 && Tim<50){ //逻辑0(560us):高电平时间在200us-1ms
Data = 0;
}
if(OK == 1){
hw_jsm <<= 1;
hw_jsm += Data;
if(Num >= 32){
hw_jsbz = 1;
break;
}
}
Num++;
}
}
EXTI_ClearITPendingBit(EXTI_Line8); //清除外部中断线标志
}
hongwai.h
#ifndef __hw_H
#define __hw_H
#include "system.h"
extern u32 hw_jsm;
extern u32 hw_jsbz;
void EXTI9_5_IRQHandler(void);
u8 HW_jssj(void);
void hw_Init(void);
#endif
main.c
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "key.h"
#include "dma.h"
#include "rtc.h"
#include "iic.h"
#include "24cxx.h"
#include "hw.h"
int main()
{
u8 i=0;
u8 key;
u8 k = 0;
SysTick_Init(168);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
LED_Init();
USART1_Init(9600);
KEY_Init();
adcx_Init();
TIM11_CH1_PWM_Init(255,0); //APB2总线,最大时钟168M,168/256 = 656.25KHz
AT24CXX_Init();
hw_Init();
while(1)
{
if(hw_jsbz == 1){ //标志进入中断
hw_jsbz = 0; //红外标志清零
printf("红外接收码%0.8Xd\n\r",hw_jsm);
hw_jsm = 0; //数据清零
}
i++;
if(i%20==0){
led1=!led1;
}
myDelay_ms(10);
}
}