z-stack协议栈串口驱动与同时使用两个串口的配置方法_第1页
z-stack协议栈串口驱动与同时使用两个串口的配置方法_第2页
z-stack协议栈串口驱动与同时使用两个串口的配置方法_第3页
z-stack协议栈串口驱动与同时使用两个串口的配置方法_第4页
z-stack协议栈串口驱动与同时使用两个串口的配置方法_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Z-Stack串口操作:CC2530共有两个串口,UART0和UART1,两个串口可以通过设置寄存器PERCFG的值映射到不同的引脚上,对应的映射关系如下:端口P0口0位置1RTCTTXRX位置2TXRXRTCT串口1位置1RXTXRTCT位置2RXTXRTCTPERCFG寄存器相关位的描述如下:位名称复位读/写描述1U1CFG0读/写串口1端口映射。0:位置1;1:位置20U0CFG0读/写串口0端口映射。0:位置1;1:位置2在CC2530中提供了两种方式来操作串口,即直接存取访问(DMA)和中断(ISR)方式,两种操作方式的区别在这里不再叙述,想了解的请自行查阅

2、相关资料。在z-stack中默认的使用DMA方式来操作串口,默认配置的串口为UART0,UART0默认使用位置1,即P02为UART的RX,P03为UART的TX。接下来将详细介一下Z-STACK串口默认的配置流程,并介绍如何配置同时使用两个串口。一、 串口默认配置的流程从main函数开始,串口的初始化化函数在调用HalDriverInit()函数时被调用,在HalDriverInit函数中调用了函数HalUARTInit()函数,函数原型如下:void HalUARTInit(void)#if HAL_UART_DMA HalUARTInitDMA();#endif#if HAL_UART_

3、ISR HalUARTInitISR();#endif#if HAL_UART_USB HalUARTInitUSB();#endif可以看出,协议栈通过判断宏定义的方法来判断以何种方式来初始化串口,有关的宏可以在hal_board_cfg.h中找到,先将与串口有关的宏列出以便分析:* Set to TRUE enable UART usage, FALSE disable it */#ifndef HAL_UART /如果未定义HAL_UART/*如果定义了defined ZAPP_P1、defined ZAPP_P2、defined ZTOOL_P1、defined ZTOOL_P2中的一

4、个,就定义HAL_UART为1,协议栈默认地定义了ZTOOL_P1,可以点击project->options->c/c+complier->preprocess->defined symbols来查看预编译的宏*/#if (defined ZAPP_P1) | (defined ZAPP_P2) | (defined ZTOOL_P1) | (defined ZTOOL_P2)#define HAL_UART TRUE#else /否则的话在进行下面的#define HAL_UART FALSE /将HAL_UART定义为0,即不使用串口#endif#endif#if

5、HAL_UART /如果HAL_UART为1/ Always prefer to use DMA over ISR.总是优先地使用DMA方式#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/*执行完上面的一部分代码后,HAL_UART_DMA的值就

6、为1了,具体自行分析#define HAL_UART_ISR 0 /默认不实用ISR方式来处理中断/*在这里已经定义了HAL_UART_ISR,所以就不会进入下面的#ifndef HAL_UART_ISR判断了*/#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#endi

7、f#define HAL_UART_DMA 0#endif/*执行完上面的代码后,HAL_UART_ISR就被定义为0了*/ Used to set P2 priority - USART0 over USART1 if both are defined.#if (HAL_UART_DMA = 1) | (HAL_UART_ISR = 1)#define HAL_UART_PRIPO 0x00#else#define HAL_UART_PRIPO 0x40#endif/*上述代码设置了两个串口的优先级,串口0大于串口1*/*这里的#else对应的是#if HAL_UART,意思就是如果串口使用

8、,就将两种方式的宏都定义为0*/#else#define HAL_UART_DMA 0#define HAL_UART_ISR 0#endif/* USB is not used for CC2530 configuration */#define HAL_UART_USB 0上述代码的if和else对应的关系可能很难看出,可以用notepad打开源文件来查看对应关系。总结一下,上述代码完成的功能就是将HAL_UART_DMA宏设置为1,将HAL_UART_ISR宏设置为0。然后我们再回到HalUARTInit(void)函数,可以看出在这里调用的串口初始化函数是HalUARTInitDMA(

9、)函数,函数原型如下(省略了部分不必要的代码):static void HalUARTInitDMA(void) halDMADesc_t *ch; /定义了一个DMA通道 /*设置串口优先级*/ P2DIR &= P2DIR_PRIPO; P2DIR |= HAL_UART_PRIPO;#if (HAL_UART_DMA = 1) /默认配置会执行这里的语句/*设置UART0在位置1,P0口*/ PERCFG &= HAL_UART_PERCFG_BIT; / Set UART0 I/O to Alt. 1 location on P0.#else/*否则的话UART0在位置

10、2,P1口*/ PERCFG |= HAL_UART_PERCFG_BIT; / Set UART1 I/O to Alt. 2 location on P1.#endif/*设置P0口的P02、P03为外设功能,P02为RX、P03为TX*/ PxSEL |= HAL_UART_Px_RX_TX; / Enable Tx and Rx on P1./*禁用P02和P03的ADC功能,以防止对串口通信产生干扰。TI的工程师是挺细心的,其实我们在使用的时候也不会傻到把这两个端口硬件连接为ADC吧*/ ADCCFG &= HAL_UART_Px_RX_TX; / Make sure ADC

11、 doesnt use this./*设置为UART模式,还可配置为SPI模式*/ UxCSR = CSR_MODE; / Mode is UART Mode./*清除单元/ UxUCR = UCR_FLUSH; / Flush it./*未列出DMA初始化的一些代码*/.上面的函数执行完成以后就基本上完成了串口的初始化,包括串口处理方式、串口对应的引脚等,进一步的串口初始化设置在HalUARTOpenDMA(halUARTCfg_t *config)函数中被完成,该函数的原型如下,在看懂这个函数之前我们需要先了解一下结构体halUARTCfg_t 这个结构体的定义在hal_uart.h文件中

12、,原型如下:typedef struct bool configured; /是否注册串口 uint8 baudRate; /串口通信波特率设置 bool flowControl; /硬件流控制 uint16 flowControlThreshold; /dont care uint8 idleTimeout; /dont care halUARTBufControl_t rx; /dont care halUARTBufControl_t tx; /dont care bool intEnable; /dont care uint32 rxChRvdTime; /dont care halU

13、ARTCBack_t callBackFunc; /串口回调函数halUARTCfg_t;可以看出上述结构体完成了串口初始化所需要的各项参数,包括在OSAL中注册串口,通信波特率的设置等,同时HalUARTOpenDMA函数的形参也是这个结构体,也就是说这些初始化将在这个函数中被完成,下面来通过注释来分析这个函数。static void HalUARTOpenDMA(halUARTCfg_t *config) /*注册串口回调函数,串口收到数据后会调用回调函数*/ dmaCfg.uartCB = config->callBackFunc; / / Only supporting subs

14、et of baudrate for code size - other is possible. HAL_UART_ASSERT(config->baudRate = HAL_UART_BR_9600) | (config->baudRate = HAL_UART_BR_19200) | (config->baudRate = HAL_UART_BR_38400) | (config->baudRate = HAL_UART_BR_57600) | (config->baudRate = HAL_UART_BR_115200); if (config->b

15、audRate = HAL_UART_BR_57600 | config->baudRate = HAL_UART_BR_115200) UxBAUD = 216; else UxBAUD = 59; switch (config->baudRate) case HAL_UART_BR_9600: UxGCR = 8; dmaCfg.txTick = 35; / (32768Hz / (9600bps / 10 bits) / 10 bits include start and stop bits. break; case HAL_UART_BR_19200: UxGCR = 9;

16、 dmaCfg.txTick = 18; break; case HAL_UART_BR_38400: UxGCR = 10; dmaCfg.txTick = 9; break; case HAL_UART_BR_57600: UxGCR = 10; dmaCfg.txTick = 6; break; default: / HAL_UART_BR_115200 UxGCR = 11; dmaCfg.txTick = 3; break; /*上面的部分代码通过switch判断完成了对串口波特率的设置,具体的寄存器值可以参考下面的波特率寄存器设置表*/ / 8 bits/char; no pari

17、ty; 1 stop bit; stop bit hi. if (config->flowControl) UxUCR = UCR_FLOW | UCR_STOP; PxSEL |= HAL_UART_Px_CTS; / DMA Rx is always on (self-resetting). So flow must be controlled by the S/W polling the Rx / buffer level. Start by allowing flow. PxOUT &= HAL_UART_Px_RTS; PxDIR |= HAL_UART_Px_RTS;

18、 else UxUCR = UCR_STOP; /停止位为高电平 /*dont care*/ dmaCfg.rxBuf0 = *(volatile uint8 *)DMA_UDBUF; / Clear the DMA Rx trigger. HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_RX); HAL_DMA_ARM_CH(HAL_DMA_CH_RX); osal_memset(dmaCfg.rxBuf, (DMA_PAD 0xFF), HAL_UART_DMA_RX_MAX*2); UxCSR |= CSR_RE; / Initialize that TX DMA is not

19、 pending dmaCfg.txDMAPending = FALSE; dmaCfg.txShdwValid = FALSE;波特率UxBAUD.BAUD_M7:0UxGCR.BAUD_E误差(%)24005960.1448005970.1496005980.141440021680.03192005990.142880021690.033840059100.1457600216100.037680059110.14115200216110.03230400216120.03至此,串口的初始化已经全部完成了,我们在使用串口时只需要调用写串口函数HalUARTWrite(uint8 port

20、, uint8 *buf, uint16 len) 和串口读函数HalUARTRead(uint8 port, uint8 *buf, uint16 len) 就行了,在这两个函数的内部同样是使用判断宏的方法来调用,DMA串口读写函数还是ISR串口读写函数,关于串口读写方式的具体实现方式在这里不再详细介绍,毕竟在使用时我们并不需要对它们进行改动。上面结介绍了串口初始化的流程,接下来介绍如何在协议栈中配置使用串口。二、 在协议栈中配置使用串口首先确定你在options选项下定义了宏来使用串口功能,比如说宏ZTOOL_P1,如下图所示:如果你的协议栈是默认的设置,就是装上以后没有修改过,那就按照下

21、面的步骤来,如果是你修改使用过的,就只修改和你的不同的地方就行了。首先新建两个C文件,GenericAppCoordinator.c和GenericAppEnddevice.c,然后将协议栈中原来的GenericApp中的内容分别复制进新建的两个文件中,这样做是为了能清除地区分不同设备类型的程序,然后将新建的两个文件添加到协议栈的APP层。首先修改GenericAppCoordinator.c文件,修改GenericApp_Init函数如下(只写出并注释了添加的部分,省略部分和原代码相同):void GenericApp_Init( byte task_id ) halUARTCfg_t ua

22、rtConfig; /定义一个串口配置有关的结构体类型 uartConfig.configured = TRUE; /注册串口 uartConfig.baudRate = HAL_UART_BR_9600; /波特率设置为9600 uartConfig.flowControl = FALSE; /禁用硬件流控 uartConfig.flowControlThreshold = 1; / 2x30 don't care - see uart driver. uartConfig.rx.maxBufSize = 255; / 2x30 don't care - see uart d

23、river. uartConfig.tx.maxBufSize = 255; / 2x30 don't care - see uart driver. uartConfig.idleTimeout = 1; / 2x30 don't care - see uart driver. uartCEnable = TRUE; / 2x30 don't care - see uart driver. uartConfig.callBackFunc =rxCB; /注册串口回调函数 HalUARTOpen (0,&uartConfig);/ 打开串口0

24、将GenericApp_MessageMSGCB函数中的内容替换如下:void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt ) uint8 sendBuff11; /定义一个发送的数据, switch ( pkt->clusterId ) case GENERICAPP_CLUSTERID: osal_memcpy(&sendBuff,pkt->cmd.Data,sizeof(sendBuff);/将数据包中的数据拷贝到发送数组中 HalUARTWrite(0,(uint8*)&sendBuff,sizeo

25、f(sendBuff); /将接收到的数据输出到串口 break; 在文件开头声明串口回调函数:/* * LOCAL FUNCTIONS */void GenericApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg );void GenericApp_HandleKeys( byte shift, byte keys );void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );void GenericApp_SendTheMessage( void );void rxCB(uint8 port

26、,uint8 event);在文件的最后添加串口回调函数:void rxCB(uint8 port,uint8 event) /*添加自定义的功能,用来读出串口发来的数据*/以上是协调器端的代码修改,具体的功能就是当协调器接收到无线数据后,就通过串口0将收到的无线数据通过串口发送,这样我们就可以在电脑上用串口调试软件来观察接收到的无线数据了。要实现上述的功能还需要另外一个设备来向协调器发送无线数据,这里我们用一个终端节点设备来向协调器发送无线数据。接着来修改GenericApp_Enddevice文件中的代码,GenericApp_Init函数的修改和GenericApp_Coordinato

27、r.c中的修改一样。然后在GenericApp_ProcessEvent( byte task_id, UINT16 events )函数中,如果终端节点设备加入网络(网络状态改变),我们就触发发送数据的事件,代码修改如下(省略部分和原代码相同):UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )case AF_INCOMING_MSG_CMD: GenericApp_MessageMSGCB( MSGpkt ); break; case ZDO_STATE_CHANGE: GenericApp_NwkState = (d

28、evStates_t)(MSGpkt->hdr.status); if ( (GenericApp_NwkState = DEV_ZB_COORD) | (GenericApp_NwkState = DEV_ROUTER) | (GenericApp_NwkState = DEV_END_DEVICE) ) / Start sending "the" message in a regular interval. osal_set_event(GenericApp_TaskID,GENERICAPP_SEND_MSG_EVT); break;if ( events &a

29、mp; GENERICAPP_SEND_MSG_EVT ) / Send "the" message GenericApp_SendTheMessage(); / Setup to send message again osal_start_timerEx( GenericApp_TaskID, GENERICAPP_SEND_MSG_EVT, GENERICAPP_SEND_MSG_TIMEOUT ); / return unprocessed events return (event上述代码的意思时,如果终端节点的网络状态发生改变(加入网络),就设置事件GENERICA

30、PP_SEND_MSG_EVT,如果事件GENERICAPP_SEND_MSG_EVT发生(被设置),就调用函数GenericApp_SendTheMessage()来发送无线数据,同时使用osal_start_timerEx函数来定时触发GENERICAPP_SEND_MSG_EVT事件,也就是每GENERICAPP_SEND_MSG_TIMEOUT时间发送一次数据。既然要发送数据,我们还需要在GenericApp_SendTheMessage()函数中做些修改,将函数修改成如下内容:void GenericApp_SendTheMessage( void ) char theMessage

31、Data = "Hello World"/要发送的数据 GenericApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit; /使用16位的短地址发送数据 GenericApp_DstAddr.endPoint = GENERICAPP_ENDPOINT; /数据源为终端节点 GenericApp_DstAddr.addr.shortAddr = 0x0000; /数据发送的目标地址为0X0000,即协调器 if ( AF_DataRequest( &GenericApp_DstAddr, &GenericApp_ep

32、Desc, GENERICAPP_CLUSTERID, (byte)osal_strlen( theMessageData ) + 1, (byte *)&theMessageData, &GenericApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) = afStatus_SUCCESS ) / Successfully requested to be sent. else / Error occurred in request to send. 剩下的就是串口回调函数了,处理方法和协调器那里的相同。至此串口的配置就全部完成了,

33、将程序非别烧到协调器和终端节点,然后用串口调试软件监测协调器的串口0,发现会以5秒每次的频率接收到Hello World数据。前面讲过,协议栈默认地以DMA的方式来处理串口,而且默认的是使用串口0的,但是如果我们在项目中要用到两个串口时该怎么办呢?接下来就介绍如何在协议栈中配置以同时使用两个串口。三、 在协议栈中配置以同时使用两个串口要想同时使用两个串口,就需要以两种不同的方式来处理串口,既然串口0默认使用了DMA方式,那我们就看一下如何以ISR的方式来处理串口1。首先是初始化,在前面我们分析过,在串口的初始化函数HalUARTInit中是以判断宏的方式来决定以什么样的方式来对串口进行初始化的

34、,同时我们也分析过在hal_board_cfg.h中宏HAL_UART_DMA被定义为了1,而宏HAL_UART_ISR被定义为了0,所以我们要在hal_board_cfg.hR文件中将宏HAL_UART_ISR定义为非0值,那么这个非0值是几呢?我们来看一下HalUARTOpen函数中的代码来确定:uint8 HalUARTOpen(uint8 port, halUARTCfg_t *config) (void)port; (void)config;#if (HAL_UART_DMA = 1)/ HAL_UART_DMA为1,所以会执行下面的语句/*只有在串口号为0的时候才会以DMA的方式打

35、开串口0*/ if (port = HAL_UART_PORT_0) HalUARTOpenDMA(config);#endif#if (HAL_UART_DMA = 2) /下面的语句不会被执行 if (port = HAL_UART_PORT_1) HalUARTOpenDMA(config);#endif#if (HAL_UART_ISR = 1) /如果将HAL_UART_ISR 设置为1,就会执行下面的语句/*只有在串口号为0的时候才会以ISR的方式打开串口0*/ if (port = HAL_UART_PORT_0) HalUARTOpenISR(config);#endif#if

36、 (HAL_UART_ISR = 2)/ 如果将HAL_UART_ISR 设置为2,就会执行下面的语句/*只有在串口号为1的时候才会以ISR的方式打开串口0*/ if (port = HAL_UART_PORT_1) HalUARTOpenISR(config);#endif#if (HAL_UART_USB) HalUARTOpenUSB(config);#endif return HAL_UART_SUCCESS;通过上面所加的注释我们大致可以看出,串口0被固定地只能用DMA的方式来处理,也就是说如果想使用串口1的话就必须使用ISR的方式来处理串口1,也就是说给HAL_UART_ISR定义

37、的非0值只能是2,明白了这一点以后,我们就在hal_board_cfg.h修改HAL_UART_ISR的宏定义为2,修改如下:/* Set to TRUE enable UART usage, FALSE disable it */#define HAL_UART_DMA 1#endif#endif#define HAL_UART_ISR 2#else这样的话,在初始化时就可以同时对两个串口以不同的方式初始化了,但是要想使用串口1的话还需要设置串口1的位置(位置1或者2),也就是串口以所在的端口,以及其他相关的寄存器,要修改的位置在_hal_uart_isr.c文件中,在这里我们将串口1配置到

38、位置1,也就是P04作为UART1的TX,P05作为UART1的RX,首先要将文件中所有的预编译判断 #if (HAL_UART_ISR = 1)修改为#if (HAL_UART_ISR = 2),这是因为我们将他的宏定义改成了2,然后修改串口1配置有关的寄存器宏定义如下(我将默认的注释掉了):#if (HAL_UART_ISR = 2) /#if (HAL_UART_ISR = 1)/*unenable the default*/*#define PxOUT P0#define PxDIR P0DIR#define PxSEL P0SEL#define UxCSR U0CSR#define

39、UxUCR U0UCR#define UxDBUF U0DBUF#define UxBAUD U0BAUD#define UxGCR U0GCR#define URXxIE URX0IE#define UTXxIE UTX0IE#define UTXxIF UTX0IF*/*END*/*use add*/#define PxOUT P0 /UART1在P0口位置#define PxDIR P0DIR /端口0方向控制寄存器#define PxSEL P0SEL /端口0功能选择#define UxCSR U1CSR /UART1控制和状态寄存器#define UxUCR U1UCR /UART

40、1控制寄存器#define UxDBUF U1DBUF /UART1发送和接收数据缓冲区#define UxBAUD U1BAUD /UART1波特率设置寄存器#define UxGCR U1GCR /UART1通用控制#define URXxIE URX1IE /UART1 RX中断使能#define UTXxIE UTX1IE /UART1 TX中断使能#define UTXxIF UTX1IF /UART1 TX中断标志/*END*/接着是串口1位置有关的寄存器宏定义:#if (HAL_UART_ISR = 2) /#if (HAL_UART_ISR = 1)/*unenable the default*/*#define HAL_UART_PERCFG_BIT 0x01 / USART0 on P0, Alt-1; so clear this bit.#define HAL_UART_Px_RX_TX 0x0C / Peripheral I/O Select for Rx/Tx.#define HAL_UART_Px_RTS 0x20 / Peripheral I/O Select for RTS.#define HAL_UART_Px_CTS 0x10 / Peripheral I/O Select for CTS.*/*end*/*use add*/#define

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论