|
节点与计算机利用串口通信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实现了节点与计算机的双向通信。
|
|