一、串口概述
略
二、源代码
TestSerial.h
#ifndef TEST_SERIAL_H
#define TEST_SERIAL_H
//这里自定义了一个结构体,作为发送我们需要发送的数据报
//结构体很简单,就是一个 特殊变量的 counter计数器
typedef nx_struct test_serial_msg {
nx_uint16_t counter;
} test_serial_msg_t;
//下面这个枚举类型表示我们的串口标志位
enum {
AM_TEST_SERIAL_MSG = 0x89,
};
#endif
TestSerialAppC.nc
#include "TestSerial.h"
configuration TestSerialAppC {}
implementation {
//main
components TestSerialC as App, MainC;
App.Boot -> MainC.Boot;
//led
components LedsC;
App.Leds -> LedsC;
//serial
components SerialActiveMessageC as AM;
App.Control -> AM;
App.Receive -> AM.Receive[AM_TEST_SERIAL_MSG];//接收数据的通道号,在.h文件中列举的枚举变量
App.AMSend -> AM.AMSend[AM_TEST_SERIAL_MSG];//发送数据的通道号,在.h文件中列举的枚举变量
App.Packet -> AM;
//timer
components new TimerMilliC();
App.MilliTimer -> TimerMilliC;
}
TestSerialC.nc
#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;
uint16_t counter = 0;
//主要流程如下:
//1 开启主程序,开启串口
//2 串口开启成功,开启定时器,以1s作为周期
//3 定时器开启后,每秒 设置有效负载的值 为 counter
// 3.1 发送数据包
// 3.2 发送成功,上锁
//4 发送完成后触发 sendDone 事件,
// 4.1 判断发送完毕的包是否是我们想要发送的包
event void Boot.booted() {
call Control.start();//开启串口,对应事件为StartDone
}
event void MilliTimer.fired() {
counter++;
//如果没有锁定就,往下执行读取包数的程序
if (locked) {
return;
}
else {
//getPayload 会返回一个有效负载区域的指针
test_serial_msg_t* rcm = (test_serial_msg_t*)call Packet.getPayload(&packet, sizeof(test_serial_msg_t));
if (rcm == NULL) {return;}
if (call Packet.maxPayloadLength() < sizeof(test_serial_msg_t)) {
return;
}
rcm->counter = counter;
//AM_BROADCAST_ADDR 表示0xffff,表示广播之意,只是在串口通信中不作任何意义。
if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(test_serial_msg_t)) == SUCCESS) {
locked = TRUE;
}
}
}
//收报的事件,
//首先判断长度是否是两个字节,然后再根据字节开关灯
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) {}
}
Makefile
COMPONENT=TestSerialAppC
include $(MAKERULES)
三、现象数据分析
使用Listen来监听接收的数据。
00 FF FF 00 00 02 00 89 00 03
-
第一个字节表示AM地址, 默认为00
-
第二个、第三个字节是接收者地址
FFFF表示广播,但是再串口通信中无意义。
-
第四、第五个字节是发送者地址
0000表示0号节点发送数据 -
第六个字节是有效负载的长度
02表示长度位两个字节,
-
第七个字节是网络组号,
-
第八位是自定义的通道号
-
最后的即为我们的有效数据
信息报样例
四、举一反三。
修改代码
typedef nx_struct test_serial_msg {
nx_uint16_t counter;
nx_uint16_t id;
} test_serial_msg_t;
event void MilliTimer.fired() {
counter++;
//如果没有锁定就,往下执行读取包数的程序
if (locked) {
return;
}
else {
//getPayload 会返回一个有效负载区域的指针
test_serial_msg_t* rcm = (test_serial_msg_t*)call Packet.getPayload(&packet, sizeof(test_serial_msg_t));
if (rcm == NULL) {return;}
if (call Packet.maxPayloadLength() < sizeof(test_serial_msg_t)) {
return;
}
rcm->counter = counter;
rcm->id = TOS_NODE_ID;
//AM_BROADCAST_ADDR 表示0xffff,表示广播之意,只是在串口通信中不作任何意义。
if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(test_serial_msg_t)) == SUCCESS) {
locked = TRUE;
}
}
}
把节点ID打印出来