实验日期:2012年12月13日
实验内容:上位机通过串口将数据发送到节点,节点将接收到的数据反馈给上位机
实验环境:基于Linux下的TinyOS Telosb节点
接收到PC发出的数据后,通过定时器的方式反馈收到的数据,同时LED0闪烁。
新添加TimerMilliC组件和SerialAMsender组件。SerialAMsender组件主要完成反馈数据至串口。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiATO2YiN0MWN5EWMxYDNidDM3U2YwEWZ4gzLcBTO2cXbvwlbj5yZtlWYul2cuczcvw1LcpDc0RHaiojIsJye.jpg)
(1)发送数据方法
发送数据的思路比较简单,可以简单概况为:打包à发送
具体地,步骤如下:
a)定义message_t变量,如message_t ToUartMsg;
b)定义有效数据数据段(即载荷区),如
typedef nx_struct ReturnMsg
{
nx_uint16_t testnum;
}ReturnMsg;//定义结构体,其中testnum是有效数据段中占两个字节的数据
c)定义指向payload段指针(关键)
通过Packet接口调用getpayload函数获取payload段地址,需要message消息(即message_t)变量的地址和有效数据段字节长度两个参数,如:
ReturnMsg *btrpkt=(ReturnMsg *)(call UartPacket.getPayload(&ToUartMsg,sizeof(ReturnMsg)));//UartPacket为Packet接口
d)装载载荷区
给有效数据段对应的结构体中的变量赋值,如:
btrpkt->testnum=temp16;//temp16是uint16_t类型数据
e)发送数据
调用AMSend接口中send函数即可将数据发送到串口,如:
call UartSend.send(0xff,&ToUartMsg,sizeof(ReturnMsg);//由于是发送到串口,故第一个AM地址参数可忽略(任意)。
f)相应发送数据完毕的函数(sendDone函数)
event void UatSend.sendDone(message_t *msg,error_t error)
【测试】
1.向串口写入数据:java net.tinyos.tools.Send 00 ff ff 00 09 00 89 07 01 03
LED0灯没有马上点亮,而是隔3秒中左右开始闪烁
2、侦听串口:java net.tinyos.tools.Listen –comm [email protected]/dev/ttyUSB0:telos
Linux终端反馈数据:00 00 FF 00 00 02 00 06 01 03
Xgcom软件反馈数据:
1)无校验:7E 45 00 00 FF00 00 02 00 06 01 03 E5 AC 7E
2)奇校验:7E 45 80 00 FF00 00 02 00 06 01 03 E5 AC BF
3)偶检验:7E 45 80 00 FF 00 00 02 00 06 01 03 E5 AC BF
3、串口数据包格式分析:
在TinyOS 2.x的串口协议栈里,各协议字段分别和特定的组件有关,其具体格式如下图所示:
F | P | S | D | Payload | CR | F |
串口协议包的格式
F:帧字节,表示数据包开始,与HdlcTranslateC组件有关
P:协议字节,与SerialP组件有关
S:序号字节,与SerialP组件有关
D:包格式的分派字节,与SerialDispatcherC组件有关
Payload:数据包的有效载荷区,与SerialDispatcherC组件有关
CR:两个字节的CRC校验码,校验从S到Payload,与SerialP组件有关
F:帧字节,表示数据包接收,与HdlcTranslate组件有关
注意:这里的Payload不是AM消息里的Payload,二是串口协议包中的Payload。
有效载荷区是SerialDispatcherC组件读入的连续数据包,包含串口主动消息的包头。需要注意的是,从P到CR的任何字节如果等于0x7e或0x7d,将会相应的被转换为0x7d 0x5e与0x7d 0x5e
7E 4500 00FF 00 00 02 00 06 01 03E5 AC 7E
F |P | S | D| Payload | CR |F
【完整代码】
PC2NodeC.nc文件:
module PC2NodeC
{
uses interface SplitControl as SerialControl;
uses interface Packet as UartPacket;
uses interface AMSend as UartSend;
uses interface Receive as UartReceive[am_id_t id];
uses interface Leds;
uses interface Boot;
uses interface Timer<TMilli> as Timer0;
}
implementation
{
typedef nx_struct RealMsg
{
nx_uint16_t LedCount;
}RealMsg;
message_t ToUartMsg;
typedef nx_struct ReturnMsg
{
nx_uint16_t testnum;
}ReturnMsg;
uint16_t temp16;
event void Boot.booted()
{
uint8_t i;
call SerialControl.start();//启动
}
event void SerialControl.startDone(error_t error)
{
}
event void SerialControl.stopDone(error_t error){}
//接收到从PC发过来的数据
event message_t *UartReceive.receive[am_id_t id](message_t *msg,void *payload,uint8_t len)
{
if(len==sizeof(RealMsg))
{
RealMsg *btrpkt=(RealMsg*)payload;
temp16=btrpkt->LedCount;
call Timer0.startPeriodic(1000);
}
return msg;
}
event void Timer0.fired()
{
ReturnMsg *btrpkt2=(ReturnMsg*)(call UartPacket.getPayload(&ToUartMsg,sizeof(ReturnMsg)));
btrpkt2 -> testnum = temp16;
if(call UartSend.send(0xff,&ToUartMsg,sizeof(ReturnMsg))==SUCCESS)
{
call Leds.led0Toggle();
}
}
event void UartSend.sendDone(message_t *msg, error_t error) {}
}
PC2NodeAppC.nc文件
configuration PC2NodeAppC
{
}
implementation
{
//components
components PC2NodeC,MainC,LedsC;
components SerialActiveMessageC as SeriAcMsg;
components new SerialAMSenderC(6);
components new TimerMilliC() as T0;
//Links
PC2NodeC -> SeriAcMsg.Packet;
PC2NodeC.UartSend -> SerialAMSenderC.AMSend;
PC2NodeC -> SeriAcMsg.Receive;
PC2NodeC -> MainC.Boot;
PC2NodeC.SerialControl -> SeriAcMsg;//有疑问???因为SerialControl 是由PC2NodeC提供的
PC2NodeC -> LedsC.Leds;
PC2NodeC.Timer0 -> T0;
}