协议栈版本:ZStack-2007(ZStack-CC2530-2.5.1a)。
芯片型号:CC2530。
我们在使用ZigBee时通常只用到一个串口,但是在某些情况下希望同时使用两个串口。ZStack默认只能使用一个串口。不过我们可以通过修改协议栈内容来同时使用两个串口。
首先来看一下为什么ZStack只能使用一个串口():
MT_UART.h头文件中:
#if defined (MT_UART_DEFAULT_PORT)
HalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig);
#else
/* Silence IAR compiler warning */
(void)uartConfig;
#endif
//定义了ZTOOL_P1
#if defined (ZTOOL_P1) || defined (ZTOOL_P2) //DMA方式
#define MT_UART_DEFAULT_PORT ZTOOL_PORT
#elif defined (ZAPP_P1) || defined (ZAPP_P2) //ISR方式
#define MT_UART_DEFAULT_PORT ZAPP_PORT
#endif
#if defined (ZTOOL_P1)
#define ZTOOL_PORT HAL_UART_PORT_0//串口0
#elif defined (ZTOOL_P2)
#define ZTOOL_PORT HAL_UART_PORT_1//串口1
#else
#undef ZTOOL_PORT
#endif
该头文件中定义了一个默认UART串口端口,从第二段 #if defined (ZTOOL_P1) || defined (ZTOOL_P2) //DMA方式
开始,由于使用了if-else结构,如果定义了ZTOOL_P1或者ZTOOL_P2,那么默认端口为ZTOOL_PORT,在这种情况下ISR方式就不会再出现了。如果没有使用DMA方式,并且定义了ZAPP_P1或者ZAPP_P2,则采用ISR方式。
接下来看第三段:如果定义了ZTOOL_P1,则ZTOOL_PORT为HAL_UART_PORT_0串口0,否则如果定义了ZTOOL_P2,则为串口1。该结构仍采用了if-else结构,也就是说使用了串口0就不会再用到串口1。
那么我们可以得出这样的结论,使用了DMA方式就不能再用ISR方式,使用了串口0就不能再用串口1。当然这只是默认串口,默认串口只能有一个。这个似乎和使用两个串口没什么关系,只是使用两个串口就不能再采用默认串口这一说了。
下面再看hal_board_cfg.h中的这样一段:
//如果在没有定义HAL_UART且定义了ZAPP_P、ZAPP_P2、ZTOOL_P1、ZTOOL_P2那么定义HAL_UART TRUE;否则定义HAL_UART FALSE
#ifndef HAL_UART
#if (defined ZAPP_P1) || (defined ZAPP_P2) || (defined ZTOOL_P1) || (defined ZTOOL_P2)
#define HAL_UART TRUE
#else
#define HAL_UART FALSE
#endif
#endif
//如果HAL_UART为真并且没有定义HAL_UART_DMA,并且HAL_DMA为真并且定义了ZAPP_P2、 ZTOOL_P2那么 定义HAL_UART_DMA 2否则定义HAL_UART_DMA 1
#if HAL_UART
#ifndef HAL_UART_DMA
#if HAL_DMA
#if (defined ZAPP_P2) || (defined ZTOOL_P2)
#define HAL_UART_DMA 2
#else
#define HAL_UART_DMA 1
#endif
#else
#define HAL_UART_DMA 0
#endif
#endif
#ifndef HAL_UART_ISR
#if HAL_UART_DMA // Default preference for DMA over ISR.
#define HAL_UART_ISR 0
#elif (defined ZAPP_P2) || (defined ZTOOL_P2)
#define HAL_UART_ISR 2
#else
#define HAL_UART_ISR 1
#endif
#endif
第一段的意思是如果定义了ZTOOL_P1等四个当中的一个,那么就HAL_UART即为真。即串口可用。
在该头文件上仔细找可以找到该句:
#ifndef HAL_DMA
#define HAL_DMA TRUE
#endif
那么对于第二段,我们可以得出这样的结论:只要是定义了ZTOOL_P1等四个当中的一个,那么HAL_UART_DMA的逻辑值就为1否则为0。
而对于第三段只要HAL_UART_DMA的逻辑值为1,则ISR不可用,注释意为默认DMA优先级高于ISR。
所以对于ZStack来说默认只能使用一个串口。那么想要使用两个串口该怎么办呢?当然是要修改上面的代码了。
ZigBee使用两个串口的方法:
修改hal_board_cfg.h中的第二三段代码如下:
#if HAL_UART
//Always prefer to use DMA over ISR.
#if HAL_DMA
#ifndef HAL_UART_DMA
#if (defined ZAPP_P1)||(defined ZTOOL_P1)
#define HAL_UART_DMA 1
#elif(defined ZAPP_P2)||(defined ZTOOL_P2)
#define HAL_UART_DMA 2
#else
#define HAL_UART_DMA 1
#endif
#endif
#define HAL_UART_ISR 2
#else
#ifndef HAL_UART_ISR
#if(defined ZAPP_P1)||(defined ZTOOL_P1)
#define HAL_UART_ISR 1
#elif(defined ZAPP_P2)||(defined ZTOOL_P2)
#define HAL_UART_ISR 2
#else
#define HAL_UART_ISR 1
#endif
#endif
#define HAL_UART_DMA 0
#endif
(该段代码摘录自网上,使用时定义ZATOOL_P1即可,这样选择了串口0DMA方式,串口1中断方式,如果定义ZAPP_P2可能会产生逻辑问题)
修改后意为如果使用了DMA,则定义相应的通道为DMA方式,同时定义串口1采用中断方式,如果没有定义DMA,则使用中断方式。
修改完以后协议栈已支持同时使用两个串口,但是想要使用还得对串口进行初始化。自带的串口初始化不作改动,默认串口0采用DMA方式,另外需要写一个串口1的初始化函数。函数如下:
void MT_Uart1Init ()
{
halUARTCfg_t uartConfig1;
/* Initialize APP ID */
App_TaskID = 0;
/* UART Configuration */
uartConfig1.configured = TRUE;
uartConfig1.baudRate = MT_UART_DEFAULT_BAUDRATE;
uartConfig1.flowControl = MT_UART_DEFAULT_OVERFLOW;
uartConfig1.flowControlThreshold = 32;
uartConfig1.rx.maxBufSize = 32;
uartConfig1.tx.maxBufSize = 32;
uartConfig1.idleTimeout = 6;
uartConfig1.intEnable = TRUE;
uartConfig1.callBackFunc = MT_UartProcessZToolData;
/* Start UART */
HalUARTOpen (HAL_UART_PORT_1, &uartConfig1);
/* Silence IAR compiler warning */
/* Initialize for ZApp */
#if defined (ZAPP_P1) || defined (ZAPP_P2)
/* Default max bytes that ZAPP can take */
MT_UartMaxZAppBufLen = 1;
MT_UartZAppRxStatus = MT_UART_ZAPP_RX_READY;
#endif
}
注意红色字体部分: HalUARTOpen (HAL_UART_PORT_1, &uartConfig1);
初始化打开串口为HAL_UART_PORT_1,其他参数有结构体uartConfig1传给回调函数。当然还需要将该初始化注册到用户应用层。即在用户应用层初始化函数中(例:void SampleApp_Init( uint8 task_id )注:不同的程序应用层初始化函数不同)调用该函数即可。
当然还需要回调函数。两个串口初始化均采用同样的回调函数,测试显示只能使用一个回调函数。所以对于串口事件均指定一个处理事件,如果想要两个串口分别对应不同的串口事件,则做如下修改:
if (pMsg)
{
/* Fill up what we can */
if(port == HAL_UART_PORT_0)
{
pMsg->hdr.event = CMD_SERIAL_MSG;
}
else
{
pMsg->hdr.event = CMD_SERIAL1_MSG;
}
pMsg->msg = (uint8*)(pMsg+1);
pMsg->msg[MT_RPC_POS_LEN] = LEN_Token;
state = CMD_STATE1;
}
在用户应用层加上相应的触发事件及处理函数即可。
由于板子还没有出来,还没有进行测试。
板子测试成功。