查看: 118084|回复: 126

“飞比”Zigbee论坛CC2530开发板学习教程(四)-- 串口通讯之SerialApp

[复制链接]
outman 发表于 2010-8-24 21:46:59 | 显示全部楼层 |阅读模式
RS232,也称标准串口,是目前最常用的一种串行通讯接口,因其成本低廉,应用广泛而被很多嵌入式系统所采用。在CC2530开发板上,由于LCD、LED等基本外接显示信息量有限,同时串口也方便了与其他系统进行通讯,所以它无疑成为了开发者最重要的一个调试手段。

  本章的重点,就是以Zstack 2007中提供的例程--SerialApp为基础,对CC2530的串口部分进行详细的介绍。

  [注:本文源自www.feibit.com--“飞比”Zigbee论坛,为尊重劳动者成果,如需转载请保留此行,并通知作者]

  例3.基于Zstack 2007的串口通讯
  在之前的“奥特曼Zigbee读书日记(三)和(四)”中,其实已经利用TI提供的基本库,从零开始,一步步地搭建了一个“老王”和“老张”打招呼的例程,但是由于他们俩说的所有话都是程序规定的,所以他们只能简单地说两句话“吃了吗”和“吃了”,然后不停地重复,我们中国人自然没有这么呆啦~~在本实验中,看看中国小伙是如何“远程”泡美国MM的~~~

  在这个场景中,“中国小伙”通过QQ,向美国MM申请加为好友(申请绑定),在美国MM验证后(绑定成功)后,双方你一句我一句地就聊起来了(串口终端1<==>Zigbee节点1 <==>Zigbee节点2 <==>串口终端2)。如下图(1)所示:


                                    图(1)

  注:“日记”中的例程的串口通讯部分其实是抛开Zstack的串口程序而重新写的,但实际上Zstack已经做过这部分工作了,在本例程中,我们不对ZStack做任何修改,只是分析下其程序功能与原理。读者可以在安装ZStack-CC2530-2.3.0-1.4.0后,在C:\Texas Instruments\ZStack-CC2530-2.3.0-1.4.0\Projects\zstack\Utilities\SerialApp\CC2530DB目录下,打开SerialApp这个工程进行实验。

  [一]程序功能
  实现两个节点之间的绑定与通讯,同时每个节点可与其“上位机”--所边接的PC串口终端,进行通讯。示意如下:


                                    图(2)

  [二]操作说明
  分别将Coordinator与EndDevice程序编译、下载至两套开发板后,按Reset键后,屏幕显示如下:

     (图3)      


     (图4)

  如果显示信息如上图所示,则表示网络初始化成功。

  此时,按下任意一个节点的摇杆(Joystick)右键进行绑定申请,然后立即按下另外一个节点的Joystick右键进行绑定确认。此时,两个节点的红色LED灯--LED1,同时点亮,表示绑定成功,可以开始通信。

  打开串口调试助手(注:可以在一台电脑上打开两个,或者在两台电脑上分别打开),分别对两个节点的串口进行设置,具体设置请参见图(1)中左边的设置,其中:串口的名称请在“设备管理器”中查找,波特率设为38400。

  至此,准备工作已经做好。然后在任何一个串口终端上发送数据,此时另外一个终端即可接收此数据,即完成了一个(串口终端1==>Zigbee节点1 ==>Zigbee节点2 ==>串口终端2)的数据传输过程。

  另外,在整个过程中,异常情况的LED显示:
  1. LED1闪烁,表示在规定的绑定申请时间内,无设备对其进行绑定确认
  2. LED3闪烁,表示连接节点丢失,如对方节点产生掉电等异常情况
  
  [三]系统解析
  本例程采用的是OSAL的系统,其原理读者可参考如下几篇文章,如有疑问请跟贴进行讨论:
  1. 奥特曼Zigbee读书日记(二)--OSAL系统框架专题(作者:outman)
  2. 深入浅出Z-Stack 2006 OSAL多任务资源分配机制(作者:cyril3 )
  3. 我心目中的Zstack OSAL & Message(作者:ssls18years )
  
  在此不做赘述,仅对此例程中的按键处理过程进行简单的讲解:
  1. 申请绑定与绑定确认
  首先,由某节点触发Joystick右键,即HAL_KEY_SW_2,对如何通过查询电平、确认按键事件,并调用相应的按键处理函数的过程有疑问的读者请参见上述文章。在按键处理函数--SerialApp_HandleKeys中,

    if ( keys & HAL_KEY_SW_2 )
    {
      HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF );
     
      // Initiate an End Device Bind Request for the mandatory endpoint
      txAddr.addrMode = Addr16Bit;
      txAddr.addr.shortAddr = 0x0000; // Coordinator
      ZDP_EndDeviceBindReq( &txAddr, NLME_GetShortAddr(),
                            SerialApp_epDesc.endPoint,
                            SERIALAPP_PROFID,
                            SERIALAPP_MAX_CLUSTERS, (cId_t *)SerialApp_ClusterList,
                            SERIALAPP_MAX_CLUSTERS, (cId_t *)SerialApp_ClusterList,
                            FALSE );
    }
  此处发起绑定请求,等待其他节点应答,而如果有一个节点也按了Joystick右键,同样发出了绑定请求,则本节点收到一个End_Device_Bind_rsp的信息,并在SerialApp_ProcessZDOMsgs函数中进行了处理,如下代码:

/*********************************************************************
* @fn      SerialApp_ProcessZDOMsgs()
*
* @brief   Process response messages
*
* @param   none
*
* @return  none
*/
static void SerialApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )
{
  switch ( inMsg->clusterID )
  {
    case End_Device_Bind_rsp:
      if ( ZDO_ParseBindRsp( inMsg ) == ZSuccess )
      {
        // Light LED
        HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
      }

      break;
...
  }
}
  至此,中国小伙已经成功加美国MM为好友了~

  接下来的事,大家想必都知道了。。。
  看看他们是怎么发送信息,怎么接收信息的吧?
  1. “串口终端1”的数据,如何被“节点1”所接收,并且发送出去的?

  串口数据是由哪层来负责的呢?--HAL。。。恩,猜对了。但这个肯定不是靠猜的,其中的过程就不讲了。让我们从主循环(osal_start_system)的Hal_ProcessPoll函数找下去(用source insight的同学可以用ctrl +),Hal_ProcessPoll ==> HalUARTPoll ==> HalUARTPollDMA

  这个HalUARTPollDMA函数里最后有这样一句话:dmaCfg.uartCB(HAL_UART_DMA-1, evt); 对dmaCfg.uartCB这个函数进行了调用,ctrl / 搜索这个dmaCfg.uartCB,发现SerialApp_Init函数有两句话:

   uartConfig.callBackFunc         = SerialApp_CallBack;
    HalUARTOpen (SERIAL_APP_PORT, &uartConfig);

  此处将dmaCfg.uartCB这个函数注册成为SerialApp_CallBack,也就是说SerialApp_CallBack函数每次循环中被调用一次,对串口的内容进行查询,如果DMA中接收到了数据,则调用HalUARTRead,将DMA数据读至数据buffer并通过AF_DataRequest函数发送出去,注意:送出去的信息的CLUSTERID(信息簇ID)号为SERIALAPP_CLUSTERID1。

  总结一下这个过程:串口数据==>DMA接收==>主循环中通过SerialApp_CallBack查询==>从DMA获取并发送到空中。

  2. 节点2在收到空中的信号后,如何传递给与其相连的串口终端?
  节点2从空中捕获到信号后,在应用层上首先收到信息的就是SerialApp_ProcessEvent这个函数了,它收到一个AF_INCOMING_MSG_CMD的事件,并通知SerialApp_ProcessMSGCmd,执行以下代码

  switch ( pkt->clusterId )
  {
  // A message with a serial data block to be transmitted on the serial port.
  case SERIALAPP_CLUSTERID1:
... ...
      // Transmit the data on the serial port.
      if ( HalUARTWrite( SERIAL_APP_PORT, pkt->cmd.Data+1, (pkt->cmd.DataLength-1) ) )
      {
        // Save for next incoming message
        SerialApp_RxSeq = seqnb;
        stat = OTA_SUCCESS;
      }

... ...

  这样就将从空中获取到的信息,传给了串口终端2--美国MM,第一句话终于传到美国了~至于后面的事情嘛,我们就不关注了,看小伙自己的造化了~~~

  另外,此例程中还有一种模式,就是这个中国小伙可以按条件搜索(Joystick左键,profileID与clusterID相同者响应),但这种条件找出的MM都比较有个性--只接受你的信息,但不给你发。想想也是,明显没诚意嘛~ 这种模式的细节,本教程不再涉及,有兴趣的读者可自行了解。

  声明一点,要真想泡美国MM,只用我们所谈的Zigbee是暂时搞不定的,它最大的传输距离能有几公里就相当不易了,不过隔壁办公室的MM,倒是可以考虑送她一个~~~

  [四]网络结构及协议解析
  本例程的重点是串口的应用,其中涉及的组网及绑定等网络层细节,暂不详细阐述,将在后续的“奥特曼Zigbee读书日记”中进行深入分析。

  [五]扩展思考
  1. DMA方式与ISR方式的UART传输,有什么区别?分别如何实现?
  2. ZDO_CB_MSG与AF_INCOMING_MSG_CMD等事件的产生机制?
  3. 如何完成“多对一”或者“一对多”的通信?
  4. 绑定表的存储位置与生命周期?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
xingqing 发表于 2010-8-25 11:14:15 | 显示全部楼层
呵呵  期待中。。。。。
leewei 发表于 2010-8-26 10:57:54 | 显示全部楼层
拜读又一大作
 楼主| outman 发表于 2010-8-26 14:19:59 | 显示全部楼层
终于写完了,沙发已经被人坐了,自己弄个小板凳先坐着看看~
hiber2010 发表于 2010-8-26 15:11:56 | 显示全部楼层
楼主辛苦了,期待新作
teny 发表于 2010-9-9 17:29:41 | 显示全部楼层
写得很不错,逻辑性好,易懂
P.langevin 发表于 2010-9-9 22:23:42 | 显示全部楼层
膜拜楼主一个~~~~~
lxp198205 发表于 2010-9-25 12:03:42 | 显示全部楼层
uartConfig.flowControl 此处配置可要特别注意了,不然串口调试起来可就麻烦了。只有你置低P0.4才能通信。看到这忽然明白了,谢谢!
sendoc 发表于 2010-9-26 16:53:48 | 显示全部楼层
本帖最后由 sendoc 于 2010-9-26 21:48 编辑

回复 10# lxp198205

    uartConfig.flowControl          = FALSE;//TRUE;我的这样配置是可以的。
问下
    bool     flowControl;//控制位,如果是1的话就说明是4线模式,0代表2线模式,默认的是4线模式
4线、2线什么意思?
sendoc 发表于 2010-9-27 19:59:41 | 显示全部楼层
本帖最后由 sendoc 于 2010-9-27 20:09 编辑

找到关于流控的定义如下:
流控是用来在两个数据传输速度不同的设备中控制数据流量的技术(如一个点阵串口打印机和一个RS-232界面连接)。
流控的数据流控控制功能确保2台设备相互通讯,数据避免丢失。
RS-232通讯使用两种基本方式来进行流控:
软件方法:XON/XOFF XON(0x11)和XOFF(0x13)定义为通讯过程中使用的特殊控制字符。
这2个字符通过字符的方式传送,其操作简单易懂。
硬件方法:RTS/CTS RTS和CTS是两个单独的信号,通过不同的信号线来发送用作硬件流控。
RTS是输出信号,它表示能将数据传送至其他设备。CTS是输入信号,允许其他设备可否进行数据传输。
这种方法的缺点就是需要至少两根线,并能发送二进位数据。

根据上文可作如下推测:
uartConfig.flowControl          = FALSE;//TRUE;
PC机串口设置硬件流控=TRUE;否则FALSE。
这里 flowControl=1,采用4线; flowControl=0,采用2线。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表