一、红外遥控器介绍
红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。同类产品的红外线遥控器,可以有相同的遥控频率或编码,而不会出现遥控信号“串门”的情况。红外遥控的编码目前广泛使用的是:NEC Protocol 的PWM(脉冲宽度调制)和Philips RC-5 Protocol 的PPM(脉冲位置调制)
二、NEC协议特征和码位定义
(1)协议特征
①8位地址和8位指令长度;
② 地址和命令2次传输(确保可靠性);
③ PWM脉冲宽度调制,以发射红外载波的占空比代表“0”和“1”;
④ 载波频率为38Khz;
⑥ 位时间为1.125ms或2.25ms;
(2)码位定义
NEC码的位定义:一个脉冲对应560us的连续载波,一个逻辑1传输需要2.25ms(560us脉冲+1680us低电平),一个逻辑0的传输需要1.125ms(560us脉冲+560us低电平)。而遥控接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到的信号为:逻辑1应该是560us低+1680us高,逻辑0应该是560us低+560us高。
(3)NEC遥控器指令格式
NEC遥控指令的数据格式为:同步码头、地址码、地址反码、控制码、控制反码。同步码由一个9ms的低电平和一个4.5ms的高电平组成,地址码、地址反码、控制码、控制反码均是8位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。
三、解码接收程序
(1)hwjs.h文件
#ifndef _hwjs_H
#define _hwjs_H
#include "system.h"
/*******GPIO和外部中断设置**********/
void Hwjs_Init(void);
/*******获取高电平的时间以判断接收到的数据**********/
u8 HW_jssj(void);
//定义全局变量
extern u32 hw_jsm;//接收到的数据
extern u8 hw_jsbz;//接收到数据的标志
//0到10的十进制编码(各个遥控器可能有所不同,可用串口测出)
#define Mode_0 16738455
#define Mode_1 16724175
#define Mode_2 16718055
#define Mode_3 16743045
#define Mode_4 16716015
#define Mode_5 16726215
#define Mode_6 16734885
#define Mode_7 16728765
#define Mode_8 16730805
#define Mode_9 16732845
#endif
(2)hwjs.c文件
#include "hwjs.h"
#include "SysTick.h"
u32 hw_jsm; //定义一个32位的数据变量,保存接收码
u8 hw_jsbz; //定义一个8位数据变量,用于指示接收标志
/*******************************************************************************
函数名:Hwjs_Init
函数功能:红外端口初始化函数,时钟端口和外部中断初始化
*******************************************************************************/
void Hwjs_Init(){
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/*开启GPIO时钟及管脚复用时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG|RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;//红外接收引脚
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOG,&GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource15); //把红外接收引脚作为外部中断线路
EXTI_ClearITPendingBit(EXTI_Line15);
/*设置外部中断模式*/
EXTI_InitStructure.EXTI_Line=EXTI_Line15;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
/*设置NVIC参数*/
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //打开全局中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
NVIC_Init(&NVIC_InitStructure);
}
/*******************************************************************************
函数名:HW_jssj
函数功能:高电平持续时间,将记录时间保存在t中返回
*******************************************************************************/
u8 HW_jssj(){
u8 t=0;
while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_15)==1){
t++;
delay_us(20);
if(t>=250) return t;//超时溢出
}
return t;
}
/*红外遥控中断*/
void EXTI15_10_IRQHandler(void) {
u8 Tim=0,Ok=0,Data,Num=0;
while(1){
if(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_15)==1){
Tim=HW_jssj(); //获得此次高电平时间
if(Tim>=250) break; //不是有用信号
if(Tim>=200 && Tim<250)
{
Ok=1; //起始信号
}
else if(Tim>=60 && Tim<90)
{
Data=1; //收到数据1
}
else if(Tim>=10 && Tim<50)
{
Data=0; //收到数据0
}
if(Ok==1){
hw_jsm<<=1;
hw_jsm+=Data;
if(Num>=32){
hw_jsbz=1;
break;
}
}
Num++;
}
}
EXTI_ClearITPendingBit(EXTI_Line15); //清除中断标志
}
(3)调用示例
int main(){
SysTick_Init(72); //设置系统时钟为72M
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //优先级分组
Hwjs_Init(); //红外遥感初始化
USATR1_Init(9600); //串口通信初始化,用于在串口调试助手接收数据
while(1){
if(hw_jsbz==1) //如果红外接收到数据
{
hw_jsbz=0; //清零标志位
printf("红外接收码 %d\r\n",hw_jsm); //串口打印
switch(((int)hw_jsm)){
case Mode_1:
break;
case Mode_2:
break;
case Mode_3:
break;
case Mode_4:
break;
case Mode_5:
break;
case Mode_6:
break;
case Mode_7:
break;
case Mode_8:
` break;
}
}
}
}