BLE开发笔记——协议栈HAL驱动控制LED
已经了解了OSAL工作原理和完成了启动过程的简单分析,那么我们可以尝试协议栈开发了,首先可以玩一下LED的控制,我有一个CC2541-DK MINI Keyfob,本文就以此为测试平台。
准备工作
新建完整的协议栈工程
这里以SimpleBLEPeripheral例程为基础新建工程,方法可以参考 BLE开发笔记——简单新建属于自己的协议栈工程。
配置工程
- 选择配置文件CC2541
- 右键单击工程,选择Options…,启动Options窗口
- 选择左边栏General Options下的C/C++ Compiler,然后在右侧选择Preprocessor选项卡,操作正确的话,应该会看到Defined symbols:(one per line),要修改其中的宏定义:
- 修改HAL_LED=FALSE为HAL_LED=TRUE
- 修改POWER_SAVING为xPOWER_SAVING以禁用低功耗管理
注:
上述禁用低功耗的原因是协议栈默认LED为耗能元件,系统每次在进入休眠模式的时候会把LED关闭,当唤醒的时候有回复LED的状态,如果不禁用低功耗,LED会一直循环闪烁。
配置硬件
如果你所使用的硬件平台是TI官方开发套件或者是仿TI的硬件,此部分的操作可以忽略,不过我认为还是需要了解一下的。
如果是非官方的设计,对应HAL驱动中LED管脚有可能与官方蓝牙开发套件的设计有区别,官方开发板上LED1对应芯片的P1_0管脚,如果多于一个LED,那么LED2对应P1_1,LED3对应P1_4,LED的配置文件可以在IAR工程目录HAL--->Target--->CC2540EB--->Config
找到,名为hal_board_cfg.h,所以我们可以修改此文件来适配自己设计的硬件电路,默认LED配置代码如下:
/* LED Configuration */
#if defined (HAL_BOARD_CC2530EB_REV17) && !defined (HAL_PA_LNA) && !defined (HAL_PA_LNA_CC2590)
#define HAL_NUM_LEDS 3
#elif defined (HAL_BOARD_CC2530EB_REV13) || defined (HAL_PA_LNA) || defined (HAL_PA_LNA_CC2590)
#define HAL_NUM_LEDS 1
#else
#error Unknown Board Indentifier
#endif
#define HAL_LED_BLINK_DELAY() st( { volatile uint32 i; for (i=0; i<0x5800; i++) { }; } )
/* 1 - Green */
#define LED1_BV BV(0)
#define LED1_SBIT P1_0
#define LED1_DDR P1DIR
#define LED1_POLARITY ACTIVE_HIGH
#ifdef HAL_BOARD_CC2530EB_REV17
/* 2 - Red */
#define LED2_BV BV(1)
#define LED2_SBIT P1_1
#define LED2_DDR P1DIR
#define LED2_POLARITY ACTIVE_HIGH
/* 3 - Yellow */
#define LED3_BV BV(4)
#define LED3_SBIT P1_4
#define LED3_DDR P1DIR
#define LED3_POLARITY ACTIVE_HIGH
#endif
还要注意LED1_POLARITY是来配置IO控制LED发光的有效电平的,默认的Active_HIGH代表IO输出高电平时LED亮,假如我们所用的硬件电路LED连接在了P0_3上,而且是低电平点亮LED,那么若想用LED1控制,那么可以修改LED1的四句配置为下面的样子:
/* 1 - Green */
#define LED1_BV BV(3)
#define LED1_SBIT P0_3
#define LED1_DDR P0DIR
#define LED1_POLARITY ACTIVE_LOW
HAL_LED函数及宏定义
控制LED使用的是HalLedSet函数,有两个参数,第一个参数是LED名称宏定义,第二个参数是LED工作模式宏定义,使用如下:
HalLedSet( HAL_LED_1, HAL_LED_MODE_ON );
这里我们只需要操作LED1,所以第一个参数就用HAL_LED_1就行,LED工作模式宏定义如下:
#define HAL_LED_MODE_OFF 0x00 // 关闭LED
#define HAL_LED_MODE_ON 0x01 // 打开LED
#define HAL_LED_MODE_BLINK 0x02 // 闪烁一次
#define HAL_LED_MODE_FLASH 0x04 // 不断的闪烁,最多255次
#define HAL_LED_MODE_TOGGLE 0x08 // 翻转LED状态
点亮LED
-
首先我们要保证初始化的时候LED是灭的,所以在SimpleBLEPeripheral_Init函数(在simpleBLEPeripheral.c文件中)的最后执行关闭LED的语句:
void SimpleBLEPeripheral_Init( uint8 task_id ) { simpleBLEPeripheral_TaskID = task_id; // Setup the GAP VOID GAP_SetParamValue( TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL ); . . . // 关闭LED HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF ); // Setup a delayed profile startup osal_set_event( simpleBLEPeripheral_TaskID, SBP_START_DEVICE_EVT ); }
-
然后在SimpleBLEPeripheral_ProcessEvent的SBP_START_DEVICE_EVT**事件处理中加上点亮LED的语句:
if ( events & SBP_START_DEVICE_EVT ) { // Start the Device VOID GAPRole_StartDevice( &simpleBLEPeripheral_PeripheralCBs ); // Start Bond Manager VOID GAPBondMgr_Register( &simpleBLEPeripheral_BondMgrCBs ); // 点亮LED HalLedSet( HAL_LED_1, HAL_LED_MODE_ON ); // Set timer for first periodic event osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD ); return ( events ^ SBP_START_DEVICE_EVT ); }
-
编译下载到电路板上,顺利的话可以看到启动后LED保持常亮。
BLINK和FLASH
LED的BLINK和FLASH工作模式效果都是闪烁,不过BLINK是闪烁一次,FLASH是闪烁多次,我们也可以用上面点亮LED的方式测试BLINK和FLASH工作模式,只需更改上面HalLedSet( HAL_LED_1, HAL_LED_MODE_ON );即可,工作模式改为HAL_LED_MODE_BLINK或HAL_LED_MODE_FLASH。_
其实我们可以配置闪烁的周期时间和LED亮所占时间比,FLASH还可以设置闪烁次数,虽然可以闪烁多次,但最多可以闪烁255次,找到工程文件的hal_led.h
文件,会看到如下的配置代码(在这里加了注释):
/* Defaults */
#define HAL_LED_DEFAULT_MAX_LEDS 4 // LED数量
#define HAL_LED_DEFAULT_DUTY_CYCLE 5 // LED亮的占空比,数值是百分比,这里是闪烁周期时间的5%
#define HAL_LED_DEFAULT_FLASH_COUNT 50 // FLASH工作模式的闪烁次数
#define HAL_LED_DEFAULT_FLASH_TIME 1000 // 闪烁周期时间,单位ms,这里周期是1s
可以根据自己需求更改上述的宏定义即可。
LED状态翻转
工作模式使用宏定义HAL_LED_MODE_TOGGLE,在这里我们可以使用定时器触发事件的方式测试这个工作模式。
-
任务初始化中关闭LED
void SimpleBLEPeripheral_Init( uint8 task_id ) { simpleBLEPeripheral_TaskID = task_id; // Setup the GAP VOID GAP_SetParamValue( TGAP_CONN_PAUSE_PERIPHERAL, DEFAULT_CONN_PAUSE_PERIPHERAL ); . . . // 关闭LED HalLedSet( HAL_LED_1, HAL_LED_MODE_OFF ); // Setup a delayed profile startup osal_set_event( simpleBLEPeripheral_TaskID, SBP_START_DEVICE_EVT ); }
-
定义LED翻转事件,这个需要在simpleBLEPeripheral.h文件中添加事件的宏定义SBP_LED_TOGGLE_EVT,默认有两个事件的宏定义,只需添加我们的就可以,事件标识ID是WORD,所以最多可以设置16个事件,一位一个事件,如下的样子:
// Simple BLE Peripheral Task Events #define SBP_START_DEVICE_EVT 0x0001 #define SBP_PERIODIC_EVT 0x0002 #define SBP_LED_TOGGLE_EVT 0x0004
-
添加事件的触发定时器,在SimpleBLEPeripheral_ProcessEvent的设备启动事件处理中添加即可:
if ( events & SBP_START_DEVICE_EVT ) { // Start the Device VOID GAPRole_StartDevice( &simpleBLEPeripheral_PeripheralCBs ); // Start Bond Manager VOID GAPBondMgr_Register( &simpleBLEPeripheral_BondMgrCBs ); // 为LED翻转事件设置触发定时器,时间为500ms osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_LED_TOGGLE_EVT, 500 ); // Set timer for first periodic event osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD ); return ( events ^ SBP_START_DEVICE_EVT ); }
-
可以在设备启动事件处理代码的下面,添加LED翻转事件的处理代码,每个事件的处理后面一定要清掉事件标识:
// LED翻转事件 if ( events & SBP_LED_TOGGLE_EVT ) { HalLedSet( HAL_LED_1, HAL_LED_MODE_TOGGLE ); // 翻转LED osal_start_timerEx( simpleBLEPeripheral_TaskID, SBP_LED_TOGGLE_EVT, 500 ); // 重新设置定时器以实现周期触发事件 return ( events ^ SBP_LED_TOGGLE_EVT ); // 处理完事件,消除事件标识 }
-
编译,下载程序到开发板,一切顺利的话,led每500ms就会翻转一次状态。