ImageVerifierCode 换一换
格式:DOCX , 页数:19 ,大小:36.94KB ,
资源ID:7282719      下载积分:12 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/7282719.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(ZStack中串口发送接收的流程.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

ZStack中串口发送接收的流程.docx

1、ZStack中串口发送接收的流程Z-Stack中串口发送接收的流程 (2010-12-16 18:42) 分类: ZigBee 技术学习 串口接收发送数据有两种方式,一种是中断的模式,另一种是DMA方式,这里主要以中断的方式,来看一下使用串口来发送,接收数据的整个流程。这里以SerialApp例程为例子。在mian函数中的调用HalDriverInit();函数,在函数中初始化串口,主要是配置管脚和DMA通道void HalDriverInit (void)/* UART */#if (defined HAL_UART) & (HAL_UART = TRUE)HalUARTInit();#en

2、dif从程序中可以看出要想使用协议栈中串口,初始化串口必须定义HAL_UART和HAL_UART TRUE 在hal_board_cfg.h文件中。#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 /* ZAPP, ZTOOL */#endif /* HAL_UART */然后在osal_start_system()开始系统后,会调用Hal

3、_ProcessPoll()来读取时间和串口。在CC2430的数据手册中有这样一段话。Data reception on the UART is initiatedwhen a 1 is written to the UxCSR.RE bitThe UART will then search for a valid start bit on the RXDx input pin and set theUxCSR.ACTIVE bit high. When a validstart bit has been detected the received byte is shifted into t

4、he receive register .The UxCSR.RX_BYTE bit is set and a receive interrupt is generated when the operation has completed. The received data byte is available through the UxBUF register. When UxBUF is read, UxCSR.RX_BYTE is cleared by hardware.当有数据接收时,UxCSR.RE位将被置1,然后,UART将在RXDx的输入引脚上查找一个有效的开始位,当找到这个开

5、始位时,将设置UxCSR.ACTIVE位为高电平。当一个有效的开始位被查找到,收到的字节将被移动到接收寄存器中。然后,UxCSR.RX_BYTE位设为1.并且,当这个接收操作完成后接收中断会被产生。接收到的数据可以通过操作UxBUF寄存器,当UxBUF寄存器的数据被读出后,UxCSR.RX_BYTE位被硬件清除。串口发生中断首先调用中断的处理函数,这个是接收的中断函数。#if HAL_UART_0_ENABLEHAL_ISR_FUNCTION( halUart0RxIsr, URX0_VECTOR )cfg0-rxBufcfg0-rxHead = U0DBUF;if ( cfg0-rxHead

6、 = cfg0-rxMax )cfg0-rxHead = 0;elsecfg0-rxHead+;#endif该中断函数主要是把U0DBUF寄存器,也就是接收到数据的寄存器,把数据读取来放到UART的结构体中的,cfg0-rxBuf,中,这个数组的内存分配是在HalUARTOpen()函数中。SerialApp.c中有下面的定义#if !defined( SERIAL_APP_RX_MAX )#if (defined( HAL_UART_DMA ) & HAL_UART_DMA#define SERIAL_APP_RX_MAX 128#else/* The generic safe Rx min

7、imum is 48, but if you know your PC App will not* continue to send more than a byte after receiving the CTS, lower max* here and safe min in _hal_uart.c to just 8.*/#define SERIAL_APP_RX_MAX 64#endif#endifSerialApp_Init()函数中有下面的赋值,uartConfig.rx.maxBufSize = SERIAL_APP_RX_MAX;HalUARTOpen()函数中有下面的赋值:所

8、以其cfg-rxMax=128,cfg-rxMax = config-rx.maxBufSize;其中rxHead这个参数始终指向像一个参数被存放到rxBuf的位置。因为硬件串口缓存器U0DBUF只能存放一个字节,如果不及时把这个接收到的转移出去,那么就会被下一个到来的字节覆盖掉,所以rxHead变量就指向了这个存放的地址,当然是基于定义的rxBuf存储空间。而if ( cfg0-rxHead = cfg0-rxMax )这一句判断也说明的很清楚,一旦这个计数达到了定义的最大接收数量,也就是说已经把rxBuf存储空间占满了,那么就不能在继续存放了。中断函数执行完后,就应该跳到发生中断时执行的地

9、方,这时程序继续执行,然后在osal_start_system()开始系统后,会循环调用Hal_ProcessPoll()来读取时间和串口,void Hal_ProcessPoll ()/* Timer Poll */HalTimerTick();/* UART Poll */#if (defined HAL_UART) & (HAL_UART = TRUE)HalUARTPoll();#endif下面是HalUARTPoll();函数的源代码,在这里有对接收到的数据进行处理的程序。void HalUARTPoll( void )#if ( HAL_UART_0_ENABLE | HAL_UA

10、RT_1_ENABLE )static uint8 tickShdw;uartCfg_t *cfg;uint8 tick;#if HAL_UART_0_ENABLE/当发生串口接收中断时cfg0就会改变,如果串口没有数据输入cfg0为空,当接收到数据时cfg0将在串口中断服务程序中被改变if ( cfg0 )cfg = cfg0;#endif#if HAL_UART_1_ENABLEif ( cfg1 )cfg = cfg1;#endif/ Use the LSB of the sleep timer (ST0 must be read first anyway)./系统上电后,睡眠定时器就会

11、自动启动做自增计数ST0即睡眠定时器启动到现在计算值的最低8位tick = ST0 - tickShdw;tickShdw = ST0;/下面是一个无限循环do/-发送超时时间if ( cfg-txTick tick )cfg-txTick -= tick;elsecfg-txTick = 0;/-接收超时时间if ( cfg-rxTick tick )cfg-rxTick -= tick;elsecfg-rxTick = 0;/是使用DMA方式还是使用中断方式#if HAL_UART_ISR#if HAL_UART_DMAif ( cfg-flag & UART_CFG_DMA )pollD

12、MA( cfg );else/中断方式#endifpollISR( cfg );#elif HAL_UART_DMApollDMA( cfg );#endif/* The following logic makes continuous callbacks on any eligible flag* until the condition corresponding to the flag is rectified.* So even if new data is not received, continuous callbacks are made./如果接收缓存中有数据,当接收数据时rxH

13、ead会增计数,当读取数据时rxTail会增计数,两个标志的初始值都为0,所以这两个标志的差值就指示了缓存中有多少的数据*/if ( cfg-rxHead != cfg-rxTail ) /不相等表示有数据uint8 evt;if ( cfg-rxHead = (cfg-rxMax - SAFE_RX_MIN) )/已保存的数据已经超过了安全界限,发送接收满事件evt = HAL_UART_RX_FULL;else if ( cfg-rxHigh & (cfg-rxHead = cfg-rxHigh) )/rxBuf 接收到预设值(默认80字节),则触发事件,为什么是80,在上一篇转载的文章中

14、有介绍,这里重点关注执行的流程。evt = HAL_UART_RX_ABOUT_FULL;else if ( cfg-rxTick = 0 )/超时事件evt = HAL_UART_RX_TIMEOUT;elseevt = 0;/如果发生事件,并且配置了回调函数则调用回调函数if ( evt & cfg-rxCB )/(cfg-flag & UART_CFG_U1F)!=0)判读是那个串口,如果是串口1则为1,否则为0cfg-rxCB( (cfg-flag & UART_CFG_U1F)!=0), evt );#if HAL_UART_0_ENABLEif ( cfg = cfg0 )#if

15、HAL_UART_1_ENABLEif ( cfg1 )cfg = cfg1;else#endifbreak;else#endifbreak; while ( TRUE );#elsereturn;#endif说明:(1)下面我们看一下pollISR()函数static void pollISR( uartCfg_t *cfg )/计算rxBuf中还有多少数据没有读出(以字节为单位)uint8 cnt = UART_RX_AVAIL( cfg );/如果串口没有接收到数据,也就是说没有发生过串口接收中断,那么cfg应为是为空的,则cnt=0如果发生了串口中断,则cnt计算出串口缓存中还有多少数

16、据没有读出,这个缓存并不是硬件寄存器的缓存,而是程序中开辟一段空间if ( !(cfg-flag & UART_CFG_RXF) )/这里是针对流控制的,如果又有新的数据接收到了那么就要重置超时时间(超时时间由睡眠定时器来控制),而且需要把已经读出的数据数目减去!/ If anything received, reset the Rx idle timer.if ( cfg-rxCnt != cnt )cfg-rxTick = HAL_UART_RX_IDLE;cfg-rxCnt = cnt;/* It is necessary to stop Rx flow in advance of a

17、full Rx buffer becausebytes can keep coming while sending H/W fifo flushes./当接收缓存超过安全界限的时候停止RX流*/if ( cfg-rxCnt = (cfg-rxMax - SAFE_RX_MIN) )RX_STOP_FLOW( cfg );#endifpollISR()函数主要作用就是设置rxTick和rxCn,/关于安全界限,在程序中有下面一段:/* Need to leave enough of the Rx buffer free to handle the incoming bytes* after as

18、serting flow control, but before the transmitter has obeyed it.* At the max expected baud rate of 115.2k, 16 bytes will only take 1.3 msecs,* but at the min expected baud rate of 38.4k, they could take 4.2 msecs.* SAFE_RX_MIN and DMA_RX_DLY must both be consistent according to* the min & max expecte

19、d baud rate.*/如果声明了流控制,为保证数据的正确接收需要在RX缓存区中预留出足够的空间。CC2430可以使用的最大串口波特率为115.2k。这个安全界限的数字跟使用的波特率还有串口tick有关。具体参考Z-STACK问题之串口结构uartCfg_t乱说文章。可以看到,在初始化时rxHead=rxTail=0,如果发生接收中断,在中断服务函数中把U0DBUF寄存器中的数据传送到rxbuf中,这时rxHead和rxTail的值不在相等,其中,rxHead是rxBuf接收到数据的个数,rxTail是rxBuf移出的数据个数,再根据两者的差值,判断具体的事件evt。然后,根据evt和设置

20、的回调函数,通过cfg-rxCB调用相应的回调函数。代码也是体显在下面一句。cfg-rxCB( (cfg-flag & UART_CFG_U1F)!=0), evt );第一个参数主要是判断,是UART1还是UART0.第二个参数是触发的事件类型,那个个回调函数,具体是指向函数呢?首先,我们在void SerialApp_Init( uint8 task_id )初始化函数中,对串口进行了配置,其中下面两句中有关于回调函数的。#elseuartConfig.callBackFunc = rxCB;#endifHalUARTOpen (SERIAL_APP_PORT, &uartConfig);

21、其中,在HalUARTOpen()函数中,有下面的一条语句,uint8 HalUARTOpen( uint8 port, halUARTCfg_t *config )cfg-rxCB = config-callBackFunc; 也就是调用下面的rxCB函数。程序中定义了两个串口接收缓冲区:otaBuf上otaBuf2.当otaBuf中无数据时,处于空闲状态时,由otaBuf接收串口数据;当otaBuf中保留有数据时,下等待接收节点发送接收数据响应或由于某些正在重新给接收节点发送数据时,可通过otaBuf2接收数据,当otaBuf和otaBuf2都没有处于空闲状态时,说明数据没有及时发送给接收

22、节点,发生了数据累积,缓冲区被占用,需要进行流量控制,所以直接退出接收回调函数,暂不接收数据。static void rxCB( uint8 port, uint8 event )uint8 *buf, len;/* While awaiting retries/response, only buffer 1 next buffer: otaBuf2.* If allow the DMA Rx to continue to run, allocating Rx buffers, the heap* will become so depleted that an incoming OTA res

23、ponse cannot be received.* When the Rx data available is not read, the DMA Rx Machine automatically* sets flow control off - it is automatically re-enabled upon Rx data read.* When the back-logged otaBuf2 is sent OTA, an Rx data read is scheduled.*/if ( otaBuf2 ) /缓冲区被占用return;if ( !(buf = osal_mem_

24、alloc( SERIAL_APP_RX_CNT ) )return;/* HAL UART Manager will turn flow control back on if it can after read.* Reserve 1 byte for the sequence number.这里的SERIAL_APP_RX_CNT为80这里为什么是80,上篇文章中也有分析*/len = HalUARTRead( port, buf+1, SERIAL_APP_RX_CNT-1 );if ( !len ) / Length is not expected to ever be zero.os

25、al_mem_free( buf );return;/* If the local global otaBuf is in use, then either the response handshake* is being awaited or retries are being attempted. When the wait/retries* process has been exhausted, the next OTA msg will be attempted from* otaBuf2, if it is not NULL. otaBuf正在使用,则就使用otaBuf2*/if (

26、 otaBuf ) /otaBuf正在被占用otaBuf2 = buf; /otaBuf2接收数据otaLen2 = len;elseotaBuf = buf; /otaBuf接收数据otaLen = len;/* Dont call SerialApp_SendData() from here in the callback function.* Set the event so SerialApp_SendData() runs during this tasks time slot.产生发送数据事件*/osal_set_event( SerialApp_TaskID, SERIALAPP

27、_MSG_SEND_EVT );#endif在事件处理函数中,有下面的判断。UINT16 SerialApp_ProcessEvent( uint8 task_id, UINT16 events )if ( events & SERIALAPP_MSG_SEND_EVT )SerialApp_SendData( otaBuf, otaLen );/return ( events SERIALAPP_MSG_SEND_EVT );下面是SerialApp_SendData()函数的源代码,调用AF_DataRequest(),通过OTA发送数据。由于在数据包之前增加了序列号SerialApp_S

28、eqTx,多次重发的数据不会被接收节点重复发送到串口。static void SerialApp_SendData( uint8 *buf, uint8 len )afStatus_t stat;/ Pre-pend sequence number to the start of the Rx buffer.*buf = +SerialApp_SeqTx;otaBuf = buf;otaLen = len+1;stat = AF_DataRequest( &SerialApp_DstAddr,(endPointDesc_t *)&SerialApp_epDesc,SERIALAPP_CLUST

29、ERID1,otaLen, otaBuf,&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS );if ( (stat = afStatus_SUCCESS) | (stat = afStatus_MEM_FAIL) )/在设定的时间内没有发送成功,则重新发送。osal_start_timerEx( SerialApp_TaskID, SERIALAPP_MSG_RTRY_EVT,SERIALAPP_MSG_RTRY_TIMEOUT );rtryCnt = SERIALAPP_MAX_RETRIES;elseFREE_OTABUF();/重发的次数void SerialApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt )uint8 stat;uint8 seqnb;uint8 delay;switch ( pkt-clusterId )/ A message with a serial data block to be transmitted on the serial port./接收节点收到的接收数据命令,case SERIALAPP_CLUSTERID1:seqnb = pkt-cmd.Da

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1