方法一
协议栈版本: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_UARTTRUE;否则定义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;
}
在用户应用层加上相应的触发事件及处理函数即可。
由于板子还没有出来,还没有进行测试。
板子测试成功。
方法二
前两天因为做东西需要在zstack协议栈下同时使用两个串口,通过参考网上的一些资料,经过一段时间的折腾,算是搞定了,现在把详细的配置方法贴出来跟大家分享,如果有问题的话也希望大家指出来共同进步。
1、在hal_board_cfg.h中,更改#define HAL_UART_ISR 0为#define HAL_UART_ISR 2,使用uart1为中断方式,在P1口,因此,全局来看,串口0为DMA方式,在P0口,串口1为ISR方式,在P1口。
2、更改MT_UARTInit函数中开启串口程序部分如下:
#if defined(MT_UART_DEFAULT_PORT)
HalUARTOpen (MT_UART_DEFAULT_PORT,&uartConfig);
HalUARTOpen (HAL_UART_PORT_1,&uartConfig);
#else
3、关于分别处理两个串口的数据问题:
在MT_UART.c中加入串口区分,在MT_UartProcessZToolData函数中登记串口事件时加入串口区分,如下:
if(port==0)
pMsg->hdr.event = CMD_SERIAL_MSG_0;
else if(port==1)
pMsg->hdr.event = CMD_SERIAL_MSG_1;
CMD_SERIAL_MSG_0为串口0数据处理,CMD_SERIAL_MSG_1为串口1数据处理,需要更改相应的宏定义,在MT.h中更改
/* Message CommandIDs */
#defineCMD_SERIAL_MSG_0 0x01
#defineCMD_SERIAL_MSG_1 0x07
4、更改MT_TASK.c中MT_ProcessIncomingCommand函数在switch语句中加入串口区分,如下
switch (msg->hdr.event )
{
case CMD_SERIAL_MSG_0:
MT_ProcessIncoming(msg->msg);
break;
case CMD_SERIAL_MSG_1:
MT_ProcessIncoming(msg->msg);
break;
5、用户可以通过修改SampleApp.c中的SampleApp_ProcessEvent函数来实现处理两个不同串口的数据,如下:
switch (MSGpkt->hdr.event )
{
case CMD_SERIAL_MSG_0:
SampleApp_SerialCMD((mtOSALSerialData_t *)MSGpkt);
break;
case CMD_SERIAL_MSG_1:
SampleApp_SerialCMD((mtOSALSerialData_t*)MSGpkt);
break;
串口处理函数可根据网蜂教程自行编写实现相应的功能。
好啦,到这里就配置完成了,希望能改需要的朋友一些帮助,同时如果有问题的话还请各位不吝赐教,批评指正,共同进步。