配置串口参数,开启串口功能

在Z-Stack中我们可以直接调用API接口来开启设备的串口功能,此API接口函数为“uint8 HalUARTOpen(uint8 port, halUARTCfg_t *config)”。我们先来看看这个函数的形参,形参“port”表示要开启的串口号,CC2530有两个串口,串口0和串口1,这个看个人硬件所用的串口来选择开启哪个串口。形参“config”里包含了这个串口的使用参数,详情如下:

  1. typedef struct
  2. {
  3. bool configured;
  4. uint8 baudRate;
  5. bool flowControl;
  6. uint16 flowControlThreshold;
  7. uint8 idleTimeout;
  8. halUARTBufControl_t rx;
  9. halUARTBufControl_t tx;
  10. bool intEnable;
  11. uint32 rxChRvdTime;
  12. halUARTCBack_t callBackFunc;
  13. }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 ———————————————————————

  1. void Gateway_Init( uint8 task_id )
  2. {
  3. halUARTCfg_t uartconf;
  4. ……
  5. // 配置串口
  6. uartconf.baudRate = HAL_UART_BR_115200;
  7. uartconf.callBackFunc = Handle_UartEvent;
  8. uartconf.configured = TRUE;
  9. uartconf.flowControl = FALSE;
  10. uartconf.flowControlThreshold = 64;
  11. uartconf.idleTimeout = 6; // 6ms后串口空闲则发送串口空闲事件,参数不可设为0
  12. uartconf.rx.maxBufSize = 128;
  13. uartconf.tx.maxBufSize = 128;
  14. uartconf.intEnable = TRUE;
  15. // 开启串口0
  16. HalUARTOpen(HAL_UART_PORT_0, &uartconf);
  17. ……
  18. }

串口发送和接收功能

串口发送数据就只需要调用“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端。

串口透传数据 - 图1

终端节点编程

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

串口透传数据 - 图2

屏蔽掉Z-Stack默认开启的MT_TASK、MT_SYS_FUNC、MT_ZDO_FUNC。

———————————————————- Gateway.c ——————————————————————————————-
去掉与本项目无关的初始化,在自己的任务初始化函数当中配置串口参数,开启串口0功能。

  1. void Gateway_Init( uint8 task_id )
  2. {
  3. halUARTCfg_t uartconf;
  4. g_gateway_taskid = task_id;
  5. // 填充端口描述符
  6. g_gateway_epdesc.endPoint = GATEWAY_ENDPOINT;
  7. g_gateway_epdesc.task_id = &g_gateway_taskid;
  8. g_gateway_epdesc.simpleDesc = (SimpleDescriptionFormat_t *)&g_gateway_simpledesc;
  9. g_gateway_epdesc.latencyReq = noLatencyReqs;
  10. // 注册该端口
  11. afRegister(&g_gateway_epdesc);
  12. /* 新添加代码 START */
  13. // 配置串口参数
  14. uartconf.baudRate = HAL_UART_BR_115200;
  15. uartconf.callBackFunc = Handle_UartEvent;
  16. uartconf.configured = TRUE;
  17. uartconf.flowControl = FALSE;
  18. uartconf.flowControlThreshold = 64;
  19. uartconf.idleTimeout = 6; // 6ms后串口空闲则发送串口空闲事件,参数不可设为0
  20. uartconf.rx.maxBufSize = 128;
  21. uartconf.tx.maxBufSize = 128;
  22. uartconf.intEnable = TRUE;
  23. // 开启串口0
  24. HalUARTOpen(HAL_UART_PORT_0, &uartconf);
  25. /* 新添加代码 END */
  26. // 初始化LED灯
  27. // Init_IndicatorLight();
  28. // 通知g_gateway_taskid任务有LED灯闪烁事件发生
  29. // osal_set_event(g_gateway_taskid, EVENT_FLASH_LED); // 关掉上一篇文章的LED灯闪烁功能
  30. // 开始定期发送数据给协调器
  31. // osal_set_event(g_gateway_taskid, EVENT_PERIOD_SEND_DATA);
  32. }

创建串口事件处理回调函数。

  1. static void Handle_UartEvent(uint8 port, uint8 event)
  2. {
  3. // 处理串口0接收事件
  4. if(port==HAL_UART_PORT_0)
  5. {
  6. switch(event)
  7. {
  8. // 当发生 RX 事件
  9. case HAL_UART_RX_FULL:
  10. case HAL_UART_RX_ABOUT_FULL:
  11. case HAL_UART_RX_TIMEOUT:
  12. {
  13. // 读取接收数据的长度
  14. uint16 rxbuflen = Hal_UART_RxBufLen(HAL_UART_PORT_0);
  15. // 创建接收数据内存
  16. uint8* rxbuf = osal_mem_alloc(rxbuflen);
  17. // 若内存创建成功
  18. if(rxbuf!=NULL)
  19. {
  20. // 读取 RX 数据
  21. HalUARTRead(HAL_UART_PORT_0, rxbuf, rxbuflen);
  22. // 直接透传给协调器
  23. SendMessageToCoor(rxbuf, rxbuflen);
  24. // 释放内存
  25. osal_mem_free(rxbuf);
  26. }
  27. }
  28. break;
  29. default:
  30. break;
  31. }
  32. }
  33. }

创建数据无线发送函数,发送数据到协调器中。

  1. static void SendMessageToCoor(uint8* data, uint16 datalen)
  2. {
  3. // 目标地址为协调器
  4. afAddrType_t CoorAddr = {0};
  5. CoorAddr.addrMode = (afAddrMode_t)Addr16Bit;
  6. CoorAddr.addr.shortAddr = 0x00;
  7. CoorAddr.endPoint = GATEWAY_ENDPOINT;
  8. // 发送数据到协调器
  9. AF_DataRequest(&CoorAddr, &g_gateway_epdesc,
  10. TRANSMISSION_CLUSTERID, datalen, data,
  11. &g_transid, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS);
  12. }

协调器编程

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

屏蔽掉Z-Stack默认开启的MT_TASK、MT_SYS_FUNC、MT_ZDO_FUNC。
———————————- Gateway.c ——————————————————————————————-
在自己的任务初始化函数当中配置串口参数,开启串口0功能。

  1. void Gateway_Init( uint8 task_id )
  2. {
  3. halUARTCfg_t uartconf;
  4. ……
  5. // 配置串口参数
  6. uartconf.baudRate = HAL_UART_BR_115200;
  7. uartconf.callBackFunc = NULL;
  8. uartconf.configured = TRUE;
  9. uartconf.flowControl = FALSE;
  10. uartconf.flowControlThreshold = 64;
  11. uartconf.idleTimeout = 6; // 6ms后串口空闲则发送串口空闲事件,参数不可设为0
  12. uartconf.rx.maxBufSize = 128;
  13. uartconf.tx.maxBufSize = 128;
  14. uartconf.intEnable = TRUE;
  15. // 开启串口0
  16. HalUARTOpen(HAL_UART_PORT_0, &uartconf);
  17. ……
  18. }

发送接收数据到PC端。

  1. static void Gateway_MessageMSGCB( afIncomingMSGPacket_t *pkt )
  2. {
  3. switch ( pkt->clusterId )
  4. {
  5. case TRANSMISSION_CLUSTERID:
  6. {
  7. // 置反LED灯开关状态
  8. // osal_set_event(g_gateway_taskid, EVENT_FLASH_LED);
  9. // 发送接收数据到PC端
  10. HalUARTWrite(HAL_UART_PORT_0, pkt->cmd.Data, pkt->cmd.DataLength);
  11. }
  12. break;
  13. }
  14. }

分别按下终端设备和协调器设备工程的编译按钮,0错误0警告。然后我们将程序分别烧录到两个CC2530设备中,等待设备自动组网后,通过“串口调试助手”发送数据给终端节点,然后再通过“串口调试助手”观察协调器就可以看到终端设备发送过来的数据了。
串口透传数据 - 图4


qrcode_for_gh_e95b474fcf08_344.jpg