3845|2

8616

帖子

8

资源

管理员

按键与红外遥控接收(三)数字时钟的设计 [复制链接]

文章节选自:《ARM Cortex-M0从这里开始》 作者:zhaojun_xf   http://bbs.eeworld.com.cn/thread-324656-1-1.html

 

按键与红外遥控接收
    数字时钟设置采用按键和红外遥控两种方式,极大的方便了时钟是设置。
1  遥控概述
红外遥控是目前使用最为广泛的一种通信方式。由于红外遥控装置具有体积小、功耗低、功能强、成本低等特点。
1. 红外遥控系统
通用红外遥控系统由发射和接收两大部分组成,应用编/解码专用集成电路芯片来进行控制操作,如图8-9所示。

                未命名1.jpg

2. 红外遥控发射编码
一般红外电视遥控器的输出都是用编码后串行数据对38~40kHz的方波进行脉冲幅度调制而产生的。当发射器按键按下后,即有遥控码发出,所按的键不同遥控编码也不同。这种遥控码具有以下特征:
遥控发射的一帧码含有一个引导码,16位的用户编码和8位的键数据码、键数据码的反码也同时被传送。码型结构如下:

                  未命名2.jpg

引导码由一个9ms的载波波形和4.5ms的关断时间构成,随后跟随4字节编码。这4字节的编码由低8位用户编码、高8位用户编码、8位键数据码和8位键数据码的反码。编码采用脉冲位置调制方式(PPM)。利用脉冲之间的时间间隔来区分“0”和“1”。每次8位的码被传送之后,它们的反码也被传送,减少了系统的误码率。
3. 位定义
用户码或数据码中的每一个位可以是位“1”,也可以是位“0”。不同厂家的脉冲编码、码型和码流是不一样的。本书使用的遥控码型如图8-11所示。

                   未命名3.jpg

2  硬件电路的设计
时钟的设置通过按键和遥控两种方式同时进行,图8-9所示为按键电路图,图8-10所示为遥控接收电路图。
LPC1100系列微处理器虽然内部有上下拉电阻,但是电阻阻值为40KΩ左右,属于弱上拉,为了保证电路的可靠性和通用性,在这里还是加上了10KΩ的上拉电阻。

                                       未命名41.jpg

                                                                             未命名42.jpg

红外遥控接收的连接非常简单,只要分别连接好电源和数据输出端口即可。

                                                  未命名5.jpg

3 程序设计
为了能够及时接收到按键和红外遥控值,这里的按键输入和红外遥控输入均采用中断方式接收。具体代码下面将详细介绍。
1. 按键接收
(1)初始化函数
本函数主要是完成按键端口的设置及中断的初始化工作,使按键产生时,处理器能够正常的识别按键。所以先设置端口均为输入端口,采用低电平触发中断,之后使能每个端口的中断。
/******************************  程序清单8-9  **********************************/
/********************************************************************************
* FunctionName   : KeyInit()
* Description    : 初始化按键
* EntryParameter : None
* ReturnValue    : None
********************************************************************************/
void KeyInit(void)
{
    // 设置为输入端口
 GPIOSetDir(KEY_PORT, KEY1, 0);
 GPIOSetDir(KEY_PORT, KEY2, 0);
 GPIOSetDir(KEY_PORT, KEY3, 0);
 GPIOSetDir(KEY_PORT, KEY4, 0);
 GPIOSetDir(KEY_PORT, KEY5, 0);
 GPIOSetDir(KEY_PORT, KEY6, 0);

 // 设置为低电平中断
 GPIOSetInterrupt(KEY_PORT, KEY1, 1, 0, 0);
 GPIOSetInterrupt(KEY_PORT, KEY2, 1, 0, 0);
 GPIOSetInterrupt(KEY_PORT, KEY3, 1, 0, 0);
 GPIOSetInterrupt(KEY_PORT, KEY4, 1, 0, 0);
 GPIOSetInterrupt(KEY_PORT, KEY5, 1, 0, 0);
 GPIOSetInterrupt(KEY_PORT, KEY6, 1, 0, 0);

 // 使能中断
 GPIOIntEnable(KEY_PORT, KEY1);
 GPIOIntEnable(KEY_PORT, KEY2);
 GPIOIntEnable(KEY_PORT, KEY3);
 GPIOIntEnable(KEY_PORT, KEY4);
 GPIOIntEnable(KEY_PORT, KEY5);
 GPIOIntEnable(KEY_PORT, KEY6);

 NVIC_EnableIRQ(KEY_EINT);        // 使能PORT中断
}
(2)中断服务函数
产生中断后,我们并不知道是哪个端口产生的,所以需要分别读取中断管脚的状态。如果读取是值为1,表示有键按下。此时,对按键赋值,清除相应管脚中断并退出,否则表示无键按下。
/******************************  程序清单8-10 **********************************/
/********************************************************************************
* FunctionName   : PIOINT1_IRQHandler()
* Description    : 中断服务函数
* EntryParameter : None
* ReturnValue    : None
********************************************************************************/
void PIOINT1_IRQHandler(void)

    uint32 key;

  key = GPIOIntStatus(KEY_PORT, KEY1);
    if (key == 1)
 {
     KeyValue = KEY_OK;
  GPIOIntClear(KEY_PORT, KEY1);
  return ;
 }
 
 key = GPIOIntStatus(KEY_PORT, KEY2);
 if (key == 1)
 {
     KeyValue = KEY_VOLM;
  GPIOIntClear(KEY_PORT, KEY2);
  return ;
 }
 
 key = GPIOIntStatus(KEY_PORT, KEY3);
 if (key == 1)
 {
     KeyValue = KEY_VOLP;
  GPIOIntClear(KEY_PORT, KEY3);
  return ;
 }
 
 key = GPIOIntStatus(KEY_PORT, KEY4);
 if (key == 1)
 {
     KeyValue = KEY_DOWN;
  GPIOIntClear(KEY_PORT, KEY4);
  return ;
 }
 
 key = GPIOIntStatus(KEY_PORT, KEY5);
 if (key == 1)
 {
     KeyValue = KEY_UP;
  GPIOIntClear(KEY_PORT, KEY5);
  return ;
 }
 
 key = GPIOIntStatus(KEY_PORT, KEY6);
 if (key == 1)
 {
     KeyValue = KEY_EXIT;
  GPIOIntClear(KEY_PORT, KEY6);
  return ;
 }  
}
2. 红外遥控
(1)红外解码函数
通过上面的介绍知道,遥控在被按下时,会按顺序发送4个字节的数据。对于应用来说,只需要获取第3字节数据就可以了。但是,接收时必须把4个字节数据都接收完成,特别是第4字节数据,它是按键的键值反码,接收这一字节数据并与第3字节进行比较,可以在很大程度上减少误码的产生。
对于红外解码来说关键在于延时时间的处理。读者在处理延时函数时,如果用for循环来实现,最好用示波器来观察延时的长度,以保证解码的顺利进行。如果没有条件也可以采用MDK的软件模拟来模拟延时函数的运行时间。
/******************************  程序清单8-11 **********************************/
/********************************************************************************
* FunctionName   : IrDecode()
* Description    : 红外解码函数,利用普通端口解码,也可以用外中断解码
* EntryParameter : None
* ReturnValue    : 返回按键编码
********************************************************************************/
uint8 IrDecode(void)
{
    uint8 i,j,num = 0;
  uint8 tmp = 0;
  uint8 irCom[4] = {0x00,0x00,0x00,0x00};
  // irCom[0]和IRCOM[1]存放用户编码;irCom[2]键值码暂存;irCom[3]键值反码存放。

 do                                                // 读引导码
 {
     for (i=0; i<4; i++)
  {
      if (IR_READ() == 0)
   {
        break;
   }

   if (i == 3)
   {
       return IR_NO;
   }
  }

  Ir_Delay(20);
 }while (IR_READ() != 0);
 
 while(IR_READ() == 0)                           // 等IR变为高电平
 {
      Ir_Delay(1);
 }                       
 
    // 读4字节按键编码 = 16位的用户码+8位键值码+8位键值反码 
 for (i=0; i<4; i++)
  {
     for (j=0; j<8; j++)                           // 8位一接收
     {
      while (IR_READ() != 0)                // 等 IR 变为低电平
     {
         Ir_Delay(1);
     }  
            
       while (IR_READ() == 0)                // 等 IR 变为高电平
     {
         Ir_Delay(1);
     }  
                 
        while (IR_READ() != 0)                     // 计算IR高电平时长
        {
         Ir_Delay(1);
         num++;          
         if (num >= 30)
      {
          return IR_NO;
      }
     }

        irCom >>= 1;                            // 接收数据右移一位
        if (num >= 8)
     {
          irCom |= 0x80;  // 电平长度大于等于8,则写入高电平
     }
        num = 0;
     }                         // 读完一字节
  }                            // 按键4字节读完
                                // 接收数据检测  
 tmp = ~irCom[3];              // 反码取反,如果反码不暂存而是直接使用,会错误
 if (irCom[2] != tmp)          // 8位键码!=8位键反码:按键错误
 {
     return IR_NO;
 }  

 return irCom[2];                                  // 返回编码
}
(2)获取按键值
在通过接收头得到红外信号并通过上面的函数解码后,我们需要对按键功能进行定义才能使用。不同遥控就算遥控上的标号是一样的,但是解码获取的码值不一定相同。所以,在接收到解码值后需要定义其含义才能使用。
程序清单8-12所示为本设计使用的遥控键值的定义,采用两个按键表示同一的功能,具体按键位置,读者可以参见表8-1。case后面的值就算遥控解码获取的,value为此值对应的含义。读者在使用其他遥控时,需通过解码函数获取按键的键值,放在对应的case语句后面即可。
/******************************  程序清单8-12 **********************************/
/********************************************************************************
* FunctionName   : IrGetValue()
* Description    : 获取按键值
* EntryParameter : None
* ReturnValue    : 返回按键值
********************************************************************************/
uint8 IrGetValue(void)
{
    uint8 value = IR_NO;

 value = IrDecode();           // 获取按键编码
 switch (value)
 {
  case 0x04:
  case 0x1E: value = IR_OK;    break;      // 确定键
  case 0x15:
     case 0x00: value = IR_VOLP;  break;      // 声音加
  case 0x4D:
  case 0x4C: value = IR_VOLM;  break;      // 声音减
  case 0x0C:
  case 0x16: value = IR_UP;    break;      // 上翻
  case 0x0F:
  case 0x0E: value = IR_DOWN;  break;      // 下翻
  case 0x10:
  case 0x0A: value = IR_EXIT; break;      // 退出
  default  : value = IR_NO;    break;      // 没有按键
 }

 if (KeyValue != IR_NO)    // 这样判断是为了保证中断按键的有效操作
 {
    return KeyValue;     // 有中断按键,保存按键值不变
 }
 else
 { 
  return (value);     // 返回红外按键值
 }
}


此帖出自NXP MCU论坛

扫一扫,关注 EEWORLD 微信订阅号

行业资讯、电子趣闻、技术干货、精彩活动……尽可掌握~


回复

308

帖子

0

资源

纯净的硅(高级)

学无止境啊!努力学习!

回复

25

帖子

0

资源

一粒金砂(中级)

很好的学习资料,等开发板到手后再实践。

回复
您需要登录后才可以回帖 登录 | 注册

最新文章 更多>>
    关闭
    站长推荐上一条 1/10 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2021 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表