ZStack版本:ZStack-CC2530-2.5.1a
下载和调试器:SmartRF04EB
IDE开发软件:IAR Embedded Workbench IDE - 8051 10.20.1
开发平台:基于TI-CC2530的任意厂家的
一、简介
ZStack-CC2530-2.5.1a协议栈中的有非常完备的LED驱动。驱动除了实现基本的“亮”、“灭”功能之外,还可以通过改变参数,同时控制多个LED亮灭、指定LED可调占空比闪烁等等。
本文简单讲解一下ZStack-CC2530-2.5.1a协议栈LED的驱动原理,以及相关移植操作。
二、驱动分析
ZStack协议栈首先是从main()函数开始运行的,我们就从main函数进行分析,
int main( void )
{
// Turn off interrupts
osal_int_disable( INTS_ALL );
// Initialization for board related stuff such as LEDs
HAL_BOARD_INIT();
通过分析,我们发现,main函数的第一条语句是关中断,这个明显与LED没有关系。第二条语句从协议栈给出的注释就可以看是有关于LED的,所以我们进行HAL_BOARD_INIT()函数的定义里,继续分析:
#define HAL_BOARD_INIT() \
{ \
uint16 i; \
\
SLEEPCMD &= ~OSC_PD; /* turn on 16MHz RC and 32MHz XOSC */ \
while (!(SLEEPSTA & XOSC_STB)); /* wait for 32MHz XOSC stable */ \
asm("NOP"); /* chip bug workaround */ \
for (i=0; i<504; i++) asm("NOP"); /* Require 63us delay for all revs */ \
CLKCONCMD = (CLKCONCMD_32MHZ | OSC_32KHZ); /* Select 32MHz XOSC and the source for 32K clock */ \
while (CLKCONSTA != (CLKCONCMD_32MHZ | OSC_32KHZ)); /* Wait for the change to be effective */ \
SLEEPCMD |= OSC_PD; /* turn off 16MHz RC */ \
\
/* Turn on cache prefetch mode */ \
PREFETCH_ENABLE(); \
\
HAL_TURN_OFF_LED1(); \
LED1_DDR |= LED1_BV; \
HAL_TURN_OFF_LED2(); \
LED2_DDR |= LED2_BV; \
HAL_TURN_OFF_LED3(); \
LED3_DDR |= LED3_BV;
通过逐句分析,我们发现有一条语句是HAL_TURN_OFF_LED1(); 从该函数的定义我们可以知道它是关闭LED1,那我们再跳转到HAL_TURN_OFF_LED1(); 这个函数的定义处分析;
#if defined (HAL_BOARD_CC2530EB_REV17) && !defined (HAL_PA_LNA) && !defined (HAL_PA_LNA_CC2590)
#define HAL_TURN_OFF_LED1() st( LED1_SBIT = LED1_POLARITY (0); )
#define HAL_TURN_OFF_LED2() st( LED2_SBIT = LED2_POLARITY (0); )
#define HAL_TURN_OFF_LED3() st( LED3_SBIT = LED3_POLARITY (0); )
#define HAL_TURN_OFF_LED4() HAL_TURN_OFF_LED1()
#define HAL_TURN_ON_LED1() st( LED1_SBIT = LED1_POLARITY (1); )
#define HAL_TURN_ON_LED2() st( LED2_SBIT = LED2_POLARITY (1); )
#define HAL_TURN_ON_LED3() st( LED3_SBIT = LED3_POLARITY (1); )
#define HAL_TURN_ON_LED4() HAL_TURN_ON_LED1()
我们发现这个文件里有大量关于LED的操作,该文件的名称是hal_board_cfg.h。通过分析该文件,发现LED的配置信息均在该文件中,如果需要移植LED驱动,只需要修改此文件即可。
ZStack-CC2530-2.5.1a的驱动里已经有了对LED的,亮,灭,闪烁灯功能的实现函数,这些功能都是通用的,不需要修改,对LED驱动的移植,唯一不同的是各个板子在设计时,LED的管脚位置,LED的个数,LED亮灯的逻辑电平不同而已。
在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
#if defined (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
三、LED驱动移植
本人所使用的板子,总共有两个LED,LED1位于P1_2,LED2位于P1_3,两个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(2)
#define LED1_SBIT P1_2
#define LED1_DDR P1DIR
#define LED1_POLARITY ACTIVE_LOW
#if defined (HAL_BOARD_CC2530EB_REV17)
/* 2 - Red */
#define LED2_BV BV(3)
#define LED2_SBIT P1_3
#define LED2_DDR P1DIR
#define LED2_POLARITY ACTIVE_LOW
/* 3 - Yellow */
#define LED3_BV BV(3)
#define LED3_SBIT P1_3
#define LED3_DDR P1DIR
#define LED3_POLARITY ACTIVE_LOW
#endif
因为我们只有两个LED灯,所以在这我将LED3的配置修改成和LED2一样的配置,如果在程序中使用LED3,则实际操作的是LED2。如果你们的板子有多于3个LED,则只需在下面添加相关配置即可。
四、LED驱动API函数介绍
ZStack-CC2530-2.5.1a协议栈LED的API函数有两个:
/***************************************************************************************************
* @fn HalLedSet
*
* @brief Tun ON/OFF/TOGGLE given LEDs
*
* @param led - bit mask value of leds to be turned ON/OFF/TOGGLE
* mode - BLINK, FLASH, TOGGLE, ON, OFF
* @return None
***************************************************************************************************/
uint8 HalLedSet (uint8 leds, uint8 mode)
该API函数的可取值,见如下代码:
/* LEDS - The LED number is the same as the bit position */
#define HAL_LED_1 0x01
#define HAL_LED_2 0x02
#define HAL_LED_3 0x04
#define HAL_LED_4 0x08
#define HAL_LED_ALL (HAL_LED_1 | HAL_LED_2 | HAL_LED_3 | HAL_LED_4)
/* Modes */
#define HAL_LED_MODE_OFF 0x00
#define HAL_LED_MODE_ON 0x01
#define HAL_LED_MODE_BLINK 0x02
#define HAL_LED_MODE_FLASH 0x04
#define HAL_LED_MODE_TOGGLE 0x08
第二个API函数是:
/***************************************************************************************************
* @fn HalLedBlink
*
* @brief Blink the leds
*
* @param leds - bit mask value of leds to be blinked
* numBlinks - number of blinks
* percent - the percentage in each period where the led
* will be on
* period - length of each cycle in milliseconds
*
* @return None
***************************************************************************************************/
void HalLedBlink (uint8 leds, uint8 numBlinks, uint8 percent, uint16 period)
第一个参数和第一个API函数的第一个参数取值相同。
第二个参数是LED闪烁的次数,如果为0,则一直闪烁。
第三个参数是占空比。
第四个参数是闪烁的周期,单位是ms。
五、驱动测试
我们在上个串口通信工程中进行测试。
在uint16 GenericApp_ProcessEvent( uint8 task_id, uint16 events )事件处理函数的串口事件分支中,添加如下语句:
case CMD_SERIAL_MSG:
HalLedBlink ( HAL_LED_1, 2, 50, 5000 );
HalLedBlink ( HAL_LED_2, 4, 50, 5000 );
HalUARTWrite(0,(((mtOSALSerialData_t *)MSGpkt)->msg)+1,*(((mtOSALSerialData_t *)MSGpkt)->msg));
break;
重新编译工程,下载。通过串口给CC250发送信息,发现发送一次,LED1闪烁2次,LED2闪烁4次,实验成功。