MT层(也有叫MT包的)是Z-Stack自带的,TI公司提供的ZTOOL工具可以通过串口的方式来和模块通信,这个工具发送的数据具有一定的协议,MT层的函数就具有解析这些协议的功能,因此在使用MT层的函数的时候,必须要遵守TI公司提供的串口协议来发送和接收数据。协议如下:

0xFE:数据帧头

DataLength:Datapayload的数据长度(不包括命令字节),以字节计,低字节在前;

CM0:命令低字节;

CM1:命令高字节;(ZTOOL软件就是通过发送一系列命令给MT实现和协议栈交互)

Data payload:数据帧具体的数据,这个长度是可变的,但是要和DataLength一致;

FCS:校验和,从DataLength字节开始到Data payload最后一个字节所有字节的异或按字节操作;

在MT_UART.h中可以被外部调用的有这些函数:

extern void MT_UartInit (void);

extern uint8 MT_UartCalcFCS( uint8 *msg_ptr, uint8 length );

extern void MT_UartRegisterTaskID( uint8 taskID );

void MT_UartProcessZToolData ( uint8 port, uint8 taskId );

void MT_UartProcessZAppData ( uint8 port, uint8 event );

1、MT_UartInit 串口初始化函数:

void MT_UartInit (){halUARTCfg_t uartConfig;//定义串口配置参数的结构体,包括波特率、使能串口等等App_TaskID = 0;uartConfig.configured           = TRUE;uartConfig.baudRate             = MT_UART_DEFAULT_BAUDRATE;uartConfig.flowControl          = MT_UART_DEFAULT_OVERFLOW;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;/*预定义,作用是使用MT_UartProcessZToolData还是MT_UartProcessZAppData*MT_UartProcessZToolData为和官方的串口调试工具通信,*MT_UartProcessZAppData为传输app数据,这个需要做一些修改才可以使用*/#if defined (ZTOOL_P1) || defined (ZTOOL_P2)uartConfig.callBackFunc         = MT_UartProcessZToolData;#elif defined (ZAPP_P1) || defined (ZAPP_P2)uartConfig.callBackFunc         = MT_UartProcessZAppData;#elseuartConfig.callBackFunc         = NULL;//如果都不想用,那么就可以自己填一个串口处理回调函数#endif#if defined (MT_UART_DEFAULT_PORT)HalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig);//串口初始化,调用上面的uartConfig作为参数,函数内还根据是否使用DMA来做不同的初始化#else(void)uartConfig;#endif#if defined (ZAPP_P1) || defined (ZAPP_P2)//同样的预定义,先不管这两个参数作用MT_UartMaxZAppBufLen  = 1;MT_UartZAppRxStatus   = MT_UART_ZAPP_RX_READY;#endif}

这个函数主要就是完成了串口的初始化,以及串口DMA的配置,最后根据宏定义ZTOOL_P1、ZTOOL_P2来确定MT的回调函数,如果都没有定义的话那么就使用用户指定的函数。如果不想用官方提供的串口模块,可以参考MT的初始化来完成自己的串口初始化代码。下面为我写的串口初始化函数,写的不好,欢迎大佬指点。


static char Uart_RX[200];
static char Uart_TX[200];static void FS_Uart_CallBack(uint8 port,uint8 event);/*
*串口初始化函数
*UARTx:要操作的是串口几
*baud:串口波特率
*/
void usart_init(uint8 UARTx,uint8 baud)
{halUARTCfg_t uartConfig;assert(ASSERT_UART_BAUD(baud));assert(ASSERT_UARTX(UARTx));uartConfig.configured           = TRUE;              // 2x30 don't care - see uart driver.uartConfig.baudRate             = baud;uartConfig.flowControl          = FALSE;uartConfig.flowControlThreshold = 32; // 2x30 don't care - see uart driver.uartConfig.rx.maxBufSize        = 32;  // 2x30 don't care - see uart driver.uartConfig.tx.maxBufSize        = 32;  // 2x30 don't care - see uart driver.uartConfig.idleTimeout          = 6;   // 2x30 don't care - see uart driver.uartConfig.intEnable            = TRUE;              // 2x30 don't care - see uart driver.uartConfig.callBackFunc         = FS_Uart_CallBack;  //指定串口回调函数HalUARTOpen (UARTx, &uartConfig);
}/*串口回调函数*/
static void FS_Uart_CallBack(uint8 port,uint8 event)
{if(( event & ( HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT ) ) ) {   if(port == HAL_UART_PORT_0){         uint16 len = Hal_UART_RxBufLen(HAL_UART_PORT_0); //取出本次接收到的字符长度              HalUARTRead(HAL_UART_PORT_0, Uart_RX, len); if ( len > 0 ){//成功接收到数据,对数据进行处理osal_printf("%s",Uart_RX);}}else//port == HAL_UART_PORT_1{}}
}//串口printf 函数
//确保一次发送数据不超过Uart_TX_LEN字节
void osal_printf(char* fmt,...)
{  uint16 i,j; va_list ap; va_start(ap,fmt);vsprintf((char*)Uart_TX,fmt,ap);va_end(ap);i=strlen((const char*)Uart_TX);     //此次发送数据的长度for(j=0;j<i;j++)           //循环发送数据{HalUARTWrite(HAL_UART_PORT_0, &Uart_TX[j], 1); }
}

2、void MT_UartRegisterTaskID( uint8 taskID );

void MT_UartRegisterTaskID( byte taskID )//注册串口任务,在应用层中的任务注册{App_TaskID = taskID;}

3、void MT_UartProcessZToolData ( uint8 port, uint8 taskId );

void MT_UartProcessZToolData ( uint8 port, uint8 event ){uint8  ch;uint8  bytesInRxBuffer;(void)event;  // Intentionally unreferenced parameterwhile (Hal_UART_RxBufLen(port)){HalUARTRead (port, &ch, 1);//从RX缓冲区中读取一个字节switch (state){//state开始的值肯定是0x00(猜的),判断数据第一个字节是不是0xFE,如果是那么state = 0x03,以此类推,下面的也是这个意思case SOP_STATE:                      //SOP_STATE =  0x00if (ch == MT_UART_SOF)      //MT_UART_SOF = 0xFEstate = LEN_STATE;            //LEN_STATE = 0x03break;case LEN_STATE:                    //LEN_STATE = 0x03LEN_Token = ch;tempDataLen = 0;//这里的C语言语法有点难懂(对我来说),给pMsg分配内存空间,大小等于sizeof ( mtOSALSerialData_t )结构体大小+1个表示数据长度的标识符占用的空间+两个CMD占用的空间+数据占用的空间,注意这里最后强制转换成mtOSALSerialData_t这个结构体的指针,也就是pMsg指向了该分配内存的首地址,而且pMsg是mtOSALSerialData_t类型的。pMsg+1 等于pMsg+sizeof ( mtOSALSerialData_t )的大小,此时指向了数据的长度标识符。而且此时的协议第二个字节表示的数据的长度,ch = dataLengthpMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof ( mtOSALSerialData_t ) +MT_RPC_FRAME_HDR_SZ + LEN_Token );if (pMsg){pMsg->hdr.event = CMD_SERIAL_MSG;pMsg->msg = (uint8*)(pMsg+1);pMsg->msg[MT_RPC_POS_LEN] = LEN_Token;   //发送CMD_SERIAL_MSGstate = CMD_STATE1;              //CMD_STATE1 = 0x01}else{state = SOP_STATE;return;}break;//和下面的两个case都表示了CMDcase CMD_STATE1:                       //CMD_STATE1 = 0x01pMsg->msg[MT_RPC_POS_CMD0] = ch;state = CMD_STATE2;                //CMD_STATE2 = 0x02break;case CMD_STATE2:pMsg->msg[MT_RPC_POS_CMD1] = ch;if (LEN_Token){state = DATA_STATE;           //DATA_STATE = 0x04}else{state = FCS_STATE;                //FCS_STATE = 0x05}break;//下面的case里就是处理数据的部分case DATA_STATE://对于刚刚接手的这个字节ch的处理pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen++] = ch;//然后通过Hal_UART_RxBufLen这个函数看看Rx缓冲区还有多少个字节bytesInRxBuffer = Hal_UART_RxBufLen(port);//如果Rx缓冲区的字节数<=(总长度 - 已读出的长度),那么一次性将缓冲区的数据读出来,否则就将(总长度 - 已读出的长度 )的数据读出来,这里很好理解,其实我认为这里数据处理在上面的 case CMD_STATE2:来完成就好了,就免去了读取第一个字节的数据这步了,可能为了更直观吧。if (bytesInRxBuffer <= LEN_Token - tempDataLen){HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], bytesInRxBuffer);tempDataLen += bytesInRxBuffer;}else{HalUARTRead (port, &pMsg->msg[MT_RPC_FRAME_HDR_SZ + tempDataLen], LEN_Token - tempDataLen);tempDataLen += (LEN_Token - tempDataLen);}//读完后,不要忘了把读取的数量更新下,全部读完后, state = FCS_STATE来看看是不是都读正确了if ( tempDataLen == LEN_Token )state = FCS_STATE;break;case FCS_STATE:           //FCS_STATE = 0x05FSC_Token = ch;//通过校验位,来判断数据是否有错误if ((MT_UartCalcFCS ((uint8*)&pMsg->msg[0], MT_RPC_FRAME_HDR_SZ + LEN_Token) == FSC_Token)){//如果正确,那么发送消息到应用层,这个消息是上面case LEN_STATE:中的pMsg->hdr.event = CMD_SERIAL_MSG;osal_msg_send( App_TaskID, (byte *)pMsg );}else{osal_msg_deallocate ( (uint8 *)pMsg );}state = SOP_STATE;break;default:break;}}}

4、void MT_UartProcessZAppData ( uint8 port, uint8 event );

这个函数就比较简单了,没有去分析那么多协议的东西

下面两个参数都是标志位,感觉没有特别大的用处。。。。

// MT_UartMaxZAppBufLen  = 1;//  MT_UartZAppRxStatus   = MT_UART_ZAPP_RX_READY;void MT_UartProcessZAppData ( uint8 port, uint8 event ){osal_event_hdr_t  *msg_ptr;uint16 length = 0;//确定Rx缓冲区数据长度uint16 rxBufLen  = Hal_UART_RxBufLen(MT_UART_DEFAULT_PORT);//MT_UartMaxZAppBufLen一次最大处理数据的长度,查看缓冲区长度是否大于这个长度if ((MT_UartMaxZAppBufLen != 0) && (MT_UartMaxZAppBufLen <= rxBufLen)){length = MT_UartMaxZAppBufLen;}else{length = rxBufLen;}if (event == HAL_UART_TX_FULL){// Do something when TX if fullreturn;}//一堆宏定义,没有深究到底有何作用,都是满足条件的if (event & ( HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)){//App_TaskID = taskID;初始化函数后,任务ID就已经不为0了if ( App_TaskID ){//在初始化函数中串口状态标识符,且有数据if ((MT_UartZAppRxStatus == MT_UART_ZAPP_RX_READY ) && (length != 0)){//关闭流控MT_UartAppFlowControl (MT_UART_ZAPP_RX_NOT_READY);//分配内存,大小=数据长度+消息头长度msg_ptr = (osal_event_hdr_t *)osal_msg_allocate( length + sizeof(osal_event_hdr_t) );if ( msg_ptr ){msg_ptr->event = SPI_INCOMING_ZAPP_DATA;msg_ptr->status = length;HalUARTRead( MT_UART_DEFAULT_PORT, (uint8 *)(msg_ptr + 1), length );//发送消息到应用层osal_msg_send( App_TaskID, (uint8 *)msg_ptr );}}}}}

关于 z-Stack MT层的使用相关推荐

  1. Zigbee使用MT层实现串口写和读操作,简要了解osal_msg_send消息机制

    MT层的串口API文件是MT_UART.c和MT_UART.h.如下图: 首先在应用层初始化函数下添加以下代码: MT_UartInit();//串口初始化 MT_UartRegisterTaskID ...

  2. Lesson 9.29.39.4 黑箱:不可解释的深层神经网络探索多层神经网络:层vsh(z)

    二.黑箱:深层神经网络的不可解释性 首先从结构上来看,多层神经网络比单层神经网络多出了"中间层".中间层常常被称为隐藏层(hidden layer),理论上来说可以有无限层,所以在 ...

  3. binder-JAVA层机制

    根据之前分析过的cpp代码,以及编写了JAVA层的代码,笔者画了一个图进行了分层 JAVA中,RPC层的代码是直接通过aidl文件生成的,cpp部分是需要我们自己编写的 那么在JAVA中就存在两个问题 ...

  4. Coursera吴恩达《神经网络与深度学习》课程笔记(4)-- 浅层神经网络

    红色石头的个人网站:redstonewill.com 上节课我们主要介绍了向量化.矩阵计算的方法和python编程的相关技巧.并以逻辑回归为例,将其算法流程包括梯度下降转换为向量化的形式,从而大大提高 ...

  5. DeepLearning.AI第一部分第三周、 浅层神经网络(Shallow neural networks)

    文章目录 3.1 一些简单的介绍 3.2神经网络的表示Neural Network Representation 3.3计算一个神经网络的输出Computing a Neural Network's ...

  6. 01.神经网络和深度学习 W3.浅层神经网络

    文章目录 1. 神经网络概览 2. 神经网络的表示 3. 神经网络的输出 4. 多样本向量化 5. 激活函数 6. 为什么需要 非线性激活函数 7. 激活函数的导数 8. 随机初始化 作业 参考: 吴 ...

  7. caffe data层_Caffe Softmax层的实现原理?

    题主没有对符号作必要的说明,先按我的理解对符号进行定义 z是softmaxwithloss层的输入,f(z)是softmax的输出,即 y是输入样本z对应的类别,y=0,1,...,N 对于z,其损失 ...

  8. 网络协议栈深入分析(三)--BSD socket和传输层sock

    Linux内核中协议族有INET协议族,UNIX协议族等,我们还是以INET协议族为例. 下面是内核中的协议族声明: [cpp] view plaincopy /* Supported address ...

  9. BP神经网络推导(两个隐藏层)

    typora-root-url: image BPBPBP神经网络 1.激活函数 ​ 激活函数(Activation Function)是在人工神经网络的神经元上运行的函数,负责将神经元的输入映射到输 ...

最新文章

  1. inum在linux中含义,linux
  2. Redis缓存使用技巧
  3. 解决Xamarin Android SDK Manager闪退问题
  4. postman使用介绍
  5. Windows7是什么
  6. 教表弟用Python写了个“飞机大战”游戏!表弟:可以拜你为师吗?
  7. Flink 助力美团数仓增量生产的应用实践
  8. 内存不足:杀死进程或牺牲孩子
  9. oracle 自动表分析,其实 Oracle 直方图自动统计算法存在这些缺陷!
  10. 都是执行软件测试,差异点在那里
  11. azure云数据库_如何将MySQL表迁移到Microsoft Azure SQL数据库
  12. 报错 The CUDA compiler identification is unknown;No CMAKE_CUDA_COMPILER could be found.
  13. C#抓取网页数据、分析并且去除HTML标签(转载)
  14. H3C交换机DHCP排查
  15. Spring Boot中mybatis:Field peopleInfoMapper in ‘**’that could not be found.
  16. onlyOffice常用api整理(1)
  17. iOS开发中的零碎知识点笔记 韩俊强的博客
  18. 物联网IoT应用技术有哪些?
  19. 华为eNSP基础命令
  20. 什么是Python之禅?

热门文章

  1. 解读青岛城市规划建设:5年内再添40座山头公园
  2. O32:头寸管理,我有话说
  3. ESLint+Prettier+Vetur 统一Vue项目代码风格
  4. 解决在VSCode上使用Vetur插件格式化Vue代码时,会出现单引号和结尾冒号问题
  5. Android Camera2教程之打开相机、开启预览、实现PreviewCallback、拍照
  6. pytorch版本RetinaFace人脸检测模型推理加速
  7. xcode 使用xparse,xccov解析xcresult文件,查看代码覆盖率,导出日志,提取附件等
  8. 2019计算机考研大纲考什么,2019计算机考研大纲解析
  9. 如何激发员工的积极主动性
  10. java根据距离计算经纬度_Java根据两点的经纬度来计算之间的距离