目录
一、HAL 调用 LED:
(1)LED 函数:
在SampleSwitch工程中,LED的API在hal_led.h文件中可以找到,位置如下:
#ifndef HAL_LED_H
#define HAL_LED_H
#ifdef __cplusplus
extern "C"
{
#endif
/*********************************************************************
* INCLUDES
*/
#include "hal_board.h" // 包含硬件板相关的头文件,定义了硬件平台的基本配置和接口
/*********************************************************************
* MACROS
*/
/*********************************************************************
* CONSTANTS
*/
/* LEDS - The LED number is the same as the bit position */
#define HAL_LED_1 0x01 // 定义第一个LED的位掩码,表示第0位(从右往左数第一位)
#define HAL_LED_2 0x02 // 定义第二个LED的位掩码,表示第1位
#define HAL_LED_3 0x04 // 定义第三个LED的位掩码,表示第2位
#define HAL_LED_4 0x08 // 定义第四个LED的位掩码,表示第3位
#define HAL_LED_ALL (HAL_LED_1 | HAL_LED_2 | HAL_LED_3 | HAL_LED_4) // 定义所有LED的位掩码组合
/* Modes */
#define HAL_LED_MODE_OFF 0x00 // LED关闭模式
#define HAL_LED_MODE_ON 0x01 // LED常亮模式
#define HAL_LED_MODE_BLINK 0x02 // LED闪烁模式
#define HAL_LED_MODE_FLASH 0x04 // LED闪光模式
#define HAL_LED_MODE_TOGGLE 0x08 // LED翻转模式(切换当前状态)
/* Defaults */
#define HAL_LED_DEFAULT_MAX_LEDS 4 // 默认支持的最大LED数量
#define HAL_LED_DEFAULT_DUTY_CYCLE 5 // 默认占空比,用于控制LED闪烁或闪光的亮灭时间比例
#define HAL_LED_DEFAULT_FLASH_COUNT 50 // 默认闪光次数
#define HAL_LED_DEFAULT_FLASH_TIME 1000 // 默认每次闪光的时间间隔(单位:毫秒)
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
/*
* Initialize LED Service.
*/
extern void HalLedInit(void); // 声明LED初始化函数,用于初始化LED相关的硬件和变量
/*
* Set the LED ON/OFF/TOGGLE.
*/
extern uint8 HalLedSet(uint8 led, uint8 mode); // 声明设置LED状态的函数,参数为LED编号和模式,返回值表示操作结果
/*
* Blink the LED.
*/
extern void HalLedBlink(uint8 leds, uint8 cnt, uint8 duty, uint16 time); // 声明LED闪烁函数,参数为LED组合、闪烁次数、占空比和时间间隔
/*
* Put LEDs in sleep state - store current values
*/
extern void HalLedEnterSleep(void); // 声明进入睡眠状态的函数,用于保存当前LED状态
/*
* Retore LEDs from sleep state
*/
extern void HalLedExitSleep(void); // 声明退出睡眠状态的函数,用于恢复之前保存的LED状态
/*
* Return LED state
*/
extern uint8 HalLedGetState(void); // 声明获取当前LED状态的函数,返回值为当前所有LED的状态组合
#ifdef __cplusplus
}
#endif
#endif
常用的函数有三个:
/*
* 声明LED初始化函数,用于初始化LED相关的硬件和变量
*/
extern void HalLedInit(void);
/*
* 声明设置LED状态的函数,参数为LED编号和模式,返回值表示操作结果
*/
extern uint8 HalLedSet(uint8 led, uint8 mode);
/*
* 声明LED闪烁函数,参数为LED组合、闪烁次数、占空比和时间间隔
*/
extern void HalLedBlink(uint8 leds, uint8 cnt, uint8 duty, uint16 time);
默认的LED程序中,支持4个LED灯:
/* LEDS - The LED number is the same as the bit position */
#define HAL_LED_1 0x01 // 定义第一个LED的位掩码,表示第0位(从右往左数第一位)
#define HAL_LED_2 0x02 // 定义第二个LED的位掩码,表示第1位
#define HAL_LED_3 0x04 // 定义第三个LED的位掩码,表示第2位
#define HAL_LED_4 0x08 // 定义第四个LED的位掩码,表示第3位
#define HAL_LED_ALL (HAL_LED_1 | HAL_LED_2 | HAL_LED_3 | HAL_LED_4) // 定义所有LED的位掩码组合
HalLedSet( uint8 led, uint8 mode )函数可以设定LED的工作模式。参数1:led用于指定待设定的LED,参数2:mode用于指定工作模式,这个工作模式有4种:
/* Modes */
#define HAL_LED_MODE_OFF 0x00 // LED关闭模式
#define HAL_LED_MODE_ON 0x01 // LED常亮模式
#define HAL_LED_MODE_BLINK 0x02 // LED闪烁模式
#define HAL_LED_MODE_FLASH 0x04 // LED闪光模式
#define HAL_LED_MODE_TOGGLE 0x08 // LED翻转模式(切换当前状态)
如果想要闪烁一个灯可以设置为:
HalLedSet(HAL_LED_1,HAL_LED_MODE_BLINK)
HalLedBlink( uint8 leds, uint8 cnt, uint8 duty, uint16 time )函数的作用是让LED闪烁。参数1:leds用于指定LED,参数2:cnt用于指定闪烁的次数,参数3:duty用于指定LED是开启状态时的占空比,参数4:time用于指定每次闪烁的时间周期(单位:ms)。
例如,让HAL_LED_1,闪烁200次,占空比为50%(高电平占250ms,低电平占250ms),周期为500ms:
HalLedBlink(HAL_LED_1,200,50,500);
(2)物理映射确认:
默认物理映射定义如下:(位于hal_board_cfg.h文件中)
/* 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
#ifdef ENABLE_LED4_DISABLE_S1
/* 4 - Orange */
#define LED4_BV BV(1)
#define LED4_SBIT P0_1
#define LED4_DDR P0DIR
#define LED4_POLARITY ACTIVE_HIGH
#define LED4_SET_DIR() do {LED4_DDR |= LED4_BV;} while (0)
#else
#define LED4_SET_DIR()
#endif
其中,BV表示数值1向左移动n位如下:
- LEDx_SBIT:表示LED对应连接的引脚。
- LEDx_DDR :表示设置对应方向LED寄存器为P1DIR。
- LEDx_POLARITY:表示设置LED的驱动方式,如ACTIVE_HIGH高电平驱动。
上面是协议栈默认的配置,如果需要增加可以根据实际的硬件连接情况进行修改。
(3)LED API应用:
在【CC2530 教程 十一】CC2530 Z-Stack 协议栈软件架构中有介绍,如何添加自定义的事件,并触发处理。
事件代码如下:
// 处理自定义的用户事件:USER_EVENT
if ( events & USER_EVENT )
{
printf("Blink LED!\r\n");
HalLedBlink(
HAL_LED_1,
200,
50,
500);
//消除已经处理的事件,然后返回未处理的事件
return ( events ^ USER_EVENT );
}
启用LED宏定义:
位置如下:
【CC2530 教程 十二】CC2530 Z-Stack 硬件抽象层有介绍
烧录代码:
点击运行:
LED灯闪烁并输出打印 Blink LED:
二、HAL 调用 key:
(1)KEY 函数:
在SampleSwitch工程中,key的API在hal_key.h文件中可以找到,位置如下:
默认的按键中,SW_1~SW_5为方向按键,SW_6和SW_7为常规按键。
同理,在头文件hal_board_cfg.h中可以配置按键与CC2530引脚的对接关系。代码如下:
#define ACTIVE_LOW !
#define ACTIVE_HIGH !! /* double negation forces result to be '1' */
/* S1 */
#define PUSH1_BV BV(1)
#define PUSH1_SBIT P0_1
#if defined (HAL_BOARD_CC2530EB_REV17)
#define PUSH1_POLARITY ACTIVE_HIGH
#elif defined (HAL_BOARD_CC2530EB_REV13)
#define PUSH1_POLARITY ACTIVE_LOW
#else
#error Unknown Board Indentifier
#endif
/* Joystick Center Press */
#define PUSH2_BV BV(0)
#define PUSH2_SBIT P2_0
#define PUSH2_POLARITY ACTIVE_HIGH
按键:
(2)处理按键事件:
按键由OSAL调度,在Z-Stack中使用按键之前,必须要先在OSAL中注册。可以在应用层中注册,应用层的初始化函数zclSampleSw_Init默认已经完成了此注册工作,如下所示:
注册之后,如果按键被按下,那么就会产生一个应用层的系统事件KEY_CHANGE。打开zcl_samplesw.c文件中的zclSampleSw_event_loop函数,可以找到KEY_CHANGE事件的处理函数zclSampleSw_HandleKeys,如下所示:
事件处理函数zclSampleSw_HandleKeys的代码定义如下:
添加自定义处理函数(按下后反转 LED ):
(3)KEY API应用:
启用按键的宏定义:
由于系统是使用中断的方式检测按键行为的所以需要定义宏ISR_KEYINTERRUPT。
HAL_KEY=TRUE
ISR_KEYINTERRUPT
(4)HAL KEY框架:
hal_key.c文件:
在hal_key.c文件中,有以下几个重要函数:
HalKeyInit
HalKeyConfig
HalKeyPoll
HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )
HalKeyInit:
初始化函数,代码如下:
void HalKeyInit( void )
{
/* Initialize previous key to 0 */
halKeySavedKeys = 0;
HAL_KEY_SW_6_SEL &= ~(HAL_KEY_SW_6_BIT); /* 设置引脚功能为GPIO */
#if ! defined ENABLE_LED4_DISABLE_S1
HAL_KEY_SW_6_DIR &= ~(HAL_KEY_SW_6_BIT); /* 设置引脚方向为输入 */
#endif
HAL_KEY_JOY_MOVE_SEL &= ~(HAL_KEY_JOY_MOVE_BIT); /* 设置引脚功能为GPIO*/
HAL_KEY_JOY_MOVE_DIR &= ~(HAL_KEY_JOY_MOVE_BIT); /* 设置引脚方向为输入 */
/* 初始化回调函数 */
pHalKeyProcessFunction = NULL;
/* Start with key is not configured */
HalKeyConfigured = FALSE;
}
HalKeyInit函数主要作用GPIO配置为输入功能。HAL_KEY_SW_6_SEL等定义其实是按键GPIO配置相关的寄存器,这些定义可以在hal_key.c中找到,如果需要添加其他按键,也遵循这个方法添加即可。
HalKeyConfig:
用来配置和中断相关的内容,代码如下:
void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)
{
/* 启用/禁用中断 */
Hal_KeyIntEnable = interruptEnable;
/* 注册回调函数 */
pHalKeyProcessFunction = cback;
/* 确定是否启用中断 */
if (Hal_KeyIntEnable)
{
/* 上升/下降沿配置 */
PICTL &= ~(HAL_KEY_SW_6_EDGEBIT); /* Clear the edge bit */
/* For falling edge, the bit must be set. */
#if (HAL_KEY_SW_6_EDGE == HAL_KEY_FALLING_EDGE)
PICTL |= HAL_KEY_SW_6_EDGEBIT;
#endif
/* Interrupt configuration:
* - Enable interrupt generation at the port
* - Enable CPU interrupt
* - Clear any pending interrupt
*/
HAL_KEY_SW_6_ICTL |= HAL_KEY_SW_6_ICTLBIT;
HAL_KEY_SW_6_IEN |= HAL_KEY_SW_6_IENBIT;
HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT);
/* Rising/Falling edge configuratinn */
HAL_KEY_JOY_MOVE_ICTL &= ~(HAL_KEY_JOY_MOVE_EDGEBIT); /* Clear the edge bit */
/* For falling edge, the bit must be set. */
#if (HAL_KEY_JOY_MOVE_EDGE == HAL_KEY_FALLING_EDGE)
HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_EDGEBIT;
#endif
/* Interrupt configuration:
* - Enable interrupt generation at the port
* - Enable CPU interrupt
* - Clear any pending interrupt
*/
HAL_KEY_JOY_MOVE_ICTL |= HAL_KEY_JOY_MOVE_ICTLBIT;
HAL_KEY_JOY_MOVE_IEN |= HAL_KEY_JOY_MOVE_IENBIT;
HAL_KEY_JOY_MOVE_PXIFG = ~(HAL_KEY_JOY_MOVE_BIT);
/*只有在配置hal_key之后才这样做-与睡眠相关的东西一起工作 */
if (HalKeyConfigured == TRUE)
{
osal_stop_timerEx(Hal_TaskID, HAL_KEY_EVENT); /* 如果轮询活动,取消轮询 */
}
}
else /* Interrupts NOT enabled */
{
HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* 不要产生中断 */
HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT); /* 清除中断使能位 */
osal_set_event(Hal_TaskID, HAL_KEY_EVENT);// 按键轮询
}
/* Key now is configured */
HalKeyConfigured = TRUE;
}
HalKeyPoll:
轮询按键是否按键,代码如下:
void HalKeyPoll(void)
{
uint8 keys = 0; // 定义一个变量用于存储按键状态
// 检查摇杆移动按键是否被按下(按键为高电平有效)
if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT))
{
keys = halGetJoyKeyInput(); // 调用函数获取摇杆按键输入
}
/* 如果中断未启用,则通过比较之前和当前的按键状态
* 来确定是否有按键状态发生变化。
*/
if (!Hal_KeyIntEnable)
{
if (keys == halKeySavedKeys)
{
/* 如果没有按键状态变化,直接退出 */
return;
}
/* 保存当前按键状态,以便下次比较 */
halKeySavedKeys = keys;
}
else
{
/* 如果中断已启用,则在此处理按键中断 */
}
// 检查按钮1是否被按下
if (HAL_PUSH_BUTTON1())
{
keys |= HAL_KEY_SW_6; // 如果按钮1被按下,设置对应的按键标志
}
/* 如果有新的按键被按下,并且回调函数已注册 */
if (pHalKeyProcessFunction
#ifdef HAL_LEGACY_KEYS
&& keys // 在遗留模式下,仅报告按键按下,不报告按键释放
#endif
)
{
// 调用回调函数处理按键事件
(pHalKeyProcessFunction)(keys, HAL_KEY_STATE_NORMAL);
}
}
如果采用中断方式,检测到中断时去抖然后进入这个函数;如果不是中断方式那么采用周期性轮询查看按键是否按下。
函数HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR ):中断处理函数
中断向量为P0INT_VECTOR也就是P0口的中断,按键连接的是P0_1,按下产生中断就会来到这个函数。
最终中断会在函数halProcessKeyInterrupt()中被处理:
三、HAL 调用 uart:
(1)uart 函数:
在SampleSwitch工程中,uart的API在hal_uart.h文件中可以找到,位置如下:
(2)串口配置:
使用串口前,需要首先配置一下串口,并在应用层初始化函数zclSampleSw_Init中调用一下即可完成串口配置,如下图所示。
void zclSampleSw_InitUart(void)
{
halUARTCfg_t uartConfig;
/* UART Configuration */
uartConfig.configured = TRUE; // 允许配置
uartConfig.baudRate = HAL_UART_BR_115200; // 波特率
uartConfig.flowControl = FALSE; // 关闭硬件流控
uartConfig.flowControlThreshold = 0; // 和流控相关
uartConfig.idleTimeout = 6; // 默认超时时间
uartConfig.rx.maxBufSize = ZCLSAMPLESW_UART_BUF_LEN; // 接收缓冲区大小
uartConfig.tx.maxBufSize = 0; // 发送缓冲区大小
uartConfig.intEnable = TRUE; // 使能中断
uartConfig.callBackFunc = zclSampleSw_UartCB; // 设置回调函数
/* Start UART */
HalUARTOpen(HAL_UART_PORT_0, &uartConfig); // 根据配置打开串口0
}
(3)设置回调函数:
// 串口回调函数
static void zclSampleSw_UartCB(uint8 port, uint8 event)
{
// 定义缓冲区
uint8 zclSampleSw_UartBuf[ZCLSAMPLESW_UART_BUF_LEN];
//获取当前串口接收缓冲区有多少字节的数据
uint8 rxLen = Hal_UART_RxBufLen(HAL_UART_PORT_0);
if(rxLen != 0)//如果字节数数量不等于0
{
//从串口缓冲区中读取数据
HalUARTRead(HAL_UART_PORT_0, zclSampleSw_UartBuf, rxLen);
//通过串口发送数据,进行数据转发
HalUARTWrite(HAL_UART_PORT_0, zclSampleSw_UartBuf, rxLen);
}
}
在hal_uart.h中进函数声明,方便在应用层初始化函数zclSampleSw_Init中调用。
启用串口对应的宏定义HAL_UART,INT_HEAP_LEN,其中HEAP是堆的意思,堆是一块内存空间。当程序动态地申请了一小块内存空间后,这一小块内存空间就来自于堆。工程默认的堆大小是3071个字节。定义宏INT_HEAP_LEN=2048后,堆的大小减少到2048个字节。之所以减少堆的大小,是因为串口通信功能会使用较多的栈内存空间,栈内存空间可能会不够用。
串口查看转发情况:
四、HAL 调用 ADC:
(1)ADC函数:
HAL中ADC驱动API定义在hal_adc.h和hal_adc.c中,如下所示:
在hal_adc.h有定义:
其中ADC位定义如下:
/* Resolution */
#define HAL_ADC_RESOLUTION_8 0x01
#define HAL_ADC_RESOLUTION_10 0x02
#define HAL_ADC_RESOLUTION_12 0x03
#define HAL_ADC_RESOLUTION_14 0x04
通道选择为:
/* Channels */
#define HAL_ADC_CHANNEL_0 0x00
#define HAL_ADC_CHANNEL_1 0x01
#define HAL_ADC_CHANNEL_2 0x02
#define HAL_ADC_CHANNEL_3 0x03
#define HAL_ADC_CHANNEL_4 0x04
#define HAL_ADC_CHANNEL_5 0x05
#define HAL_ADC_CHANNEL_6 0x06
#define HAL_ADC_CHANNEL_7 0x07
常用的API有:
/*
* 初始化ADC服务,将引用设置为默认值
*/
extern void HalAdcInit ( void );
/*
*以给定的分辨率从指定的ADC通道读取值
*/
extern uint16 HalAdcRead ( uint8 channel, uint8 resolution );
/*
* 设置ADC的参考电压
*/
extern void HalAdcSetReference ( uint8 reference );
/*
* 检查指定的最小Vdd。
*/
extern bool HalAdcCheckVdd(uint8 vdd);
/*
* 检查Vdd。
*/
extern uint8 HalAdcCheckVddRaw( void );
(2)ADC配置:
函数HalAdcRead ( uint8 channel, uint8 resolution )用于ADC的相关配置:
param channel - 为ADC通道,对应P0_0 ~ P0_7引脚
resolution - 为采样精度
例如:使用12位的采样精度来采P0_0的ADC值,可以配置为:
uint8 ADC;
ADC= HalAdcRead(HAL_ADC_CHANNEL_0, HAL_ADC_RESOLUTION_8);
可以在应用层的处理函数中,添加需要开启的ADC通道,实现对应引脚的ADC读取。