06_Z-Stack硬件驱动移植
LED移植
在hal_borad.h
文件中,打开其包含的hal_board.h
文件。Z-Stack协议中,默认给了四个LED的配置,将其与自己开发板的LED一一对应起来。
/* 1 - Green */
#define LED1_BV BV(0)
#define LED1_SBIT P1_0
#define LED1_DDR P1DIR
#define LED1_POLARITY ACTIVE_LOW // 低电平驱动
#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_LOW
/* 3 - Yellow */
#define LED3_BV BV(4)
#define LED3_SBIT P0_4
#define LED3_DDR P0DIR
#define LED3_POLARITY ACTIVE_LOW
#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
#endif
在编译选项的预编译中,添加HAL_LED=TRUE
,对应在hal_drivers.c
文件中的HalDrvierInit
函数中,有:
/* LED */
#if (defined HAL_LED) && (HAL_LED == TRUE)
HalLedInit();
#endif
在hal_led.h
中提供相关API,常用的有:
-
HalLedSet( uint8 led, uint8 mode)
HalLedSet(HAL_LED_1, HAL_LED_MODE_ON); // 开启LED1
-
HalLedBlink( uint8 leds, uint8 cnt, uint8 duty, uint16 time )
HalLedBlink(HAL_LED_2, //指定LED 2, // 闪烁次数 40, //占空比 200); //闪烁时间c
按键移植
在hal_borad.h
文件中,默认有两个按键,S1和Joystick Center Press,分别作为普通按键和遥感按钮的中心按钮。可以直接将Joystick当做普通按键使用。将引脚配置与自己开发板对应。
/* ------------------------------------------------------------------------------------------------
* Push Button Configuration
* ------------------------------------------------------------------------------------------------
*/
#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_LOW
#elif defined (HAL_BOARD_CC2530EB_REV13)
#define PUSH1_POLARITY ACTIVE_LOW
#else
#define PUSH1_POLARITY ACTIVE_LOW
#error Unknown Board Indentifier
#endif
/* Joystick Center Press */
#define PUSH2_BV BV(0)
#define PUSH2_SBIT P2_0
#define PUSH2_POLARITY ACTIVE_LOW
在编译选项的预编译中,添加HAL_KEY=TRUE
在hal_key.h
中定义了一些按键事件, 这些很多是遥感按钮的,大多用不着
/* Interrupt option - Enable or disable */
#define HAL_KEY_INTERRUPT_DISABLE 0x00
#define HAL_KEY_INTERRUPT_ENABLE 0x01
/* Key state - shift or nornal */
#define HAL_KEY_STATE_NORMAL 0x00
#define HAL_KEY_STATE_SHIFT 0x01
#define HAL_KEY_SW_1 0x01 // Joystick up
#define HAL_KEY_SW_2 0x02 // Joystick right
#define HAL_KEY_SW_5 0x04 // Joystick center
#define HAL_KEY_SW_4 0x08 // Joystick left
#define HAL_KEY_SW_3 0x10 // Joystick down
#define HAL_KEY_SW_6 0x20 // Button S1 if available
#define HAL_KEY_SW_7 0x40 // Button S2 if available
/* Joystick */
#define HAL_KEY_UP 0x01 // Joystick up
#define HAL_KEY_RIGHT 0x02 // Joystick right
#define HAL_KEY_CENTER 0x04 // Joystick center
#define HAL_KEY_LEFT 0x08 // Joystick left
#define HAL_KEY_DOWN 0x10 // Joystick down
/* Buttons */
#define HAL_PUSH_BUTTON_RIGHT 0x01 // Button right
#define HAL_PUSH_BUTTON_LEFT 0x02 // Button left
#define HAL_PUSH_BUTTON_SELECT 0x04 // Button select
#define HAL_KEY_BUTTON_UP 0x40 // Button up
#define HAL_KEY_BUTTON_DOWN 0x80 // Button down
在hal_key.c
的halProcessKeyInterrupt
函数中,Z-Stack原本的流程是先进入中断, 再轮询看是哪个按键按下, 但可能会出现一些问题,因此我们直接在中断函数中,保存按下的按键在keys
变量中,并通过pHalKeyProcessFunction
最终将其传给Onboard.c
文件中的OnBoard_KeyCallback
函数
/**************************************************************************************************
* @fn halProcessKeyInterrupt
*
* @brief Checks to see if it's a valid key interrupt, saves interrupt driven key states for
* processing by HalKeyRead(), and debounces keys by scheduling HalKeyRead() 25ms later.
*
* @param
*
* @return
**************************************************************************************************/
void halProcessKeyInterrupt (void)
{
bool valid=FALSE;
uint8 keys = 0;
if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT) /* Interrupt Flag has been set */
{
HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT); /* Clear Interrupt Flag */
keys = HAL_KEY_SW_6; // S1按下 added
valid = TRUE;
}
if (HAL_KEY_JOY_MOVE_PXIFG & HAL_KEY_JOY_MOVE_BIT) /* Interrupt Flag has been set */
{
HAL_KEY_JOY_MOVE_PXIFG = ~(HAL_KEY_JOY_MOVE_BIT); /* Clear Interrupt Flag */
keys |= HAL_KEY_SW_7; // S2按下 added
valid = TRUE;
}
/* Invoke Callback if new keys were depressed */
if (pHalKeyProcessFunction
#ifdef HAL_LEGACY_KEYS
&& keys //in legacy modes, only report key presses and do not report when a key is released
#endif
)
{
(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
} // added
if (valid)
{
osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);
}
}
将OnBorad.c
文件中的OnBorad_KeyCallBack
函数的shift
变量修改如下,使其在S1或S2其中一个触发时为true
,然后OnBoard_SendKeys
发送按键事件(KEY_CHANGE)和被触发按键的信息
void OnBoard_KeyCallback ( uint8 keys, uint8 state )
{
uint8 shift;
(void)state;
shift = ((keys & HAL_KEY_SW_6)||(keys & HAL_KEY_SW_7)) ? true : false; // 需修改这里
if ( OnBoard_SendKeys( keys, shift ) != ZSuccess ) // 发送按键事件
{
...
}
}
最后,编写应用层(zcl_samplexxx.c
文件中)的按键处理函数zclSampleLight_HandleKeys
完成相应的功能即可
static void zclSampleLight_HandleKeys( byte shift, byte keys )
{
if(keys & HAL_KEY_SW_6) // 按键S1被按下
{
HalLedBlink(HAL_LED_1, 10, 50, 400);
return;
}
if(keys & HAL_KEY_SW_7) // 按键S2被按下
{
HalLedBlink(HAL_LED_2, 10, 50, 400);
return;
}
}
由于Z-Stack协议栈默认只用S1一个按键,若要用多个按键,则需根据以上步骤一步步修改代码(否则只需在zclSampleLight_HandleKeys
完成S1处理事件即可),还是比较不方便的。
Uart移植
Z-Stack中,Uart的移植非常方便,只需在应用层写好初始化函数和回调函数,即可使用串口功能。若习惯使用printf
函数,则需重写putchar()
函数,本文选择重写方式。
/* ============== UART0 ==============*/
/**
* @brief 重写 putchar函数 UART0 Rx: P0_2 Tx: P0_3
*/
__near_func int putchar(int c)
{
UTX0IF = 0; // 清除发送标志位
U0DBUF = (char)c;
while(UTX0IF == 0); // 等待发送成功 发送成功时 发送标志位复位
return(c);
}
/**
* @fn zclSampleSw_UartCB
*
* @brief Uart Callback
*/
static void zclSampleLight_UartCB(uint8 port, uint8 event)
{
unsigned char idx=0;
memset(&UART_RxData, 0, sizeof(UART_RxData)); // 清空接收缓存
while(Hal_UART_RxBufLen(HAL_UART_PORT_0))
{
HalUARTRead(HAL_UART_PORT_0, &UART_RxBuf, 1);
if((UART_RxState == 0) && (idx == 0)) // 等待包头
{
if(UART_RxBuf == '@')
{
UART_RxState = 1;
}
else // 清除接收缓存
{
U0UCR |= 0x80; // 清除 UART RX FIFO
U0CSR &= ~0x40; // 关闭 UART 模块
U0CSR |= 0x40; // 重新启用 UART 模块
return;
}
}
else if(UART_RxState == 1) // 接收数据
{
if((UART_RxBuf != '\n') && (idx < ZCLSAMPLELIGHT_UART_BUF_LEN))
{
UART_RxData[idx++] = UART_RxBuf; // 接收数据
}
else // 收到包尾或超过最大
{
UART_RxState = 0;
printf("Get Info:%s", UART_RxData);
}
}
}
}
/**
* @brief Uart初始化
*/
void zclSampleLight_InitUart(void)
{
halUARTCfg_t uartConfig;
/* UART Configuration */
uartConfig.configured = TRUE;//允许配置
uartConfig.baudRate = HAL_UART_BR_19200;//波特率
uartConfig.flowControl = FALSE;//关闭硬件流控
uartConfig.flowControlThreshold= 0;//和流控相关
uartConfig.rx.maxBufSize = ZCLSAMPLELIGHT_UART_BUF_LEN;//接收缓冲区大小
uartConfig.tx.maxBufSize = 0;//发送缓冲区大小
uartConfig.idleTimeout = 10;//默认超时时间
uartConfig.intEnable = TRUE;// 使能中断
uartConfig.callBackFunc = zclSampleLight_UartCB;//设置回调函数
/* Start UART */
HalUARTOpen(HAL_UART_PORT_0, &uartConfig);// 根据配置打开串口0
}
还需定义接收缓存和最大接收长度
#define ZCLSAMPLELIGHT_UART_BUF_LEN 128
unsigned char UART_RxBuf; // 接收缓存
unsigned char UART_RxData[ZCLSAMPLELIGHT_UART_BUF_LEN]; // 数据保存
unsigned char UART_RxState = 0; // 接收状态 0 等待包头'@' 1 接收数据
- Note:
- 值得注意的是,移植到Z-Stack后,若波特率设置为9600,则接收数据时可能出现乱码,丢包等情况,这时尝试用更高的波特率
- 通过
HalUARTOpen
只能配置一个串口,若需要同时配置两个串口,另一个串口直接采用寄存器配置的方式,Z-Stack默认不支持两个串口同时使用,修改协议栈很麻烦,直接用寄存器重新配置即可。后续我们CC2530与ESP8266的通信会提供参考案例
LCD移植
不同商家选用的LCD不同,一般情况下,将商家提供的驱动代码hal_lcd.h
和hal_lcd.c
替换即可,根据自己开发板的教程来。
常用API:
-
HalLcdWriteString ( char *str, uint8 option)
HalLcdWriteString( "End-Device", HAL_LCD_LINE_1 );
-
HalLcdWriteStringValue( char *title, uint16 value, uint8 format, uint8 line )
HalLcdWriteStringValue((char *)MSGpkt->cmd.Data,p2pCnt,10,3);
_lcd.c`替换即可,根据自己开发板的教程来。
常用API:
-
HalLcdWriteString ( char *str, uint8 option)
HalLcdWriteString( "End-Device", HAL_LCD_LINE_1 );
-
HalLcdWriteStringValue( char *title, uint16 value, uint8 format, uint8 line )
HalLcdWriteStringValue((char *)MSGpkt->cmd.Data,p2pCnt,10,3);