【BLE】CC2541之自己定义长短按键

本篇博文最后改动时间:2017年01月06日,11:06。

一、简单介绍

本文以SimpleBLEPeripheral为例,介绍怎样将普通IO口(P12)自己定义为长短按键,实现按键3S以内松开为短按键、3S之后松开为长按键。

注:本文加入按键方法不与协议栈的按键相冲突,协议栈自带的按键仍可正常使用。

二、实验平台

协议栈版本号:BLE-CC254x-1.4.0

编译软件:IAR 8.20.2

硬件平台:smart RF开发板(主芯片CC2541)

、版权声明

博主:甜甜的大香瓜

声明:喝水不忘挖井人。转载请注明出处。

原文地址:http://blog.csdn.NET/feilusia

联系方式:[email protected]

香瓜BLE之CC2541群:127442605

香瓜BLE之CC2640群:557278427

香瓜BLE之Android群:541462902

香瓜单片机之STM8/STM32群:164311667

甜甜的大香瓜的小店(淘宝店):https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i

四、实验前提

1、在进行本文步骤前,请先阅读下面博文:

1)《CC2541之按键》:http://blog.csdn.net/feilusia/article/details/47336473

2)《CC2541之自己定义按键》:http://blog.csdn.net/feilusia/article/details/50535963

2、在进行本文步骤前,请先实现下面博文:

暂无

五、基础知识

暂无

六、实验步骤

1、编写并加入自己定义的按键驱动

1)写一个按键驱动Key.C(存放在“……\BLE-CC254x-1.4.0\Projects\ble\SimpleBLEPeripheral\Source\GUA”路径下)

//******************************************************************************
//name:         Key.c
//introduce:    香瓜自己定义的按键驱动
//author:       甜甜的大香瓜
//changetime:   2016.2.23
//email:        [email protected]
//******************************************************************************
#include <ioCC2540.h>
#include "Key.h"  

/*********************宏定义************************/
//注冊时使用的宏
#define NO_TASK_ID                      0xFF            //没有注冊时的任务id
#define NO_EVEN_ID                      0x0000          //没有注冊时的事件id  

//中断消抖时使用的宏
#define KEY_DEBOUNCE_VALUE  20          //消抖时间20ms  

#ifndef false
#define false 0
#endif  

#ifndef true
#define true 1
#endif  

typedef signed   char   int8;     //!< Signed 8 bit integer
typedef unsigned char   uint8;    //!< Unsigned 8 bit integer  

typedef signed   short  int16;    //!< Signed 16 bit integer
typedef unsigned short  uint16;   //!< Unsigned 16 bit integer  

typedef signed   long   int32;    //!< Signed 32 bit integer
typedef unsigned long   uint32;   //!< Unsigned 32 bit integer  

/*********************内部变量************************/
static U8 registeredKeyTaskID = NO_TASK_ID;
static U16 registeredKeyEvenID = NO_EVEN_ID;  

/*********************函数声明************************/
extern uint8 osal_start_timerEx( uint8 task_id, uint16 event_id, uint32 timeout_value );  

//******************************************************************************
//name:             Key_Init
//introduce:        按键初始化
//parameter:        none
//return:           none
//author:           甜甜的大香瓜
//changetime:       2016.1.8
//******************************************************************************
void Key_Init(void)
{
    P1SEL &= ~(1 << 2); //P12设置为IO口
    P1DIR &= ~(1 << 2); //P12设置为输入
    P1INP &= ~(1 << 2); //P1上拉下拉模式
    P2INP &= ~(1 << 6); //P1上拉
    P1_2 = 1;           //P12拉高  

    P1IFG &= ~(1 << 2); //初始化P12中断标志位
    PICTL |= (1 << 1);  //下降沿触发
    P1IEN |= (1 << 2);  //使能P12中断
    IEN2 |= (1 << 4);   //同意P1口中断;
}  

//******************************************************************************
//name:             RegisterForKey
//introduce:        注冊任务号、处理事件号
//parameter:        task_id:任务id
//                  even_id:事件id
//return:           true:注冊成功
//                  flase:注冊不成功
//author:           甜甜的大香瓜
//changetime:       2016.1.8
//******************************************************************************
U8 RegisterForKey(U8 task_id, U16 even_id)
{
  // Allow only the first task
  if ( registeredKeyTaskID == NO_TASK_ID )
  {
    registeredKeyTaskID = task_id;
  }
  else
    return ( false );  

  // Allow only the first even
  if ( registeredKeyEvenID == NO_EVEN_ID )
  {
    registeredKeyEvenID = even_id;
  }
  else
    return ( false );  

  return ( true );
}  

//******************************************************************************
//name:             Key_Check_Pin
//introduce:        按键检測高低电平状态
//parameter:        none
//return:           KEY_LOOSEN:此时无按键按下
//                  KEY_PRESS:此时按键按下
//author:           甜甜的大香瓜
//changetime:       2016.1.8
//******************************************************************************
U8 Key_Check_Pin(void)
{
  if(P1 & (1 << 2))
  {
    return KEY_LOOSEN;
  }
  else
  {
    return KEY_PRESS;
  }
}  

//******************************************************************************
//name:             P1_ISR
//introduce:        P1的中断入口
//parameter:        none
//return:           none
//author:           甜甜的大香瓜
//changetime:       2016.1.8
//******************************************************************************
#pragma vector = P1INT_VECTOR
__interrupt void P1_ISR(void)
{
    if(Key_Check_Pin() == KEY_PRESS)
    {
      osal_start_timerEx(registeredKeyTaskID, registeredKeyEvenID, KEY_DEBOUNCE_VALUE);
    }
    P1IFG = 0;       //清中断标志
    P1IF = 0;        //清中断标志
}  

2)写一个按键头文件Key.h(存放在“……\BLE-CC254x-1.4.0\Projects\ble\SimpleBLEPeripheral\Source\GUA”路径下)

//******************************************************************************
//name:         Key.h
//introduce:    香瓜自己定义的按键驱动
//author:       甜甜的大香瓜
//changetime:   2016.2.23
//email:        [email protected]
//******************************************************************************
#ifndef KEY_H
#define KEY_H  

#ifndef U8
typedef unsigned char U8;
#endif  

#ifndef U16
typedef unsigned short U16;
#endif  

//检測io口状态时使用的宏
#define KEY_LOOSEN                      0x01
#define KEY_PRESS                       0x00  

extern void Key_Init(void);
extern U8 RegisterForKey(U8 task_id, U16 even_id);
extern U8 Key_Check_Pin(void);  

#endif  

3)project中加入Key.c和Key.h

4)在IAR设置中加入按键驱动源文件路径

$PROJ_DIR$\..\..\SimpleBLEPeripheral\Source\GUA  

2、定义按键消抖事件、按键处理事件

1)定义按键消抖事件、按键处理事件(SimpleBLEPeripheral.c的SimpleBLEPeripheral_ProcessEvent中)

  //按键消抖事件
  if ( events & SBP_KEY_DEBOUNCE_EVT )
  {
    //防止抖动,确定是按键
    if(Key_Check_Pin() == KEY_PRESS)
    {
      //定时300ms检測一次按键。假设3S内松开则为短按键,超过3S松开则为长按键
      osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_KEY_CHECK_PROCESS_EVT, SBP_KEY_CHECK_PROCESS_EVT_PERIOD );
    }      

    return (events ^ SBP_KEY_DEBOUNCE_EVT);
  } 

  //按键检測处理事件
  if ( events & SBP_KEY_CHECK_PROCESS_EVT )
  {
    //检測是否按键已经松开
    if(Key_Check_Pin() == KEY_PRESS)
    {
      //假设超时,则算长按键,直接进行长按键的处理
      if(++nKey_Time > KEY_TIMER_OVER)
      {
        //标记为长按键
        nKey_State = KEY_STATE_LONG;

        //时长清零
        nKey_Time = 0;
      }
      else
      {
        //定时300ms检測一次按键。假设3S内松开则为短按键,超过3S松开则为长按键
        osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_KEY_CHECK_PROCESS_EVT, SBP_KEY_CHECK_PROCESS_EVT_PERIOD );
      }
    }
    else
    {
        //标记为短按键
        nKey_State = KEY_STATE_SHORT;

        //时长清零
        nKey_Time = 0;
    }

    switch(nKey_State)
    {
      //短按键处理
      case KEY_STATE_SHORT:
        {
          //运行短按键函数
          GUA_Key_Short_Process();

          //清除标志
          nKey_State = KEY_STATE_IDLE;

          break;
        }

      //长按键处理
      case KEY_STATE_LONG:
        {
          //运行长按键函数
          GUA_Key_Long_Process();

          //清除标志
          nKey_State = KEY_STATE_IDLE;

          break;
        } 

      //其它
      default:break;
    }

    return (events ^ SBP_KEY_CHECK_PROCESS_EVT);
  } 

2)定义按键消抖事件的宏、按键处理事件的宏(SimpleBLEPeripheral.h中)

#define SBP_KEY_DEBOUNCE_EVT            0x1000  //按键消抖时间
#define SBP_KEY_CHECK_PROCESS_EVT       0x2000  //按键检測处理事件

3、定义并声明长、短按键处理函数(SimpleBLEPeripheral.c中)

1)定义长、短按键处理函数

//******************************************************************************
//name:             GUA_Key_Short_Process
//introduce:        短按键处理函数
//parameter:        none
//return:           none
//author:           甜甜的大香瓜
//changetime:       2016.02.23
//******************************************************************************
static void GUA_Key_Short_Process(void)
{
  //test
  P1_0 = ~P1_0;         //这里測试按一次按键,就取反一次P1_0,方便观察P1_0相应的led
  P1SEL &= ~(1 << 0);   //设置为IO口
  P1DIR |= (1 << 0);    //设置为输出
  //test
}  

//******************************************************************************
//name:             GUA_Key_Long_Process
//introduce:        长按键处理函数
//parameter:        none
//return:           none
//author:           甜甜的大香瓜
//changetime:       2016.02.23
//******************************************************************************
static void GUA_Key_Long_Process(void)
{
  //test
  P1_1 = ~P1_1;         //这里測试按一次长按键按键,就取反一次P1_1,方便观察P1_1相应的led
  P1SEL &= ~(1 << 1);   //设置为IO口
  P1DIR |= (1 << 1);    //设置为输出
  //test
}  

2)声明长、短按键处理函数

static void GUA_Key_Short_Process(void);
static void GUA_Key_Long_Process(void);

4、在应用层中使用按键

1)按键初始化(SimpleBLEPeripheral.c的SimpleBLEPeripheral_Init中)

  //按键初始化
  Key_Init();
  RegisterForKey(simpleBLEPeripheral_TaskID, SBP_KEY_DEBOUNCE_EVT);  

2)应用层代码中加入按键驱动头文件(SimpleBLEPeripheral.c中)

//GUA
#include "Key.h"
//GUA  

3)加入必要的宏(SimpleBLEPeripheral.c中)

//香瓜
//按键扫描时间
#define SBP_KEY_CHECK_PROCESS_EVT_PERIOD        300

//超过这个时长。则算长按键
#define KEY_TIMER_OVER                          10        

//按键状态
#define KEY_STATE_IDLE                          0
#define KEY_STATE_SHORT                         1
#define KEY_STATE_LONG                          2
//香瓜

这里设置为300ms检測一次按键,而且计数加1。假设计数到KEY_TIMER_OVER,则直接判定为长按键。

4)加入必要的静态变量(SimpleBLEPeripheral.c中)

//香瓜
//按键按下的时长
static uint8 nKey_Time = 0;

//按键状态
static uint8 nKey_State = KEY_STATE_IDLE;
//香瓜

七、注意事项

暂无

八、实验结果

手头没有按键,因此拿一根跳线,一端接在GND,还有一端不停地触碰P12引脚,则会发现:

1)跳线触碰P12引脚3S以内时(短按键)

P10相应的LED1的状态会变化一次。

2)跳线触碰P12引脚3S以上时(长按键)

P11相应的LED2的状态会变化一次。

实现了将普通IO口P12改动为长、短按键。并通过长短按键的不同,分别触发P11的led2亮灭、P10的led1亮灭。

因此。实验成功。

时间: 2025-01-02 11:23:19

【BLE】CC2541之自己定义长短按键的相关文章

TI BLE CC2541的I2C主模式

由于要写TM1680, 写命令跟写数据, 所以需要使用CC2541的I2C, 2541是有硬件I2C的. tm1680.c: #include "tm1680.h" //TM1680是先发送配置, 然后发送数据.void masterConfig(void);void masterSendData(void); void sendTest(void){    //uint8 buffer[24]={0x0f,0x0e};    //HalI2CWrite(2, buffer);   

ugui用户定义操作按键

界面很简单,只创建了一Image,Image下边有一个Text.基本思路是点击Image,Text清空,进入修改状态,然后用户按下任意键,按下的任意键极为修改后的键 然后下面的脚本是挂在Image下面的 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using System; p

TI BLE CC2541的SPI主模式

SPI就是用4条线来串行传输数据, 2541只能用模拟的方式用GPIO来做. //******************************************************************************//                      INCLUDES//******************************************************************************#include <ioCC2541.

基于状态机的按键扫描的实现

一般的按键输入软件接口程序非常简单,在程序中一旦检测到按键输入口为低电平(有时可能为高),便采用软件延时的方 法来进行消抖,然后再次检测按键输入,如果再次确认为低电平则表示有按键按下,转入执行按键处理程序.如果延时后检测的电平为高电平则放弃本次按键检测, 重新开始一次按键检测过程.在简单的系统中这种方法比较可以用,但是在复杂的系统实时性要求较高的系统中这种方法的CPU利用率比较低,造成资源的浪费. 另外,由于在不同的产品系统中对按键功能的定义和使用方式也会不同,而且是多变的,加上在测试和按键处理

20150218【改进】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

[改进]IMX257实现GPIO-IRQ中断按键获取键值驱动程序 2015-02-18 李海沿 一.使用struct pin_desc 管理按键的值 1.定义结构体 2.将前面我们申请中断时写的(void *)1修改为 &pins_desc[n] 在ioctl中,设置中断中修改 在key_release中释放中修改 3.在中断程序中利用我们定义的struc pins_desc判断并得到按键的值 4.得到按键键值后,唤醒程序,在read函数中返回键值 附上驱动源程序: 1 /***********

20150218【改进信号量】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

[改进信号量]IMX257实现GPIO-IRQ中断按键获取键值驱动程序 2015-02-18 李海沿 前面我们使用POLL查询方式来实现GPIO-IRQ按键中断程序 这里我们来使用信号量,让我们的驱动同时只能有一个应用程序打开. 一.首先在前面代码的基础上来一个简单的信号 1.定义一个全局的整形变量 2.在打开函数中,每次进入打开函数canopen都自减1, 3.当我们不使用时,在realease 中canopen自加1 4.这样就实现了一个简单的信号量,我们编译,测试 当我们使用两个应用程序来

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

[改进Poll定时查询]IMX257实现GPIO-IRQ中断按键获取键值驱动程序 2015-02-18 李海沿 按键驱动程序中,如果不使用read函数中使程序休眠的,而是还是使用查询方式的话,可以使用Poll函数,来控制一定时间内,如果有按键发生,则立即返回键值. 同时,poll也可以同时监控多个(比如说按键,鼠标,等)一旦发生事件则立即返回. 我们在linux查看帮助: 从帮助中的说明得知, poll, ppoll - wait for some event on a file descrip

键值转换--复杂按键事件识别程序(链接层)

复杂按键事件识别程序(链接层) 复杂按键包括多个按键的单按事件.长按事件.连按事件.组合按键事件等 本程序为链接层程序,处理和识别按键驱动层扫描到的按键信息g_u8KeyValue.(g_u8KeyValue的每一位表示一个按键) 单按事件在按下键松开时判定,其它按键情况在达到规定的时间后触发相应按键事件. 宏定义: //宏定义各按键按下时的bit值 #define KEY_EVENT_NULL_CLICK 0x00 #define KEY_EVENT_CLOCK_CLICK 0x01 #def

Android事件处理下(按键、触摸屏和滚动球的一些实现细节)

http://www.cnblogs.com/andtt/articles/2145563.html 对于按键事件,调用mDevices[i]->layoutMap->map进行映射.映射实际是由 KeyLayoutMap::map完成的,KeyLayoutMap类里读取配置文件qwerty.kl,由配置 文件 qwerty.kl 决定键值的映射关系.你可以通过修 改./development/emulator/keymaps/qwerty.kl来改变键值的映射关系. JNI 函数 在fram