Zstack提供的SerialApp例程既可以作为分析Zstack使用方式之用,也可以直接作为模板用于开发需要使用串口通信的应用。
其初始化部分代码如下图1所示:
比起之前分析过的GenericApp多了两个陌生的变量:SerialApp_Rxseq和uartConfig。其中SerialApp_Rxseq是后面任务对应的处理任务需要使用的,后面再做分析。这儿主要分析uartConfig这个结构体变量。这儿先来看一下后面的一个函数:HalUARTOpen
很显然,前面的结构体变量是用来配置串口的,后面的函数将采用前面配置的变量来配置串口。(这里需要注意一点,HalUARTOpen只能配置串口,而不能初始化串口。根据TI手册介绍,在对串口进行操作之前,一定要首先使用HalUARTInit函数对串口进行初始化。一般该函数在main函数执行时的HalDRIVERInit里面根据对应的宏定义进行了条件编译了,所以一般我们不需要自己再去初始化,但并不代表串口真的不需要初始化。)
在void HalDriverInit (void)中有如下几句代码以用于串口初始化:
#if (defined HAL_UART) && (HAL_UART == TRUE)
HalUARTInit();
#endif)
关于HalUARTOpen函数TI手册上是这样介绍的:
This function opens a port based on the configuration that is provided. A callback function is also registered so events can be handled correctly.
函数原型为:
uint8 HalUARTOpen (uint8 port, halUARTCfg_t *config);
形参中的unit8 port用于指定要打开的串口。众所周知的是CC2530有两个独立的串口,在hal中分别用HAL_UART_PORT_1和HAL_UART_PORT_2进行标识,
在hal_uart.h中可以查找到如下的宏定义:
#define HAL_UART_PORT_0 0x00
#define HAL_UART_PORT_1 0x01
所以port的取值既可以是以宏定义形式的,也可以直接为0或者1。至于0和1所对应的是具体哪个硬件串口,参考CC2530 user guider即可。
halUARTCfg_t*是一个结构体指针,指向配置串口所需参数变量。
uartConfig.configured = TRUE; // Set by the function when the port is setup correctly and read to be used:设置用于指示端口被正确配置并准备使用
uartConfig.baudRate = SERIAL_APP_BAUD;//波特率设置,hal层提供了一大堆的宏定义波特率,例如HAL_UART_BR_115200,在hal_uart.h文件中可具体查看。
uartConfig.flowControl = TRUE;//硬件流控设置,一般的,都是使用rx和tx两线通信,所以在自己的设计使用中,应该将之设为FALSE关闭硬件流控。
uartConfig.flowControlThreshold = SERIAL_APP_THRESH; // 硬件流控阀值,用于触发事件用的,不用硬件流控就不需要管它
uartConfig.rx.maxBufSize = SERIAL_APP_RX_SZ; // 用于指定串口接收缓冲区的大小,当接收缓冲区的数据字节数达到maxBufSize指定的字节数后将触发回调函数,并返回事件HAL_UART_RX_FULL以供回调函数进行判断。
uartConfig.tx.maxBufSize = SERIAL_APP_TX_SZ; // 用于指定串口发送缓冲区的大小。
这里需要注意一点.uartConfig.rx和uartConfig.tx本来就是一个结构体指针:halUARTBufControl_t*,该结构体变量里面同样包含了多个成员变量,但是根据官方手册描述,现在该结构体变量中只有maxBufsize被使用,所以这儿会是uartConfig.rx.maxBufSize...具体的该结构体变量内成员可查看hal api手册。
uartConfig.idleTimeout = SERIAL_APP_IDLE; // 这个参数主要用于串口接收中,在串口接收到数据开始算起,如果经过idleTimeout ms的时间还没有接收到新的数据,那么就会调用后面将要介绍的回调函数,并返回事件HAL_UART_RX_TIMEOUT,用于回调函数中进行具体的判断。现在很多裸机的单片机程序也同样是基于接收超时原理进行的串口模块开发。
uartConfig.intEnable = TRUE; // 串口中断使能,TRUE或者FALSE。
uartConfig.callBackFunc = SerialApp_CallBack;//回调函数的入口地址,其具体形式如下:
typedef void (*halUARTCBack_t) (uint8 port, uint8 event);
说明回调函数是一个函数指针,并带有两个参数,这两个参数会在系统调用回调函数的时候自动传入。值得注意的是这里的event参数里面所包含的值就是前面所说的使用串口可能出现的事件,如串口接收BUFF满:HAL_UART_RX_FULL和串口接收超时:HAL_UART_RX_TIMEOUT.
关于回调函数,TI提供的官方手册上是这样介绍的:
This callback is called when there is an event such as Tx done, Rx ready…
而具体的将要导致调用该函数的事件是哪些呢,手册上也有一个event table,如下图2所示:
图2
可以看出,这些事件都是之前配置uartConfig_t结构体变量的时候都提过的事件。这说明了在Zstack中回调函数是一种用于及时响应事件的一种机制,以避免OSAL任务优先级和轮询机制造成的实时性太差。
该结构体配置好了之后再使用HalUARTOpen载入该结构体变量来配置串口,至此串口就算是成功地配置了。
至于其他的初始化代码在之前的GenericApp已经分析完毕。
但还是需要提一点:afRegister,这个函数是使用终端描述符向AF(pplication Framework :应用框架)注册终端(endpoint)的,进行如此注册根据我的分析和查阅文档,应该有至少如下两点作用:
1、向周围的Zigbee设备描述本设备属性特征;
2、决定如何处理传输到本设备上的数据信息。
本节主要分析了SerialApp中关于串口的配置问题,重点在于用于配置串口的结构体变量的各成员变量作用以及其取值范围。要更加详细地了解和使用该hal模块,请参照TI官方提供的手册:HAL Driver API.pdf(SWRA193),在Zstack文件下中的Documents文件夹中可以找到该文档。