ZigBee串口说明

来源:互联网 发布:淘宝在哪里领取优惠卷 编辑:程序博客网 时间:2024/05/01 13:38

一、串口的初始化

//系统初始化

byte osal_init_system( void )

{

……

osalInitTasks();//系统任务初始化

……

}

 

//任务初始化

void osalInitTasks( void )

{

……

#if defined( MT_TASK )//如果定义了MT_TASK就初始化MT任务,所以要使用uart必须编译MT_TASK

MT_TaskInit( taskID++ );

#endif

……

}

//MT_TASK初始化

void MT_TaskInit( byte task_id )

{

MT_TaskID = task_id;//分配任务ID

……

SPIMgr_Init();//SPI(UART)管理初始化

 

} /* MT_TaskInit() */

 

//SPI(UART)管理初始化

void SPIMgr_Init ()

{

halUARTCfg_t uartConfig;

/* Initialize APP ID */

App_TaskID = 0;//应用层TaskID初始化为0,在后面应用层如果想使用uart需要注册该TaskID

 

/* UART Configuration */

uartConfig.configured = TRUE;

uartConfig.baudRate = SPI_MGR_DEFAULT_BAUDRATE;

uartConfig.flowControl = SPI_MGR_DEFAULT_OVERFLOW;

uartConfig.flowControlThreshold = SPI_MGR_DEFAULT_THRESHOLD;

uartConfig.rx.maxBufSize = SPI_MGR_DEFAULT_MAX_RX_BUFF;

uartConfig.tx.maxBufSize = SPI_MGR_DEFAULT_MAX_TX_BUFF;

uartConfig.idleTimeout = SPI_MGR_DEFAULT_IDLE_TIMEOUT;

uartConfig.intEnable = TRUE;

 

#if defined (ZTOOL_P1) || defined (ZTOOL_P2)

uartConfig.callBackFunc = SPIMgr_ProcessZToolData; //回调函数

#elif defined (ZAPP_P1) || defined (ZAPP_P2)

uartConfig.callBackFunc = SPIMgr_ProcessZAppData; //回调函数

#else

uartConfig.callBackFunc = NULL;

#endif

/* Start UART */

#if defined (SPI_MGR_DEFAULT_PORT)

HalUARTOpen (SPI_MGR_DEFAULT_PORT, &uartConfig); //打开默认串口

#else

……

}

 

 

到这里串口的初始化基本就完成了,还有个打开串口,先不下去了,下面的水是越来越浑,过几天总结底层的…

二、串口的事件处理

 

//系统主循环

void osal_start_system( void )

{

……

Hal_ProcessPoll(); // 串口与定时器轮询函数

……

}

 

// 串口与定时器轮询函数

void Hal_ProcessPoll ()

{

HalTimerTick();

 

#if (defined HAL_UART) && (HAL_UART == TRUE)

HalUARTPoll();

#endif

}

 

//串口轮询函数

void HalUARTPoll( void )

{

……//这里会根据是DMA还是普通串口有两种不同的轮询方式,这里说普通串口

#if HAL_UART_ISR

#if HAL_UART_DMA

if ( cfg->flag & UART_CFG_DMA )

{

pollDMA( cfg );

}

else

#endif

{

pollISR( cfg );

}

#elif HAL_UART_DMA

pollDMA( cfg );

#endif

……

}

//普通串口轮询函数

static void pollISR( uartCfg_t *cfg )

{

……

 

轮询完事再次回到void HalUARTPoll函数中,看是否触发事件,如果触发了HAL_UART_RX_FULLHAL_UART_RX_ABOUT_FULLHAL_UART_RX_TIMEOUT三个中任意一个就调用回调函数处理。

 

if ( evt && cfg->rxCB )

{

cfg->rxCB( ((cfg->flag & UART_CFG_U1F)!=0), evt );

}

 

//串口回调函数

#define SPI_MGR_ZAPP_RX_READY 0x01

SPIMgr_ZAppRxStatus = SPI_MGR_ZAPP_RX_READY;

函数

void SPIMgr_ProcessZAppData ( uint8 port, uint8 event )

{

 

osal_event_hdr_t *msg_ptr;

uint16 length = 0;

uint16 rxBufLen = Hal_UART_RxBufLen(SPI_MGR_DEFAULT_PORT);

//获取串口buf中数据的长度

 

……

if (event & ( HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT))

{

if ( App_TaskID )//必须这里被注册

{

// 准备向上层发送数据

//如果接收状态为READY,并且数据长度大于0说明有数据了

if ((SPIMgr_ZAppRxStatus == SPI_MGR_ZAPP_RX_READY ) && (length != 0))

{

/*要读取这些数据了,先关闭接收!*/

SPIMgr_AppFlowControl ( SPI_MGR_ZAPP_RX_NOT_READY );

 

/* 2 more bytes are added, 1 for CMD type, other for length */

msg_ptr = (osal_event_hdr_t *)osal_msg_allocate( length + sizeof(osal_event_hdr_t) );

//分配内存一个字节存放命令event,一个字节存放长度。剩下的存放length的内存存放数据

if ( msg_ptr )

{

msg_ptr->event = SPI_INCOMING_ZAPP_DATA;

msg_ptr->status = length;//这里状态存放了数据的长度

HalUARTRead( SPI_MGR_DEFAULT_PORT, (uint8 *)(msg_ptr + 1), length );//读入buf中的数值

 

//下面是触发函数

osal_msg_send( App_TaskID, (uint8 *)msg_ptr );

//这里我觉得还要打开串口,让它接收数据啊。怎么没有来这么一句话

//SPIMgr_AppFlowControl ( SPI_MGR_ZAPP_RX_READY );

}

}

}

}

}

关闭接收函数:

void SPIMgr_AppFlowControl ( bool status )

{

 

/* Make sure only update if needed */

if (status != SPIMgr_ZAppRxStatus )

{

SPIMgr_ZAppRxStatus = status;

}

 

/* App is ready to read again, ProcessZAppData have to be triggered too */

if (status == SPI_MGR_ZAPP_RX_READY)

{

SPIMgr_ProcessZAppData(SPI_MGR_DEFAULT_PORT, HAL_UART_RX_TIMEOUT );

}

}

 

因为在 SPIMgr_AppFlowControl ( SPI_MGR_ZAPP_RX_NOT_READY )SPI_MGR_ZAPP_RX_NOT_READY=0,而SPIMgr_ZAppRxStatus=1;所以会执行SPIMgr_ZAppRxStatus = status;,即接收状态SPIMgr_ZAppRxStatus =0;不再满足SPIMgr_ZAppRxStatus == SPI_MGR_ZAPP_RX_READY所以不接收数据了。

重点说明:我认为在串口回调函数加上SPIMgr_AppFlowControl ( SPI_MGR_ZAPP_RX_READY )使得串口处理完一次后立即处理下一次。

但是如果在回调函数结束前(函数内)加上这句,那么就会在流控函数中再次调用了SPIMgr_ProcessZAppData()。而导致协议栈陷入一个死循环,所以最后更正为这句话加在事件处理后,即SPI_INCOMING_ZAPP_DATA事件处理以后。不加是不行的!

三、与应用层联姻

底层和应用层联姻呢?在TI的协议栈很多都是通过注册Register。按键、串口…

通过注册可以传递任务ID,即TaskID。从而利用偷梁换柱、浑水摸鱼的技术将底层的任务传到应用层

 

//注册函数

void SPIMgr_RegisterTaskID( byte taskID )

{

App_TaskID = taskID;//任务ID被偷梁换柱了

}

//如果应用层调用了这个函数,则此时App_TaskID就变成了应用层的任务ID了……

 

现在我们在回去简单看一下串口的回调函数

void SPIMgr_ProcessZAppData ( uint8 port, uint8 event )

{

 

……

if (event & ( HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT))

{

if ( App_TaskID )//这时已经被偷梁换柱了,可怜的底层,就这样被欺骗了

{

//下面是触发函数

osal_msg_send( App_TaskID, (uint8 *)msg_ptr );

//msg_ptr发送到App_TaskID,即你注册的应用层

……

}

  1. 应用层代码:

我是在SampleApp这个例子里修改的:

事件处理函数修改:

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )

{

afIncomingMSGPacket_t *MSGpkt;

 

if ( events & SYS_EVENT_MSG )

{

MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );

while ( MSGpkt )

{

switch ( MSGpkt->hdr.event )

{

……

case SPI_INCOMING_ZAPP_DATA:

SampleApp_UART(MSGpkt);

……

}

 

void SampleApp_UART(afIncomingMSGPacket_t *pkt)

{

HalUARTWrite(0,(uint8 *)((osal_event_hdr_t *)pkt+1),pkt->hdr.status);//将串口数据写到PC(再写回去)

SPIMgr_AppFlowControl(true); //重新打开接收

}