永发信息网

zstack中怎样通过串口接收数据

答案:1  悬赏:0  手机版
解决时间 2021-04-01 12:41
zstack中怎样通过串口接收数据
最佳答案
网上和论坛里面很多帖子都把精力集中到分析协议栈的串口工作机制上,比如分析DMA
工作原理,中断工作原理,然后分析输入和输出Buffer的处理等内容,学习者跟着协议栈的
串口底层一直到顶层转圈、转圈、再转圈,蒙圈了。
实际上,从应用角度讲,我们根本就没有必要去深入的追究Zstack中串口的工作机制,
也没有必要去搞清楚到底是怎么DMA和Interrupt的,我们只要调用几个简单函数就可以正
常使用串口了。其实协议栈已经把使用串口的条件准备好了,我们何必再纠结硬件底层实现
呢?应用者应该把协议栈看作一个平台,平台之上的应用才是我们的目标。下面我就讲一下
如何利用协议栈现有平台来实现自己的串口应用。这里我所提及的现有平台即是Zstack自带
的MT包,其实Zstack中的这个MT包功能相当强大,通过TI提供的ZTOOL工具可以用串
口的方式同整个协议栈进行交互,在我们编写Zigbee应用程序的过程中,很多不知道该如何
调用的函数都能在MT中找到参考!这个不多说了,有兴趣的同学可以去专门研究一下MT
包。
二、使用方法
在MT包中,已经有了串口初始化即串口数据处理函数可用,关键的几个函数出现在
MT_Uart.c文件中。我们拿出来几个关键函数说明一下(我捡重要语句注释):
第一个函数
void MT_UartInit ()
{ // 这个是MT中的一个串口初始化函数,主要作用是初始化串口工作的一些规矩
halUARTCfg_t uartConfig;

App_TaskID = 0; //处理串口数据的任务ID,可以先不管
uartConfig.configured = TRUE;
uartConfig.baudRate = MT_UART_DEFAULT_BAUDRATE;
//默认38400波特率;可以更改,但是可能有新问题,具体解释内容比较多,我不说;
uartConfig.flowControl = FALSE;//MT_UART_DEFAULT_OVERFLOW;
//禁止硬件流控,如果你的串口只有RXD,TXD和GND三条线,必须这么做;
uartConfig.flowControlThreshold= MT_UART_DEFAULT_THRESHOLD;
uartConfig.rx.maxBufSize = MT_UART_DEFAULT_MAX_RX_BUFF;
uartConfig.tx.maxBufSize = MT_UART_DEFAULT_MAX_TX_BUFF;
uartConfig.idleTimeout = MT_UART_DEFAULT_IDLE_TIMEOUT;
uartConfig.intEnable = TRUE;
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
uartConfig.callBackFunc = MT_UartProcessZToolData;
//如果编译的时候选择使用ZTOOL,那么MT_UartProcessZtoolData将会处理串口接到的数
//据串
#elif defined (ZAPP_P1) || defined (ZAPP_P2)
uartConfig.callBackFunc = MT_UartProcessZAppData;
//如果编译的时候没有选择ZTOOL,而是选择使用了ZAPP,则由MT_UartProcessZAppData
//函数来处理串口数据串
(*如果是用CC2530的P0口那两根串口引脚,你就要define ZTOOL_P1,如果是P1口的那
两根串口引脚,你就要define ZTOOL_P2,对于ZAPP_P1和ZAPP_P2也是一个情况*)
#else
uartConfig.callBackFunc = NULL;
//这个地方,如果你有兴趣自己写一个串口处理函数,那么你实现一个My_UartProcessData
//函数,然后填到这里,替换NULL。
#endif

#if defined (MT_UART_DEFAULT_PORT)
HalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig);
//如果定义了默认串口,(0或者1),打开串口,这个HalUartOpen函数会做一大堆工作,具
//体说来就是初始化呗。。。,我没有必要展开。需要注意的是这个函数把前面哪一堆初始化
//的uartConfig做为参数传进去了噢!
#else

(void)uartConfig;
#endif

#if defined (ZAPP_P1) || defined (ZAPP_P2)

MT_UartMaxZAppBufLen = 1;
MT_UartZAppRxStatus = MT_UART_ZAPP_RX_READY;
//这两句,如果是不想使用MT_UartProcessZToolData来处理串口数据,就。。。。
//再说就要深入串口机制了,网上讲解文章太多了,自己看吧,我一会儿使用
//MT_UartProcessZToolData。
#endif
}
第二个函数
void MT_UartRegisterTaskID( byte taskID )
{
App_TaskID = taskID;
}
第三个函数
void MT_UartProcessZToolData ( uint8 port, uint8 event )
osal_msg_deallocate ( (uint8 *)pMsg );
}
我们往上看看这个Message是什么?MT_UartProcessZToolData函数开始不远的地方有以下程
序段:
if (pMsg)
{
pMsg->hdr.event = CMD_SERIAL_MSG;
pMsg->msg = (uint8*)(pMsg+1);
pMsg->msg[MT_RPC_POS_LEN] = LEN_Token;
state = CMD_STATE1;
}
从这里看到,这个函数建立了一个消息头,用CMD_SERIAL_MSG做为消息,那么
osal_msg_send给任务的那个消息将会以CMD_SERIAL_MSG出现。。。。。。。
好了,以上三个函数看完,我们试着使用一下:
以GenericApp例子为例:
void GenericApp_Init( byte task_id )

XXXXXXXXXXXXX
XXXXXXXXXXXXX
(这个函数的最后,其实放在这个函数的哪里都行)
MT_UartInit(); //added by kennan
MT_UartRegisterTaskID(GenericApp_TaskID);

再看一下MT_UartRegisterTaskID(GenericApp_TaskID):
void MT_UartRegisterTaskID( byte taskID )
{
App_TaskID = taskID;
}
好了,这样,我们顺利地把串口发来的数据用MT_UartProcessZToolData来处理,并且把处理
后的数据打包发给了任务GenericApp_TaskID。
接下来,我们看一下在GenericApp_TaskID中如何处理吧。
在GenericApp的主处理函数中:
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )

if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t*)osal_msg_receive( GenericApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case ZDO_CB_MSG:
GenericApp_ProcessZDOMsgs( (zdoIncomingMsg_t *)MSGpkt );
break;
case KEY_CHANGE:
GenericApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t
*)MSGpkt)->keys );
break;
//增加
Case CMD_SERIAL_MSG:
ProcessUartData((mtOSALSerialData_t *)MSGpkt);
//这个函数你自己实现吧,想做啥呢?想做啥就做啥。如果想把接
//到的数据发回串口,调用HalUARTWrite就行了。

如果你不知道如何提取串口消息并处理,我就好人做到底,帮你实现一个ProcessUartData()
函数吧。这个函数的作用是把接收到的数据从CM0开始一直到payload的最后一个字节发送
给串口回显,不包括校验字节噢。
ProcessUartCommand((mtOSALSerialData_t *)MSGpkt)
{ //为了正确地进行下面工作,用mtOSALSerialData_t类型来指向整个zigbee数据包(不是串
//口数据包)
uint8 *pMsg;
pMsg = MSGpkt->msg;
//定义一个指针,指向真正的串口接收数据存放位置,MSGptk里面还有一些别的Header噢。
switch ( MSGpkt->hdr.event )
{
case CMD_SERIAL_MSG://如果是串口消息。。。。
HalLedSet( HAL_LED_RED, HAL_LED_MODE_FLASH );
//用LED灯指示一下收到数据啦
uint8 *pBuffer;
uint8 datalength;
uint8 i;
//定义几个变量,为从接收到的串口包里面提取数据以及写回串口做准备
datalength = *pMsg++;
//串口包中第一个字节是数据长度噢
pBuffer = osal_mem_alloc(datalength);
//分配一块内存准备把串口消息数据拿出来
if(pBuffer != NULL)
{
for(i = 0;i < datalength; i++)
*pBuffer++ = *pMsg++;
//把消息中的串口数据按照datalength数量挨个捞出来放血(放血啥意思?把池子
//里面那东西捞出来放血,明白不?
HalUARTWrite(0,pBuffer,datalength);
//捞出来放血的串口数据再写回串口,也就是送到串口助手显示
Osal_memfree(pBuffer);
//动态申请的内存记得用完了free一下噢
}
break;
default:
break;
}
}
说明:因为ZTOOL发过来的数据是有格式的,所以如果你用串口助手来测试,那么发的数
据要按照格式来,如果你不想按那个格式,你可以自己去修改MT_UartProcessZToolData里面
的相关程序。这种方法对于想要通过PC来控制zigbee的应用场合非常实用,因为你PC发过
来的一般也会有命令和数据,如果不用MT的格式,你自己也要规范一个格式,既然MT已
经有了,我们就借用就好。
对于MT_UartProcessZAppData这个处理方法,也就是你define了ZAPP_P1或ZAPP_P2
的情况,其机制也是类似的,只不过没有规定格式,你更自由,这里我就不多说了。
再有,如果你真的在测试的时候不知道那么一长串数据的xor 结果是多少,也可以去
MT_UartProcessZToolData函数中,找到:
//if ((MT_UartCalcFCS ((uint8*)&pMsg->msg[0], MT_RPC_FRAME_HDR_SZ +
LEN_Token) == FSC_Token))
{
osal_msg_send( App_TaskID, (byte *)pMsg );
}
else
//{
//osal_msg_deallocate ( (uint8 *)pMsg );
//}
把我标红的几个位置注释掉,就不会校验了,你也不用算xor结果了,不过发数据的时候
这个位置还是要的,你随便填个0好了。
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
妈妈把一壶食油分别装在小玻璃瓶里。 每瓶装3
双开对官员意味着什么
给书店起一个有意义的店名?
一个英语辩论赛论题,求一辩开场发言和四辩总
格力二级能效 大1匹 壁挂式 能效比3.49 一小
请问奔驰r级哪里有卖?
核桃油能擦木器吗
波导和步步高的选择
西方财政理论的主要内容包括哪些?
门字加大字是什么字?谢谢
手机没电自动关机了了,但是一插上充电器又有
我家有古动 找拍卖公司收费是不是骗人的
河南成人高考的河南成考历年分数线
请问这个青花碗是什么时候的?值多少钱
新城国际酒店这个地址在什么地方,我要处理点
推荐资讯
湘潭那儿有宠物店吗,具体的位置在哪儿
《星露谷物语》鱼竿升级方法 鱼竿怎么升级
手机7软件可以吗
表姐从意大利给我带了一套 Blift的护肤品 问
在河源忠信办的结婚证去哪办离婚证
联想S301和酷比E66哪个好
话说JAKE篇的最终BOSS生前是不是也算英俊小生
天津独留有什么地方适合夜跑
大年初十返程人多吗?
骗取社会保险待遇如何处罚?要入刑吗
有一台220v,36v的降压变压器,二次绕组接一
怎么把DLL命令注入DNF,最好是用输入法注入的
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?