查看: 1720|回复: 0
打印 上一主题 下一主题

TinyOS学习笔记10-节点与计算机利用串口通信1

[复制链接]
跳转到指定楼层
沙发
发表于 2015-3-25 17:10:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
节点与计算机利用串口通信1

节点与计算机的通信是通过support/sdk/java和support/sdk/c,可以利用java代码或者C代码来实现串口的通信。根据turtorial中的内容,主要介绍了java的应用,如果在以后遇到要使用C语言连接串口的话,到时再研究。
1.如何查看本机的串口,使用motelist命令,我的机器显示如下信息:

root@ubuntu:~# motelist
Reference  Device           Description
---------- ---------------- ---------------------------------------------
XBS518PB   /dev/ttyUSB0     XBOW Crossbow Telos Rev.B

java net.tinyos.tools.Listen -comm serial@/dev/ttyUSB0:telosb
本命令代表使用java命令来执行串口的监听,net.tinyos.tools.Listen为在support/sdk/java中的一个程序,-comm serial@/dev/ttyUSB0:telosb为程序需要使用的参数。由于连接每一个设备使用不同的波特率,其中telosb代表的就是115200。在后面我们将详细分析以下这个Listen的程序。

下面首先看一下TestSerial这个例子:
本程序为节点通过串口向计算机周期性的发送数据,并显示在计算机上。
本程序有如下文件,将进行详细的分析:

TestSerial.h文件:

#ifndef TEST_SERIAL_H
#define TEST_SERIAL_H

//定义数据包的格式
typedef nx_struct test_serial_msg {
  nx_uint16_t counter;  //计数   
} test_serial_msg_t;

enum {
  AM_TEST_SERIAL_MSG = 0x89,  //表明是AM测试串口数据。就是个标志
};

#endif


TestSerialC.nc文件,实现接口中的event,和基本的通信程序差不多,但接收的是计算机传来的数据

#include "Timer.h"
#include "TestSerial.h"

module TestSerialC {
  uses {
    interface SplitControl as Control;
    interface Leds;
    interface Boot;
    interface Receive;
    interface AMSend;
    interface Timer<TMilli> as MilliTimer;
    interface Packet;
  }
}
implementation {

  message_t packet;//数据包

  bool locked = FALSE;//节点是否忙,同busy
  uint16_t counter = 0;//数据包计数

  event void Boot.booted() {
    call Control.start(); //开始,向下找startDone
  }


  //时间每次启动调用的函数
  event void MilliTimer.fired() {
    counter++;   
    if (locked) {
      return;
    }
    else {
      //设置数据包
      test_serial_msg_t* rcm = (test_serial_msg_t*)call Packet.getPayload(&packet, sizeof(test_serial_msg_t));
      if (rcm == NULL) {return;}
      //所发的数据超界,返回-comm serial@/dev/ttyUSB0:telosb
      if (call Packet.maxPayloadLength() < sizeof(test_serial_msg_t)) {
    return;
      }

      rcm->counter = counter;
       //广播该计数数据,寻找sendDone
      if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(test_serial_msg_t)) == SUCCESS) {
    locked = TRUE;
      }
    }
  }

  //接收数据程序,接收到数据后三位设置led灯
  event message_t* Receive.receive(message_t* bufPtr,
                   void* payload, uint8_t len) {
    if (len != sizeof(test_serial_msg_t)) {return bufPtr;}
    else {
      test_serial_msg_t* rcm = (test_serial_msg_t*)payload;
      if (rcm->counter & 0x1) {
    call Leds.led0On();
      }
      else {
    call Leds.led0Off();
      }
      if (rcm->counter & 0x2) {
    call Leds.led1On();
      }
      else {
    call Leds.led1Off();
      }
      if (rcm->counter & 0x4) {
    call Leds.led2On();
      }
      else {
    call Leds.led2Off();
      }
      return bufPtr;
    }
  }

  event void AMSend.sendDone(message_t* bufPtr, error_t error) {
    if (&packet == bufPtr) {
      locked = FALSE;//发送成功,节点空闲
    }
  }

  event void Control.startDone(error_t err) {
    if (err == SUCCESS) {
      call MilliTimer.startPeriodic(1000);  //开始成功,调用时间函数,周期进行循环
    }
  }
  event void Control.stopDone(error_t err) {} //结束成功
}

该程序和收发程序一致,无需考虑于串口的通信,与串口的通信的代码是在java的代码中实现的。

TestSerialAppC.nc:该文件实现相应的连线,注意AM数据包的不同,为SerialActiveMessageC

#include "TestSerial.h"

configuration TestSerialAppC {}
implementation {
  components TestSerialC as App, LedsC, MainC;
  components SerialActiveMessageC as AM;
  components new TimerMilliC();

  App.Boot -> MainC.Boot;
  App.Control -> AM;
  App.Receive -> AM.Receive[AM_TEST_SERIAL_MSG];
  App.AMSend -> AM.AMSend[AM_TEST_SERIAL_MSG];
  App.Leds -> LedsC;
  App.MilliTimer -> TimerMilliC;
  App.Packet -> AM;
}

TestSerialMsg.java:该文件实现对接收到的数据包的解析,其继承的是net.tinyos.message.Message
本文件是有MIG自动生成的,不用编辑此文件,其自动生成的代码在makefile中,如下:

TestSerialMsg.java:
    mig java -target=null $(CFLAGS) -java-classname=TestSerialMsg TestSerial.h test_serial_msg -o $@
不做详细分析,在以后讲解makefile时在详细说明

TestSerial.java:实现对与串口的连接和显示数据
import java.io.IOException;

import net.tinyos.message.*;
import net.tinyos.packet.*;
import net.tinyos.util.*;

public class TestSerial implements MessageListener {

  private MoteIF moteIF;

  public TestSerial(MoteIF moteIF) {
    this.moteIF = moteIF;
    this.moteIF.registerListener(new TestSerialMsg(), this); //为节点添加监听事件
  }

  //发送数据包,由节点发给计算机
  public void sendPackets() {
    int counter = 0;
    TestSerialMsg payload = new TestSerialMsg();
   
    try {
      while (true) {
    System.out.println("Sending packet " + counter); //输出接收的数据包,接收数据包的个数
    payload.set_counter(counter);
    moteIF.send(0, payload);//计算机给节点发送数据
    counter++;
    try {Thread.sleep(1000);}
    catch (InterruptedException exception) {}
      }
    }
    catch (IOException exception) {
      System.err.println("Exception thrown when sending packets. Exiting.");
      System.err.println(exception);
    }
  }

  //接收节点向计算机发送的数据,MessageListener的实现
  public void messageReceived(int to, Message message) {
    TestSerialMsg msg = (TestSerialMsg)message;
    System.out.println("Received packet sequence number " + msg.get_counter());
  }

  private static void usage() {
    System.err.println("usage: TestSerial [-comm <source>]");
  }

  //调用程序,传入参数为-comm serial@/dev/ttyUSB0:telosb
  public static void main(String[] args) throws Exception {
    String source = null;
    if (args.length == 2) {
      if (!args[0].equals("-comm")) {
    usage();//提示信息
    System.exit(1);
      }
      source = args[1]; //参数serial@/dev/ttyUSB0:telosb
    }
    else if (args.length != 0) {
      usage();
      System.exit(1);
    }
   
    PhoenixSource phoenix;  //??????
   
    if (source == null) {
      phoenix = BuildSource.makePhoenix(PrintStreamMessenger.err);
    }
    else {
      phoenix = BuildSource.makePhoenix(source, PrintStreamMessenger.err);//连接串口
    }

    MoteIF mif = new MoteIF(phoenix);//设置节点
    TestSerial serial = new TestSerial(mif);
    serial.sendPackets();
  }


}

运行时,先用命令make telosb将java代码编译,才可以使用 java TestSerial -comm serial@/dev/ttyUSB2:telosb
经过测试显示的数据为:
Sending packet 0
Received packet sequence number 47
Sending packet 1
Received packet sequence number 48
Sending packet 2
Received packet sequence number 49

当用Ctrl+z停止时,节点不再闪烁,接收不到java程序传来的数据。利用SerialActiveMessage实现了节点与计算机的双向通信。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

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