【CC2530 教程 十三】CC2530 Z-Stack 协议栈HAL调用

目录

一、HAL 调用 LED:

(1)LED 函数:

(2)物理映射确认:

(3)LED API应用:

二、HAL 调用 key:

(1)KEY 函数:

(2)处理按键事件:

(3)KEY API应用:

(4)HAL KEY框架:

三、HAL 调用 uart: 

(1)uart 函数:

(2)串口配置:

(3)设置回调函数:

四、HAL 调用 ADC: 

(1)ADC函数:

(2)ADC配置:


一、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读取。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

The_xzs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值