目录
如果大家对节点与节点之间无线通信的底层逻辑与原理有需求的话,可以看看笔者的这篇文章,相信能然让你更好的理解无线通信的实现(因为合在一起太长了,所以分成两篇,也更有目的性一些😁😁):节点与节点之间的无线通信的组成原理与具体实现(原理篇,含组件解析)_物联网挑战赛_勾栏听曲_0的博客-CSDN博客
TinyOS下的CC2420编程
RadioCountToLedsC组件图如下图所示,我们可以看到要实现RadioCountToLedsC相关功能,需要使用到MainC,AMReceiverC,AMSenderC,ActiveMessageC,LedsC,TimerMilliC组件,虚线框表明该组件使用的是虚拟资源。
编程语言介绍
本次实验所用的编程语言为nesC,在本篇里笔者就不过多赘述啦,感兴趣的小伙伴可以去这篇里面看看哦。CTP协议的组成原理与具体实现(实验篇,含代码)_物联网竞赛挑战赛_勾栏听曲_0的博客-CSDN博客
代码实现
我们直接进入正题,看代码来理解节点与节点之间无线通信的具体实现。
一下代码的效果是,通过无线通信完成每个节点LED灯都按同一种频率闪烁。
Makefile
Makefile文件,就是定义代码的书写规则
CFLAGS += -DCC2420_DEF_CHANNEL=14, 这句话是非常重要的,是无线通信里的频段设置
COMPONENT=RadioCountToLedsAppC
CFLAGS += -DCC2420_DEF_CHANNEL=14
CFLAGS += -I$(TOSDIR)/lib/printf
include $(MAKERULES)
RadioCountToLeds.h
#ifndef RADIO_COUNT_TO_LEDS_H
#define RADIO_COUNT_TO_LEDS_H
typedef nx_struct radio_count_msg {
nx_uint16_t counter; //计时元素
} radio_count_msg_t;
enum {
AM_RADIO_COUNT_MSG = 6,
};
#endif
RadioCountToLedsAppC.nc
implementation函数里,就是 .C 文件里要用到的一直组件的声明和连接。每个模块我都分开放置并添加了注释。
#include "RadioCountToLeds.h"
#include "printf.h"
configuration RadioCountToLedsAppC {}
implementation {
//main,leds
components MainC, RadioCountToLedsC as App, LedsC;
App.Leds -> LedsC;
App.Boot -> MainC.Boot;
//radio
components new AMSenderC(AM_RADIO_COUNT_MSG);
components new AMReceiverC(AM_RADIO_COUNT_MSG);
components ActiveMessageC;
App.Receive -> AMReceiverC;
App.AMSend -> AMSenderC;
App.AMControl -> ActiveMessageC;
App.Packet -> AMSenderC;
//timer
components new TimerMilliC();
App.MilliTimer -> TimerMilliC;
//print
components PrintfC;
components SerialStartC;
}
RadioCountToLedsC.nc
头文件
#include "Timer.h"
#include "RadioCountToLeds.h"
#include "printf.h"
implementation
模块的声明,这里对应的是TestNetworkAppC.nc里的implementation这个函数
module RadioCountToLedsC @safe() {
uses {
interface Leds;
interface Boot;
interface Receive;
interface AMSend;
interface Timer<TMilli> as MilliTimer;
interface SplitControl as AMControl;
interface Packet;
}
}
implementation
接下来implementation函数里的代码解释,笔者都写在代码注释里啦,代码不算很长,也还是很好理解的啦,大家耐心看吧~😁😁
implementation {
message_t packet; //定义一个在RadioCountToLeds.h里定义的一个结构体的包
bool locked; //锁机制,默认false
uint16_t counter = 0;
event void Boot.booted() {
call AMControl.start(); //打开无线通信
}
event void AMControl.startDone(error_t err) {
if (err == SUCCESS) { //如果无线通信打开成功
call MilliTimer.startPeriodic(1000); //打开1000毫秒定时器,1000毫秒后,执行event void MilliTimer.fired()
}
else {
call AMControl.start(); //打开失败,则重复打开
}
}
event void AMControl.stopDone(error_t err) { //对应call AMControl.start()
// do nothing
}
event void MilliTimer.fired() {
counter++; //记秒数
if (locked) { //锁机制的实现AMSend.sendDone判断发包正确后,会解除锁机制
return;
}
else {
radio_count_msg_t* rcm = (radio_count_msg_t*)call Packet.getPayload(&packet, sizeof(radio_count_msg_t)); //rcm指向packet的负载
if (rcm == NULL) {
return;
}
//如果负载不为空,就将counter的值赋值给rcm->counter
rcm->counter = counter;
//AM_BROADCAST_ADDR:无线通信中,代表广播
//如果改成 0x01,那就是向1号节点发送单播
if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(radio_count_msg_t)) == SUCCESS) { //无线发包
locked = TRUE; //打开锁机制 ,锁住后,转到senddone
}
}
}
event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len) { //节点接收数据,无线收包
if (len != sizeof(radio_count_msg_t)) {return bufPtr;} //判断是否是我想要的包
else { //如果是我想要的包
radio_count_msg_t* rcm = (radio_count_msg_t*)payload; //rcm指向包的负载
//如果rcm->counter == 1,那么 1 & 0x1 == 0x1,所以LED0会亮,以下同理
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;
}
}
}
如果有帮助的话,欢迎点赞收藏哦~🤩,有不同见解或更好的观点也可以在评论区留言,也可以笔者点点关注,互通有无,互相进步。