ALIENTKE
MiniSTM3开发板给使用者配备了标准的红外接收头和一个很小巧的红外遥控器。本节将向大家介绍,如何在ALIENTEK MiniSTM32开发板上实现红外遥控器的控制。本节分为如下几个部分:
3.21.1 红外遥控简介
3.21.2 硬件设计
3.21.3 软件设计
3.21.4 下载与测试
3.21.1红外遥控简介
红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。
由于红外线遥控不具有像无线电遥控那样穿过障碍物去控制被控对象的能力,所以,在设计红外线遥控器时,不必要像无线电遥控器那样,每套(发射器和接收器)要有不同的遥控频率或编码(否则,就会隔墙控制或干扰邻居的家用电器),所以同类产品的红外线遥控器,可以有相同的遥控频率或编码,而不会出现遥控信号“串门”的情况。这对于大批量生产以及在家用电器上普及红外线遥控提供了极大的方面。由于红外线为不可见光,因此对环境影响很小,再由红外光波动波长远小于无线电波的波长,所以红外线遥控不会影响其他家用电器,也不会影响临近的无线电设备。
红外遥控的编码目前广泛使用的是:NEC Protocol 的PWM(脉冲宽度调制)和Philips
RC-5 Protocol 的PPM(脉冲位置调制)。我们配套的遥控器使用的是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位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。
我们遥控器的按键2按下时,从红外接收头端收到的波形如下:
图3.21.1.1 按键2所对应的红外波形
从图中可以看到,其地址码为0,控制码为168。可以看到在100ms之后,我们还受到了几个脉冲,这是NEC码规定的连发码(由9ms低电平+2.5m高电平+0.56ms低电平+97.94ms高电平组成),如果在一帧数据发送完毕之后,按键仍然没有放开,则发射重复码,即连发码,可以通过统计连发码的次数来标记按键按下的长短/次数
3.21.2 硬件设计
本实验采用中断解码(也可以采用输入捕获解码),本节实验功能简介:开机在LCD上显示一些信息之后,即进入等待红外触发,如过接收到正确的红外信号,则解码,并在LCD上显示键值和所代表的意义,以及按键次数等信息。同样我们也是用LED0来指示程序正在运行。
所要用到的硬件资源如下:
1)STM32F103RBT6。
2)DS0(外部LED0)。
3)TFTLCD液晶模块。
4)红外接收头。
5)红外遥控器。
前面三部分,在之前的实例已经介绍过了,遥控器属于外部器件,遥控接收头在板子上,与MCU的连接原理图如下:
图3.21.2.1 红外遥控接收头与STM32的连接电路图
红外遥控接收头与STM32的PA1通过跳线帽连接,这个在硬件上要连接上,否则PA1将得不到信号,我们采用中断解码,PA1对应的中断为中断1,所以在程序设计的时候,我们只要开启中断1,然后在中断里执行解码就可以了。
3.21.3 软件设计
打开上一节的工程,首先在HARDWARE文件夹下新建一个REMOTE的文件夹。然后新建一个remote.c和remote.h的文件保存在REMOTE文件夹下,并将这个文件夹加入头文件包含路径。
打开remote.c文件,输入如下代码:
#include
"remote.h"
#include
"delay.h"
//Mini
STM32开发板
//红外遥控接收 驱动函数
//正点原子@ALIENTEK
//2010/6/17
u32
Remote_Odr=0; //命令暂存处
u8 Remote_Cnt=0; //按键次数,此次按下键的次数
u8 Remote_Rdy=0; //红外接收到数据
//初始化红外接收引脚的设置
//开启中断,并映射
void
Remote_Init(void)
{
RCC->APB2ENR|=1<<2; //PA时钟使能
GPIOA->CRL&=0XFFFFFF0F;
GPIOA->CRL|=0X00000080; //PA1输入
GPIOA->ODR|=1<<1; //PA.1上拉
Ex_NVIC_Config(GPIO_A,1,FTIR);//将line1映射到PA.1,下降沿触发.
MY_NVIC_Init(2,1,EXTI1_IRQChannel,2);
}
//检测脉冲宽度
//最长脉宽为5ms
//返回值:x,代表脉宽为x*20us(x=1~250);
u8
Pulse_Width_Check(void)
{
u8 t=0;
while(RDATA)
{
t++;delay_us(20);
if(t==250)return t; //超时溢出
}
return t;
}
//处理红外接收
/*-------------------------协议--------------------------
开始拉低9ms,接着是一个4.5ms的高脉冲,通知器件开始传送数据了
接着是发送4个8位二进制码,第一二个是遥控识别码(REMOTE_ID),第一个为
正码(0),第二个为反码(255),接着两个数据是键值,第一个为正码
第二个为反码.发送完后40ms,遥控再发送一个9ms低,2ms高的脉冲,
表示按键的次数,出现一次则证明只按下了一次,如果出现多次,则可
以认为是持续按下该键.
---------------------------------------------------------*/
//外部中断服务程序
void
EXTI1_IRQHandler(void)
{
u8 res=0;
u8 OK=0;
u8 RODATA=0;
while(1)
{
if(RDATA)//有高脉冲出现
{
res=Pulse_Width_Check();//获得此次高脉冲宽度
if(res==250)break;//非有用信号
if(res>=200&&res<250)OK=1; //获得前导位(4.5ms)
else
if(res>=85&&res<200) //按键次数加一(2ms)
{
Remote_Rdy=1;//接受到数据
Remote_Cnt++;//按键次数增加
break;
}
else
if(res>=50&&res<85)RODATA=1;//1.5ms
else
if(res>=10&&res<50)RODATA=0;//500us
if(OK)
{
Remote_Odr<<=1;
Remote_Odr+=RODATA;
Remote_Cnt=0; //按键次数清零
}
}
}
EXTI-> R=1<<1; //清除中断标志位
}
//处理红外键盘
//返回相应的键值
u8
Remote_Process(void)
{
u8 t1,t2;
t1=Remote_Odr>>24; //红外解码
t2=(Remote_Odr>>16)&0xff;
Remote_Rdy=0;//清除标记
if(t1==(u8)~t2&&t1==REMOTE_ID)//检验遥控识别码(ID)
{
t1=Remote_Odr>>8;
t2=Remote_Odr;
if(t1==(u8)~t2)return t1; //处理键值
}
return 0;
}
该部分代码比较简单,主要是通过中断解码,解码程序是按照前面介绍的NEC码来解的,在这里我们就不再多说了。保存remote.c,然后把该文件加入HARDWARE组下。接下来打开remote.h在该文件里面加入如下代码:
#ifndef
__RED_H
#define
__RED_H
#include
"sys.h"
//Mini
STM32开发板
//红外遥控接收 驱动函数
//正点原子@ALIENTEK
//2010/6/17
#define
RDATA PAin(1) //红外数据输入脚
//红外遥控识别码(ID),每款遥控器的该值基本都不一样,但也有一样的.
//我们选用的遥控器识别码为0
#define
REMOTE_ID 0
extern
u8 Remote_Cnt; //按键次数,此次按下键的次数
extern
u8 Remote_Rdy; //红外接收到数据
extern
u32 Remote_Odr; //命令暂存处
void
Remote_Init(void); //红外传感器接收头引脚初始化
u8
Remote_Process(void); //红外接收到数据处理
u8
Pulse_Width_Check(void);//检查脉宽
#endif
这里的REMOTE_ID就是我们开发板配套的遥控器的识别码,对于其他遥控器可能不一样,只要修改这个为你所使用的遥控器的一致就可以了。其他是一些函数的声明,我们保存此部分代码,然后在test.c里面修改主函数如下:
int
main(void)
{
u8 key;
u8 t;
Stm32_Clock_Init(9);//系统时钟设置
delay_init(72); //延时初始化
uart_init(72,9600); //串口1初始化
LCD_Init(); //初始化液晶
LED_Init(); //LED初始化
Remote_Init(); //初始化红外接收
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(60,50,"Mini STM32");
LCD_ShowString(60,70,"REMOTE
TEST");
LCD_ShowString(60,90,"ATOM@ALIENTEK");
LCD_ShowString(60,110,"2010/6/17");
LCD_ShowString(30,130, "KEYVAL:");
LCD_ShowString(130,130,"KEYCNT:");
LCD_ShowString(30,150, "SYMBOL:");
while(1)
{
if(Remote_Rdy)
{
key=Remote_Process();
LCD_ShowNum(86,130,key,3,16);//显示键值
LCD_ShowNum(186,130,Remote_Cnt,3,16);//显示按键次数
switch(key)
{
case 0:
LCD_ShowString(86,150,
"ERROR");
break;
case 162:
LCD_ShowString(86,150,
"POWER ");
break;
case 98:
LCD_ShowString(86,150,
"VOL+ ");
break;
case 2:
LCD_ShowString(86,150,
"VOL- ");
break;
case 226:
LCD_ShowString(86,150,
"CH+ ");
break;
case 194:
LCD_ShowString(86,150,
"CH- ");
break;
case 34:
LCD_ShowString(86,150,
"RECALL");
break;
case 56:
LCD_ShowString(86,150,
"0 ");
break;
case 224:
LCD_ShowString(86,150,
"1 ");
break;
case 168:
LCD_ShowString(86,150,
"2 ");
break;
case 144:
LCD_ShowString(86,150,
"3 ");
break;
case 104:
LCD_ShowString(86,150,
"4 ");
break;
case 152:
LCD_ShowString(86,150,
"5 ");
break;
case 176:
LCD_ShowString(86,150,
"6 ");
break;
case 48:
LCD_ShowString(86,150,
"7 ");
break;
case 24:
LCD_ShowString(86,150,
"8 ");
break;
case 122:
LCD_ShowString(86,150,
"9 ");
break;
case 16:
LCD_ShowString(86,150,
"ZOOM ");
break;
case 90:
LCD_ShowString(86,150,
"STOP ");
break;
case 66:
LCD_ShowString(86,150,
"REC ");
break;
case 82:
LCD_ShowString(86,150,
"TSHIFT");
break;
}
}else delay_ms(2);
t++;
if(t==200)
{
t=0;
LED0=!LED0;
}
}
}
至此,我们的软件设计部分就结束了。
3.21.4 下载与测试
在代码编译成功之后,我们通过下载代码到ALIENTEK MiniSTM32开发板上,可以看到LCD显示如下内容:
图3.21.4.1 开机后LCD显示内容
此时我们通过遥控器按下不同的按键,则可以看到LCD上显示了不同按键的键值以及按键次数和对应的遥控器上的符号。如下图所示:
图3.21.4.2 遥控接收
|