配置串口参数,开启串口功能
在Z-Stack中我们可以直接调用API接口来开启设备的串口功能,此API接口函数为“uint8 HalUARTOpen(uint8 port, halUARTCfg_t *config)”。我们先来看看这个函数的形参,形参“port”表示要开启的串口号,CC2530有两个串口,串口0和串口1,这个看个人硬件所用的串口来选择开启哪个串口。形参“config”里包含了这个串口的使用参数,详情如下:
typedef struct{bool configured;uint8 baudRate;bool flowControl;uint16 flowControlThreshold;uint8 idleTimeout;halUARTBufControl_t rx;halUARTBufControl_t tx;bool intEnable;uint32 rxChRvdTime;halUARTCBack_t callBackFunc;}halUARTCfg_t;
要自己配置的参数如下:
- configured
调用“HalUARTOpen()”函数时会自动将“.configured”参数置为TRUE;若“.configured”=TURE,再调用“HalUARTOpen()”函数打开同一个串口时,则会自动清除串口的RX、TX缓存和串口配置“uartRecord”再重新配置。此处我们设置为TRUE。
baudRate
串口的波特率有“HALUART_BR_9600”、“HAL_UART_BR_19200”、“HAL_UART_BR_38400”、 “HAL_UART BR_115200”可选。此处我们设置为“HAL_UART_BR_9600”波特率。
flowControl
硬件流控制,TRUE为开启硬件流控,FALSE为关闭硬件流控。有硬件流控功能的可以开启硬件流控,此处我们设置为FALSE,关闭硬件流控功能。
- flowControlThreshold
此参数表示RX缓存达到“maxRxBufSize”之前还有多少字节空余。当RX缓存到达“maxRxBufSize – flowControlThreshold”时,会触发相应的应用事件:“HAL_UART_RX_ABOUT_FULL”。此处我们设置为64,一般设置为“maxRxBufSize”的一半。
- idleTimeout
如果设备串口收到数据之后在“idleTimout”时间内RX没有收到新的数据了,将会触发相应的事件“HAL_UART_RX_TIMEOUT”,这时应用程序可以选择读出所有RX的值或者一部分的值,单位:毫秒。此处我们设置为6ms,当串口收到数据后,6ms内没有再收到新的数据,则触发“HAL_UART_RX_ABOUT_FULL”事件。
- rx.maxBufSize
rx包含“halUARTBufControl_t”数据结构,用于操作RX 缓冲区。当接收的字节数到达“rx.maxBufSize”时,会产生“HAL_UART_RX_FULL”事件。此处我们设置为128个字节
- intEnable
串口中断使能,TRUE为使能串口中断功能,FALSE为失能串口中断功能。此处我们设置为TRUE,使能串口中断功能。
- callBackFunc
回调函数,应用程序可以根据RX、TX出发的不同事件进行处理。此处会指向我们自己的串口事件处理函数“Handle_UartEvent()”。
配置串口参数,开启串口0。代码如下:
————————————————————————— Gateway.c ———————————————————————
void Gateway_Init( uint8 task_id ){halUARTCfg_t uartconf;……// 配置串口uartconf.baudRate = HAL_UART_BR_115200;uartconf.callBackFunc = Handle_UartEvent;uartconf.configured = TRUE;uartconf.flowControl = FALSE;uartconf.flowControlThreshold = 64;uartconf.idleTimeout = 6; // 6ms后串口空闲则发送串口空闲事件,参数不可设为0uartconf.rx.maxBufSize = 128;uartconf.tx.maxBufSize = 128;uartconf.intEnable = TRUE;// 开启串口0HalUARTOpen(HAL_UART_PORT_0, &uartconf);……}
串口发送和接收功能
串口发送数据就只需要调用“uint16 HalUARTWrite(uint8 port, uint8 *buf, uint16 len)”接口,形参“port”可选择串口0或串口1,开启了哪个串口就用哪个串口;形参“buf”为要发送的数据;形参“len”为要发送数据的长度,一次性最多只能发送“HAL_UART_DMA_TX_MAX”个字节的数据,协议栈中“HAL_UART_DMA_TX_MAX”的默认值为256。
串口接收数据需要通过上面我们注册的回调函数“Handle_UartEvent”来处理串口事件。关于接收数据的串口事件只有三个:HAL_UART_RX_FULL、HAL_UART_RX_ABOUT_FULL和HAL_UART_RX_TIMEOUT。
- HAL_UART_RX_FULL:当RX缓存数据的字节数到达“rx.maxBufSize”时,会产生“HAL_UART_RX_FULL”事件。
- HAL_UART_RX_ABOUT_FULL:当RX缓存数据的字节数到达“maxRxBufSize – flowControlThreshold”时,会产生“HAL_UART_RX_ABOUT_FULL”事件。
- HAL_UART_RX_TIMEOUT:如果设备串口收到数据之后在“idleTimout”时间内串口没有收到新的数据了,会产生“HAL_UART_RX_TIMEOUT”事件。
串口透传功能
串口透传功能具体为终端设备接收到PC端通过串口发送过来的数据,然后将数据发送至协调器端,协调器端接收到数据后再通过串口将数据发送至PC端。

终端节点编程
要使用自己的串口功能,则必须确保关闭了Z-Stack内部的串口功能,不然两者会产生冲突,串口会出现不可预期的数据。要关闭Z-Stack内部的串口功能,我们只需要屏蔽以下几个预编译即可。

屏蔽掉Z-Stack默认开启的MT_TASK、MT_SYS_FUNC、MT_ZDO_FUNC。
———————————————————- Gateway.c ——————————————————————————————-
去掉与本项目无关的初始化,在自己的任务初始化函数当中配置串口参数,开启串口0功能。
void Gateway_Init( uint8 task_id ){halUARTCfg_t uartconf;g_gateway_taskid = task_id;// 填充端口描述符g_gateway_epdesc.endPoint = GATEWAY_ENDPOINT;g_gateway_epdesc.task_id = &g_gateway_taskid;g_gateway_epdesc.simpleDesc = (SimpleDescriptionFormat_t *)&g_gateway_simpledesc;g_gateway_epdesc.latencyReq = noLatencyReqs;// 注册该端口afRegister(&g_gateway_epdesc);/* 新添加代码 START */// 配置串口参数uartconf.baudRate = HAL_UART_BR_115200;uartconf.callBackFunc = Handle_UartEvent;uartconf.configured = TRUE;uartconf.flowControl = FALSE;uartconf.flowControlThreshold = 64;uartconf.idleTimeout = 6; // 6ms后串口空闲则发送串口空闲事件,参数不可设为0uartconf.rx.maxBufSize = 128;uartconf.tx.maxBufSize = 128;uartconf.intEnable = TRUE;// 开启串口0HalUARTOpen(HAL_UART_PORT_0, &uartconf);/* 新添加代码 END */// 初始化LED灯// Init_IndicatorLight();// 通知g_gateway_taskid任务有LED灯闪烁事件发生// osal_set_event(g_gateway_taskid, EVENT_FLASH_LED); // 关掉上一篇文章的LED灯闪烁功能// 开始定期发送数据给协调器// osal_set_event(g_gateway_taskid, EVENT_PERIOD_SEND_DATA);}
创建串口事件处理回调函数。
static void Handle_UartEvent(uint8 port, uint8 event){// 处理串口0接收事件if(port==HAL_UART_PORT_0){switch(event){// 当发生 RX 事件case HAL_UART_RX_FULL:case HAL_UART_RX_ABOUT_FULL:case HAL_UART_RX_TIMEOUT:{// 读取接收数据的长度uint16 rxbuflen = Hal_UART_RxBufLen(HAL_UART_PORT_0);// 创建接收数据内存uint8* rxbuf = osal_mem_alloc(rxbuflen);// 若内存创建成功if(rxbuf!=NULL){// 读取 RX 数据HalUARTRead(HAL_UART_PORT_0, rxbuf, rxbuflen);// 直接透传给协调器SendMessageToCoor(rxbuf, rxbuflen);// 释放内存osal_mem_free(rxbuf);}}break;default:break;}}}
创建数据无线发送函数,发送数据到协调器中。
static void SendMessageToCoor(uint8* data, uint16 datalen){// 目标地址为协调器afAddrType_t CoorAddr = {0};CoorAddr.addrMode = (afAddrMode_t)Addr16Bit;CoorAddr.addr.shortAddr = 0x00;CoorAddr.endPoint = GATEWAY_ENDPOINT;// 发送数据到协调器AF_DataRequest(&CoorAddr, &g_gateway_epdesc,TRANSMISSION_CLUSTERID, datalen, data,&g_transid, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS);}
协调器编程
要使用自己的串口功能,则必须确保关闭了Z-Stack内部的串口功能,不然两者会产生冲突,串口会出现不可预期的数据。要关闭Z-Stack内部的串口功能,我们只需要屏蔽以下几个预编译即可。
屏蔽掉Z-Stack默认开启的MT_TASK、MT_SYS_FUNC、MT_ZDO_FUNC。
———————————- Gateway.c ——————————————————————————————-
在自己的任务初始化函数当中配置串口参数,开启串口0功能。
void Gateway_Init( uint8 task_id ){halUARTCfg_t uartconf;……// 配置串口参数uartconf.baudRate = HAL_UART_BR_115200;uartconf.callBackFunc = NULL;uartconf.configured = TRUE;uartconf.flowControl = FALSE;uartconf.flowControlThreshold = 64;uartconf.idleTimeout = 6; // 6ms后串口空闲则发送串口空闲事件,参数不可设为0uartconf.rx.maxBufSize = 128;uartconf.tx.maxBufSize = 128;uartconf.intEnable = TRUE;// 开启串口0HalUARTOpen(HAL_UART_PORT_0, &uartconf);……}
发送接收数据到PC端。
static void Gateway_MessageMSGCB( afIncomingMSGPacket_t *pkt ){switch ( pkt->clusterId ){case TRANSMISSION_CLUSTERID:{// 置反LED灯开关状态// osal_set_event(g_gateway_taskid, EVENT_FLASH_LED);// 发送接收数据到PC端HalUARTWrite(HAL_UART_PORT_0, pkt->cmd.Data, pkt->cmd.DataLength);}break;}}
分别按下终端设备和协调器设备工程的编译按钮,0错误0警告。然后我们将程序分别烧录到两个CC2530设备中,等待设备自动组网后,通过“串口调试助手”发送数据给终端节点,然后再通过“串口调试助手”观察协调器就可以看到终端设备发送过来的数据了。

