原创 cc2530 web控制参考实现

2014-11-25 14:24 1812 10 11 分类: MCU/ 嵌入式 文集: 导学

 

cc2530 web控制参考实现

参考代码见附件。

安装步骤:

将basic\CC2530\WebMcuTempTerminal烧写到CC2530终端模块;

将basic\CC2530\SimpleLibApps\WebMcuGateway烧写到CC2530网关模块;

将网关模块与PC之间用usb转串口线连接(安装usb转串口驱动);

运行串口调试助手,设置波特率115200。16进制显示,应能每5秒收到一条消息。16进制发送数据:7e7e0401010202,应能看到终端模块的LED0闪烁。

(消息数据说明:7e7e为分组开始标识,04是后续字节数目,0101是目标终端节点地址(在终端代码中定义),02是消息类型,02是LED状态(toggle))

在PC上安装JDK和Tomcat。

按照basic\PC_WebMcuV2\deploy\Readme.txt配置。

启动Tomcat,在浏览器中访问服务器的webmcucomm目录。

尝试在节点ID栏输入0101,在消息栏输入0202或者0201或者0200,点发送。

观察日志框是否有显示收到的消息。

多烧写一个终端节点,注意要更改其ID(地址),看工作是否正常。

 

 


终端代码说明

工程:basic\CC2530\WebMcuTempTerminal\IAR_files

注:该工程链接ZH_SimpleStack_2530.r51库,该库的库函数源代码请参考点对点通信函数的使用

上行功能:

通过modTimerAddTimeoutCallback()增加一个定时任务,timeout时设置标志mBroadcastTimeoutFlag,通知主循环调用sendMsg()发送消息。

sendMsg()函数调用modAdcSampleSingle()采集温度数据和电压数据,放置在消息的第2个字节和第3个字节(7bit有效数据)。消息的第1个字节是自定义的消息类型,这里是0x02。注意:这个消息的结构和内容格式都是由设计者自行定义的,与PC中的消息解析代码一致即可。

 

下行功能:

在RF接收回调函数中,将收到的消息和RSSI复制到缓冲区,并设置标志mRfRxPktSize。

在主循环中,判断若下行消息类型是LED控制消息(mRfRxBuffer[0] == 0x01)则根据mRfRxBuffer[1]值设置LED0状态。注:该消息的结构和内容格式都是由设计者自行定义的,与PC中的消息解析代码一致即可。


网关模块代码说明:

工程:basic\CC2530\SimpleLibApps\WebMcuGateway\IAR_files

上行功能:

在RF的接收回调函数myRxCallback中,将消息来自的节点地址、收到的消息内容、RSSI保存到缓冲区,设置标志mRfRxPktSize提示主循环。主循环将消息通过串口发送(modUartSendPkt)。注意:消息的结构和内容格式都是由设计者自行定义的,与PC中的消息解析代码一致即可。

下行功能:

在串口的接收回调函数中,将整个消息复制到缓冲区,设置标志mUartRxPktSize提示主循环。主循环根据消息的前2个字节确定接收节点地址,将后续的消息内容发送(modRfSendPkt)。注意:消息的结构和内容格式都是由设计者自行定义的,与PC中的消息解析代码一致即可。


PC代码说明:

基于Windows XP+Tomcat,采用Java+JSP+html+javascript实现。参考实现代码可以分为3个层面:

* 底层是串口通信的Java接口类,使用SUN公司提供的串口库,根据自定义的串口分组结构将字节流转换为分组;

* 中间是JSP,将xml/html请求数据与底层的函数调用联系起来;

* 上层是界面,用html和javascript编写,实现界面展现和动态更新(AJAX,利用了JQuery);


具体地:

=====

底层代码(basic\PC_WebMcuV2\src\service)

使用的SUN串口库在lib_ext子目录:comm.jar

主要类:hzheng.serial.moduleinterface.CommBufferController

上层应用通过getController()方法获取该类的实例(singleton模式);

上层应用通过connect ( String vPortName, int vPortRate )方法建立串口连接,指定串口名字和波特率;

在connect()函数中:

通过SUN的CommPortIdentifier.getPortIdentifiers()获得电脑的所有COM口对象列表,与输入的名字匹配,获得指定的COM口对象(mPortId.open());

然后设置串口参数:mSerialPort.setSerialPortParams()

采用事件回调机制,设置事件回调接口:mSerialPort.addEventListener(this)

启动两个线程,一个用于读出(从串口接收,SerialReaderThread,mSerialPort.getInputStream),一个用于写入(向接口发送,SerialWriterThread,mSerialPort.getOutputStream())。

在事件回调函数serialEvent()中,当发送完成或者有收到数据时,分别调用SerialWriterThread或SerialReaderThread的notifyEvent()函数。

上层应用通过start()和stop()方法来启动或停止收发处理。

上层应用通过getMessage()方法来获取消息队列中最早的一条消息,消息以byte[]表示,当没有新消息时,返回null。

上层应用通过sendMsg(byte[] vMsgData)方法来发送消息。

消息发送过程:

* 上层应用调用CommBufferController.sendMsg(byte[] vMsgData);(由主线程运行)

* sendMsg()调用发送线程类mSerialWriter.sendMsg(vMsgData);(由主线程运行)

* mSerialWriter.sendMsg()将消息放入发送队列Vector mMessageList,调用mMessageList.notifyAll()发送信号释放run()函数中的阻塞;(由主线程运行)[]>

* 在run()函数中(由单独线程运行),从发送队列取出一条消息,如果消息长度超过串口分组的最大长度(这里规定为100字节),则拆分为多个分组发送。在分组发送函数writePkt()中,增加分组header(开始标志和长度),然后写入SUN串口类的OutputStream中。

* 在run()函数中,每发送完一个分组,要等待发送完成事件(mWaitObject.wait())再发送下一个分组;该事件由SUN控件发起(mSerialPort.notifyOnOutputEmpty(true);serialEvent(): mSerialWriter.notifyEvent(); mWaitObject.notifyAll();)。

 

消息接收过程:

* 在SerialReaderThread.run()中,等待新数据到达事件:mWaitObject.wait();;

* 读入数据:while (mInputStream.available() > 0), numBytes = mInputStream.read(readBuffer);;

* 处理数据:handleNewByte();

mInputStream.read()不保证一次把一个分组的数据都读进来,有可能分成几段。

在handleNewByte()中,完成分组定界、接收完整分组数据、调用上层分组接收函数(mListener.handleData())的功能。

* mListener就是CommBufferController,其handleData()函数将分组加入接收消息队列mMessageList;

* 当上层应用(JSP)调用getMessage()方法时,从队列mMessageList中取一个消息返回;

=====

JSP代码

目录:basic\PC_WebMcuV2\src\gui_v2。

发送:SendMessage.jsp

与上层应用的接口为两个参数:msg和node,16进制数据字符串。(比如例子中的终端节点ID为0x101,令led状态反转的命令为0x0202,则msg="0202",node=“0101”)

先取出两个参数:

  String sMsg = request.getParameter("msg");
  String sNodeId = request.getParameter("node");
转换为字节数组:

  byte[] pMsgBytes = BytesToHex.hexStringToBytes(sMsg);
  byte[] pNodeIdBytes = BytesToHex.hexStringToBytes(sNodeId);
合成为一个消息数组:

  //combine nodeid and msg
  byte[] pPkt = new byte[pMsgBytes.length+2];
  pPkt[0]=pNodeIdBytes[0];
  pPkt[1]=pNodeIdBytes[1];
  for (int i=0;i     pPkt[i+2]=pMsgBytes;
  }

获取CommBufferController实例,启动:;i++)>

    CommBufferController pController = CommBufferController.getController();
    //change parameter according to environment
    pController.connect("COM4", 115200);   //:根据实际COM口修改
    pController.start();
发送消息:

pController.sendMsg(pPkt);

生成发送结果的xml文档:(result-status)

out.println()

 

接收:GetMessages.jsp

获取CommBufferController实例,启动:
    CommBufferController pController = CommBufferController.getController();
    //change parameter according to environment
    pController.connect("COM4", 115200);   //:根据实际COM口修改
    pController.start();

取消息直到返回为空:

byte[] pMsg=pController.getMessage();

将消息内容转换为字符串,生成xml文本:

      String pTerminalId = BytesToHex.byteToHexString(pMsg[0])+BytesToHex.byteToHexString(pMsg[1]);
      out.println("");
      out.println(""+BytesToHex.bytesToHexString(pMsg)+ "");
      out.println("");

返回xml文档。(result-msg-rawbytes)

 

=====

界面代码

目录:web\basic\PC_WebMcuV2\src\gui_v2

文件:index.html

这里只做了一个最简单的界面:

一个输入框输入终端节点ID(16进制字符串);(比如0101,注意前面那个0不能省)

一个输入消息(16进制字符串);(比如0202)

一个发送按钮;

一个收到的消息的显示框;

主要代码:

发送部分:

发送按钮调用sendMessage();

在sendMessage()中:

获取输入的节点ID和消息:

        var pMsg=document.getElementById("tx_msg").value;
        var pTermId=document.getElementById("tx_termid").value;

利用JQuery调用SendMessage.jsp,将pMsg和pTermId作为入参:

        $.post("SendMessage.jsp?msg="+pMsg+"&node="+pTermId,
         function(vRetData) {
           handleSendRet(vRetData);
         },  
         "xml"
        );

返回的xml文档交给handleSendRet()函数处理,将结果显示在日志区:

        var pStatus=vRetData.getElementsByTagName("status")[0].childNodes[0].nodeValue;
        addLog("send msg " + pStatus);
 

接收部分:

页面打开时,启动一个定时器:

在body标签中,onload="startTimer()",startTimer()调用pollMessage();

pollMessage()通过JQuery调用GetMessages.jsp并启动下一次定时:

        var pCurrTime = new Date().getTime();
        $.post("GetMessages.jsp?timestamp="+pCurrTime,
          function(vRetData) {
            handleMessage(vRetData);
            t=setTimeout('startTimer()',2000);
          },  
          "xml"
        );

调用handleMessage返回的xml文档在handleMessage()中处理,从xml文档中取出消息(DOM对象),将消息内容加入到日志区:

       var pMsgs=vRetData.getElementsByTagName("msg");
       //alert(pMsgs.length);
       if (pMsgs.length >0) {
         for (i=0;i            var pRawBytes = pMsgs.getElementsByTagName("rawbytes");
           var pTxt = pRawBytes[0].childNodes[0].nodeValue;
           addLog("receive msg: " + pTxt);
           $( "#msgrx" ).html( pTxt);
         }
       }
 

 

主索引

使用控件 控件设计
   
  附件
 zip.gifbasic.zip
  参考链接
 

 

文章评论1条评论)

登录后参与讨论

用户1824123 2015-1-1 23:57

很详细地讲解,学习了,给你点赞
相关推荐阅读
用户138786 2015-03-16 18:38
WIFI模块(HED10W07SN)应用设计入门
WIFI模块(HED10W07SN)应用设计入门 以下系列帖子记录我学习WIFI模块(HED10W07SN)的过程和心得,以及为学生设计的入门指引。 ...
用户138786 2015-03-16 18:37
HED10W07SN串口应用设计
串口通信应用设计 HED10W07SN模块有两个串口。厂家提供的参考实现中,串口0用于管理:AT指令、EM_WIFI程序下载、Boot Loader程序下载(...
用户138786 2015-03-16 16:42
HED10W07SN基本I/O设计
基本I/O设计 芯片中没有与其它外设功能复用的GPIO引脚只有3个:GPIO11、GPIO12、GPIO13。 底层提供...
用户138786 2015-03-16 16:40
WIFI模块HED10W07SN开发环境
开发环境 选择联盛德微电子的HED10W07SN模块入手进行学习是带点偶然的。 拿WIFI模块和CC2530结合做网关是很早就想做的事,但WIFI模...
用户138786 2014-11-27 19:29
无线单片机入门导学(基于CC2530)
无线单片机(WSN/Zigbee)应用设计入门导学(基于CC2530) 我们学习无线单片机编程/应用设计是为了什么呢? 1、设计有用的应用...
用户138786 2014-11-27 19:24
web方式远程控制
web方式远程控制应用设计 这一类应用的特点是客户端通过浏览器(http协议)方式对无线单片机进行远程控制及数据采集。 ...
我要评论
1
10
关闭 站长推荐上一条 /2 下一条