起重机能耗监测的无线传感网络研制.docx

上传人:b****4 文档编号:5415332 上传时间:2022-12-16 格式:DOCX 页数:27 大小:1.19MB
下载 相关 举报
起重机能耗监测的无线传感网络研制.docx_第1页
第1页 / 共27页
起重机能耗监测的无线传感网络研制.docx_第2页
第2页 / 共27页
起重机能耗监测的无线传感网络研制.docx_第3页
第3页 / 共27页
起重机能耗监测的无线传感网络研制.docx_第4页
第4页 / 共27页
起重机能耗监测的无线传感网络研制.docx_第5页
第5页 / 共27页
点击查看更多>>
下载资源
资源描述

起重机能耗监测的无线传感网络研制.docx

《起重机能耗监测的无线传感网络研制.docx》由会员分享,可在线阅读,更多相关《起重机能耗监测的无线传感网络研制.docx(27页珍藏版)》请在冰豆网上搜索。

起重机能耗监测的无线传感网络研制.docx

起重机能耗监测的无线传感网络研制

第一章绪论

1.1无线传感网的发展现状

1.2起重机能耗监测的发展现状

1.3课题的选题意义

第二章系统网络节点的硬件设计

2.1起重机能耗感知系统总体设计

2.2采集节点硬件设计

2.2.1CC2530介绍以及节点整体框图

2.2.2电源以及抗干扰性设计

2.2.3加速度传感器(SPI)

2.2.4电压/电流传感器(AD)

讲实验室选择的,具体使用视吨位而定

2.2.5陀螺仪(IIC)

2.3中心汇聚节点硬件设计

485总线

第三章CONTIKI操作系统分析与移植

3.1contiki操作系统的分析

本论文将依托Contiki操作系统提供的6LowPAN协议栈来实现基本通信。

Contiki是一个开源的、移植性极强的、专为无线传感网络设计的多任务开源操作系统。

它拥有一个基于事件驱动的内核,支持protothread进程机制,所以相当实用于资源受限的传感器节点。

Contiki的精简配置只需要几KB的ROM和几百字节的RAM就能提供多任务环境。

uIP小于5KB,uIPv6大约只有11KB。

Contiki提供了丰富的功能模块,用户可以根据需要自行裁剪源码。

内核通过消息机制实现任务间的通信,提供shell模块可以实现动态的进程任务管理。

目前,contiki已经实现并提供了Rime协议栈、IPv4/IPv6协议栈、6LoPAN协议栈、coffee文件系统、shell脚本等。

本节通过对其内核分析,为今后的使用和下一节的移植工作做好理论准备。

3.1.1Protothread进程控制原理

Protothread是用C语言编写的轻量级线程库,所以可移植性行强。

由于其采用了无栈结构,故对内存要求极小。

是一种技巧性、适应性很强的操作系统。

Protothread[1-6]是结合了时间驱动和多线程模型两种优势的一种方法。

和多线程模型一样,使用Protothreads的程序是顺序结构,但是它使用的内存很少,这一优点又是和事件驱动模型一样的。

它的缺点是当时Prothreads阻塞时,必须在编程时显式的存储变量。

表1从六个方面比较了三种机制。

进程或者线程切换的时候,为了能够实现无缝重入,传统的操作系统(如ucos)都会使用栈来保存进程上下文,会在内存中为每个进程开辟一个栈空间,每个堆栈都会浪费几十个字节的空间。

这对于内存首先的传感器节点来说,是很难承受的。

而Protothread机制的所有进程都运行在同一个堆栈上。

每个任务仅仅用两个字节的全局变量来保存被阻塞时所处的行数,当词进程被再调度时,巧妙地通过switch(_LINE_)语句跳转到刚才的执行点,就可以恢复执行了。

Protothreadde源代码其实很简单,其核心代码只有5行,保存在lc-switch.h中。

1typedefunsignedshortlc_t;

2#defineLC_INIT(s)s=0;

3#defineLC_RESUME(S)switch(s){case0:

4#defineLC_SET(s)s=__LINE__;case__LINE__;

5#defineLC_END(s)}

以上几句代码,实现的行号的保存于switch语句的挑战,相当于Protothread机制的内核。

以上面五句代码为基础,通过宏定义的方式(节省空间)再构造出了四个编程中经常用到的调用函数。

解释如下:

PT_INIT是线程初始话宏,在线程开始运行之前,需要调用该宏初始化线程控制块,他直接调用LC_INIT宏。

其实也就是将线程控制块保存的行号初始化为0,这样使得线程从头开始执行

PT_BEGIN是LC_RESUME的封装,表示线程的开始,在线程中它必须放在最开始处,这是因为protothreads是通过一个switch结构实现多线程编程的,PT_BEGIN是该结构起始部分。

PT_WAIY_UNTIL是阻塞这个线程知道某个条件成立。

它先调用LC_SET宏设置一个断点,然后判断条件是否成立,如果不成立直接返回。

知道条件成立才继续运行。

PT_EDN先调用LC_END结束整个switch结构,然后调用LC_INIT重新初始化线程控制块,这样在下次运行时可以从头开始。

Contiki中最基本的编程模式

#include "contiki.h" 

PROCESS(name,strname)//定义进程

AUTOSTART_PROCESS(...)

/*Definetheprocesscode*/ 

PROCESS_THREAD(name,ev,data)//进程功能实现

    PROCESS_BEGIN(); 

    /***这里填入自定义的应用代码***/

    PROCESS_END(); 

}

声明变量最好不要放在PROCESS_BEGIN之前,因为进程再次被调度,总是从头开始执行,直到PROCESS_BEGIN宏中的switch判断才跳转到断点case__LINE__。

也就是说,进程被调度总是会执行PROCESS_BEGIN之前的代码。

表1事件驱动,多线程,Protothreads模型定性比较

性质

事件驱动

多线程

Protothread

内存需求

控制结构

调试栈

隐式锁

抢占式

自动变量

3.1.2Contiki中的主要数据结构

3.1.2.1进程链表

结构体process是contiki中控制进程的重要数据结构,每一个进程都会有有自己的进程结构体,又称进程控制块。

系统中所有的进程控制块会被以链表的形式组织起来。

如图1所示。

1.struct process

2.{

3.  struct process *next; 

4.  const char *name; 

5.  PT_THREAD((*thread)(struct pt *, process_event_t, process_data_t));  

6. struct ptpt;     

7.  unsigned char state;  

8.  unsigned char needspoll; 

9.};

Next:

用于指向下一个进程控制块。

Name:

设定该进程的名字。

Tread:

该函数指针指向了本进程真正的执行体。

PT:

保存进程被中断的行数,即保存上下文。

State:

用于标识进程的当前状态。

其值可能为PROCESS_STATE_RUNNG,PROCESS_STATE_CALLED,PROCESS_STATE_NONE。

图1进程控制链表

3.1.2.2Contiki中的事件

Contiki是以事件来调度任务的,每个事件都有自己的事件标志块,且以链表的形式组织起来。

系统会不断的检索事件环形队列,来响应已经产生的事件。

事件环形队列如图2所示。

1.struct event_data

2.{

3.  process_event_tev;

4.  process_data_tdata;

5.  struct process *p;

6.};

Ev:

标志所产生的事件编号。

Data:

保存事件产生时获得的相关信息,即事件产生后可以给进程传递的数据。

P:

指向监听该事件的进程,即该事件产生后会激励到的进程。

图2事件环形队列

3.1.3Contiki的系统时钟分析

Contiki系统中包含一个时间模型和一组定时器模块:

timer,stimer,etimer,rtimer.timer模块的基础是clock模块。

用于处理系统时间,也用来短时间阻塞CPU。

timer和stimer最简单,用于检查一个时间周期是否到期。

timer以系统时钟tick为单位,而stimer以秒为单位,适用于较长的定时周期。

与其他的时间模块不同的是,timer库和stimer库可在中断中安全使用,因此他们适用于底层驱动程序。

(1)timer:

以系统时钟tick计数,每次定时中断到达,count计数值加1。

通过计算count、start、interval之间的数量关系而产生相应的计时效果。

系统的etimer时间结构基于该结构进行操作。

(2)stimer:

计时机制是以timer为软件基础,但计时单位为秒,适用于较长的时间周期。

(3)etimer:

用来提供时间事件,让系统按预定的时间周期来触发进程。

当etimer时间到期,会给相应的进程传递PROCESS_EVENT_TIMER事件,从而使相应的监听进程得到运行。

该机制可以使进程在不必要运行时而进入等待状态,以便其他进程运行。

或让系统进入低功耗状态。

Contiki系统使用一个全局静态变量timerlist来保存各etimer,以链表形式组织。

etimer链表由系统进程etimer_process负责管理。

(4)ctimer:

用于提供回调定时器,用于调度一段时间后调用回调函数。

由于回调定时器在时间到期时会调用一个函数,这在没有明确Contiki进程的代码中特别有用,例如通信协议的实现。

(5)rtimer:

用于调度实时任务。

Rtimer的优先级高于Contiki中的所有其他进程,使实时性要求高的任务能够得到保障。

通常使用在底层的关键代码中,例如X-MAC的实现。

3.1.4Contiki中的网络协议栈

3.1.4.1uIP协议栈分析

uIP协议栈是一种保持代码大小和存储器使用量最小的免费的TCP/IP协议栈[2]。

保留了网络通信中必要的IP、ICMP、TCP、UDP协议的功能实现,而删掉了不常用的通信协议,协议具有很强的可裁剪性。

与uc/IP,lwip和uc/ip等协议栈相比,其最大优缺点就是系统资源占用量少。

uIP协议栈代码空间只需几千字节,而内存空间占有量小于2KB。

比起通过计算机现有的IP协议栈(通常需要几十万字节),对于8位或者16微处理机来说,使用uIP协议栈来实现以太网通信,是一个合适的选择。

可以通过配置选择IPV6或者IPV4.收发公用同一块缓存。

Ipv6的代码占用空间烧高于IPv4。

图列出了uIPv6的不同计算功能所用的代码占用空间和内存占用空间详情。

uIP协议栈的运行是非常简单的,他完成三件工作:

处理通信设备驱动器传送来的数据包;处理应用程序的命令,和完成一些周期性任务。

uIP转发模块将数据包转发的到哪里的方式是通过询问一个路由协议模块,从而实现与其他节点的中继通信。

如果通信设备驱动器收到了一个数据包,则开始输入处理。

驱动器会首先调用uIP输入处理函数,它能处理输入数据包的包头。

接着,驱动器测定该数据中包是否带有应用数据,并决定是否将数据转交给应用程序。

应用程序会给输入数据返回一个接收响应,然后在有uIP输出处理模块对该响应进行处理。

输出处理同样很简单。

uIP调用应用程序后,只有当应用程序产生了发送数据给uIP协议栈时,才开始输出处理。

输出处理模块会将所使用的协议包头添加到需要传送的数据包中,继而将数据包转交给用于传输的硬件设备。

图展示了uIP的运行原则。

此图需要参照《基于Contiki的远程极爱的那监控》第九页

uIP协议栈提供了三个接口函数:

uip_init(),uip_input()和uip_periodic()。

uIP协议栈与应用程序的主要接口是UIP_APPCALL()和UIP_UDP_APPCALL()[5]。

uip_input()用来处理接收到的数据发,当该函数执行完返回时,会将要送的数据包保存在全局缓存uip_buf中,并且用整型变量uip_len记录将要发送的数据包大小。

每当uIP的定时器被激发时,uIP会调用uip_periodic()函数进行周期性处理。

图展示了uIP对IPv4数据包的处理流程。

拥有一个功能性/可选择性配置的TCP/IP栈,并且在其上实现一些应用是很棒的,但是只做到这些还不够。

为了和同样层次的节点实现通信,UIP栈需要对更低的通信层(OSI七层模型)进行实现。

那么,需要区分两种类型的通信点。

普通节点:

节点间可以通过无线连接实现通信,UIP栈需要能够发送和接收数据包。

依据UIP版本的不同,CONTIKI遵循如下两个方向。

(1):

当使用的是IPV6时,contiki选择基于路由的配置。

因此UIP6使用一个简单的叫做SICSLOWMAC的实现MAC层。

6LOWPAN模块除了提供头部压缩功能,它还有一个向无线模块发送和接收数据的功能。

(2):

对IPV4而言,Contiki选择一个基于mesh的配置。

Rime通信栈提供mesh路由和路由发现功能的实现。

因此UIP使用它在网络上实现包的发送。

从IP的观点来看,所有来自同一个本地子网的传感网的节点。

可能需要实现无线多跳功能。

网关节点:

PC+一个无线节点,两者通过SLIP方式通信。

(1):

对IPV6而言,一个节点将被简单的编程,用来接收无线数据并且将其发送到串行链路,反之亦然。

在其功能实现时,不做地址比较,节点上不运行IP栈,而只实现包头的解/压缩功能。

从PC来看,这个节点只被视为一个以太网接口,因此大部分工作交给了PC实现。

(2):

对IPV4来说,连接到PC的那个节点起着网关的作用,装上了IP栈的所有功能。

每当它有一个包要发送的时候,它将核对这个包的地址:

如果该包属于无线传感网的子网范围内,就将该包通过无线发送。

否则,它将此通过串行连接的方式发送到PC。

PC上运行的程序,是一个生成IP网络接口的程序。

3.1.4.2Rime协议栈分析

Rime协议栈是一个MAC层路由通信协议,提供mesh路由等多种路由功能,是一个轻量级、层次型的协议栈。

Rime协议栈中的协议使用分层结构。

复杂的协议由比较简单的协议构建而成。

Rime协议栈支持单跳和多跳通信原语。

多跳原语不限定数据包在网络中的传输路由。

相反,当包在网络中被发送时,每个节点的应用或上层协议被激活,用来选择下一跳路由。

这使得基于多跳原语的自定义的路由协议得以实现。

协议栈的调用方法如图所示。

(1)匿名的最大努力单跳广播原语

在Rime协议栈中,匿名的最大努力单跳广播原语(abc)是最重要,也是最基本的通信原语。

abc原语提供一个上层发送数据包到本地邻居(监听着发送channel)的方法。

在传输中,谁是发送者的相关信息不会被包含。

(2)识别的最大努力单跳广播

识别的最大努力单跳广播原语(ibc)发送一个包到所有本地邻居。

ibc原语添加单跳发送者的地址作为包属性给将要发出的包。

所有需要识别发送者的包所使用的Rime原语是ibc原语。

要么直接调用或间接调用一些其他的基于ibc的通信原语。

(3)最大努力单跳单播

最大努力单跳单播原语(uc)发送一个包到一个被识别的单跳邻居。

uc原语使用ibc原语并且增加单跳接受者地址属性到发送包。

对于接收的包,uc模块检查单跳接受者地址属性并且去除地址和本节点地址不合的包。

(4)坚固的单跳单播

坚固的单跳单播(suc)重复的发送一个包到单跳邻居使用uc原语。

stuc原语发送并且重传包知道一个上层原语或者协议取消重传。

然而,对于使用Rime协议栈来直接使用坚固的单跳单播原语的应用或者协议来说,通过可靠的单跳单播原语(ruc),stuc原语最初被使用.

(5)可靠的单跳单播

可靠的单跳单播原语(ruc)可靠地发送一个包到单跳邻居。

ruc原语使用应答和重传机制确保邻居成功接收包。

当接受者已经应答了该包,ruc模块通过回调机制通知那个发送的应用。

ruc原语使用坚固的单跳单播原语来实现重传机制。

因此,ruc原语不是非得实现设置定时器和重传这两个细节。

而是把注意力集中在处理应答上。

(6)礼貌的单跳广播

礼貌的单跳广播原语(polite)是对礼貌的交流算法(来自trickle)地一般化。

礼貌的交流算法被设计,通过不再重复一个其他节点已经发送的消息,来减少包传输总量。

礼貌广播原语的目的是避免在同一个时间间隔内,在本地邻居中多次复制在特定逻辑信道上的规定的一系列包属性。

(7)身份识别的礼貌单跳广播

身份识别的单跳广播(ipolite)像礼貌原语一样以同样的方式工作,但是会通过使用ibc层来增加发送者身份到包属性。

(8)最大努力多跳单播

最大努力多跳单播原语(mh)发送一个包到网络中一个被身份识别的节点,通过使用多跳,向网络中得每一个节点发送。

使用mh原语的应用或者协议为选择下一跳邻居提供了一个路由功能。

如果mh原语被请求去发送一个没有合适的下一跳邻居的包。

调用者会立刻被通知,然后会初始化一个路由发现进程。

路由表构建不是基于传统的路由发表构建方法,诸如基于属性的路由或者机会路由。

而是使用上层协议或应用提供的路由函数。

当一个吓一跳邻居被发现,mh原语使用最大努力单播原语发送包给它。

(9)HOP-BY-HOP可靠的多跳单播

除了在两个单跳邻居之间rhm使用可靠单跳原语。

HOP-BY-HOP可靠的多跳单播原语(rmh)和最大努力多跳单播原语是相似的。

(10)最大努力网路洪泛

最大努力网路洪泛原语(nf)发送一个单次包到所有网络中的节点。

像trickle协议一样,nf原语在每一条都使用礼貌的广播,以减少冗余传输的数目。

然后,和trickle不一样的地方,nf原语不执行洪泛包的重传,而且包不带有版本号。

相反,nf原语会在它发送的包上面设置end-to-end包的ID属性。

一个发送节点保存end-to-end发送者和它发出的最后一个包的ID。

如果一个包和最后一个包有着同样的end-to-end发送者和包ID,那么此包将不被发送。

这一措施会减少路由回环的风险。

但是不会完全杜绝路由回环的发生。

因为nf原语保存最新的可见的包属性。

因此,nf原语也会使计数器去更新属性,计数值会在一个包被发送之前减一。

如果计数值到达零,原语就会不发送数据包。

3.2contiki操作系统在基于IAR的CC2530上移植

由于contiki2.6版本中提供的源码都是基于GNU工具链开发的,不适合在IAR上直接运行。

而GND开发工具链使用起来远没有基于图形界面的IAR要方便的多,所以将contiki从GNU移植到IAR开发环境下,对今后的应用开发很重要。

3.2.1contiki源码目录结构解析

下载到源代码后,解压缩,可以看到代码结构如图所示,下面作详细介绍。

图contiki的源码结构

apps:

用来测试的应用程序,这部分代码与硬件无关,无需移植。

core:

系统内核代码,其中主要是与内核相关部分的文件,也有少部分与内核无关的部分。

在该文件夹下还有三个重要的子文件夹。

他们是与硬件相关的、存储外部设备代码的dev;与硬件无关却与网络相关的net;与操作系统内核相关的sys,该部分也与具体硬件平台无关。

cpu:

和处理器相关的代码,进行操作系统移植的时候仅仅需要根据特定处理器要求来修改该文件夹下的内容即可。

该路径下的文件夹,每一个都对应了一个处理器。

examples:

用于测试的示例程序。

这部分代码有的是基于contiki的,有的是基于java的。

platform:

是与平台相关的代码,这部分代码是针对特定评估板的应用程序入口。

同样的处理器可能有不同的评估板,每个文件夹对应一种类型的评估板。

doc:

该目录有介绍contiki的帮助文档。

tool:

包含了一些测试工具的文件夹。

这部分的内容与操作系统无关,大部分测试工具是基于Java开发的。

例如测试与Ipv6相关的一些网络性能所用的cooja工具,就在该目录下。

其他文件:

是关于contiki介绍以及相关说明的文档。

3.2.2系统内核移植

所谓操作系统移植,就是将操作系统的源码与硬件相关的部分进行修改,使之能够在特定的CPU上运行。

Contiki是一个不可剥夺的内核,移植比较简单。

3.2.2.1移植前需要考虑的问题

官方提供的Contiki源码是在Linux环境下进行的。

如果移植到IAR,首先要解决的就是IAR与GCC两个编译器之间的差异。

主要工作包括:

(1)IAR使用IDE来管理工程编译的,而GCC使用makefile。

并不是所有文件都要添加到IAR工程中,这是需要考虑的。

(2)IAR的内嵌汇编格式和GCC之间存在很大差异,需要全面地将Contiki出现内嵌汇编的地方修改成IAR格式。

如GCC定义中断服务处理程序的格式就和IAR不一致,必须将其修改为符合IAR格式。

如下:

interrupt(T1_VECTOR)

irq_t1(void)

修改为IAR格式:

#pragmavector=T1_VECTOR 

__near_func__interruptvoidrtimer_isr(void);

(3)文件差异,Linux平台下的Contiki与IAR平台下要调用的头文件或文件名字不同。

(比如io.h与iocc253x.h)

(4)增加CC2530的处理器相关代码。

这可以参考既有的CC2430。

3.2.2.2移植工程建立与源码添加

IAREmbeddedWorkbench是一款非常有名的嵌入式开发IDE,已有许多有名的大公司的产品支持使用IAR工具进行开发,本次移植中采用IAR的EW8051-EV-820。

它是目前最高效,灵活的CC2530开发平台。

支持代码在线仿真、下载、三级优化等很多优秀特性。

首先下载并安装IAR软件,建立一个IAR工程,具体建立过程不在此详述。

然后向工程中添加CC2530相关的基础代码、内核文件、和相关的功能模块。

由于本次设计需要支持6lowpan和RPL路由协议,这部分源代码在Contiki的源码目录/core/net路径下,需要有选择的添加。

net/mac目录下的文件都添加到工程中,IAR会根据工程协议的实际配置,有选择的将需要的文件链接到可执行文件中。

net/rpl目录下的文件全部加入。

由于本次设计的6lowpan网络使用的是RPL路由协议,不会使用rmie协议栈,所以net/rime目录下只添加rimeaddr.h和rimeaddr.c。

这两个文件是用来对contiki操作系统的MAC层地址进行管理的,所以必须加入。

值得注意的是需要根据工程文件的实际路径正确的设置预处理路径,以便代码能够正确引用.h文件。

本次移植的头文件路径设置如图所示。

3.2.2.3编写移植文件与修改代码

向工程中添加cpu_init.c、cpu_init.h,完成系统时钟初始化以及系统工作模式的选择。

添加IAR安装目录下8051\inc下的文件iocc2530到工程中。

建立文件clock.c,并添加到工程中。

文件clock.c用于完成系统tick的初始化以及操作系统的tick中断处理,其头文件声明在sys/clock.h中。

clock.c是移植的核心文件,它与操作系统软件部分衔接最为密切,这部分代码用于timer,stimer的计时,周期性处理etimer事件,可以说是整个系统的心脏部分。

其内容如下:

pragmavector=ST_VECTOR

__interruptvoidcc2530_clock_ISR(void)

{

DISABLE_INTERRUPTS();

ENERGEST_ON(ENERGEST_TYPE_IRQ);

timer_value=ST0;

timer_value+=((unsignedlongint)ST1)<<8;

timer_value+=((unsignedlongint)ST2)<<16;

timer_value+=TICK_VAL;

ST2=(unsigned

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学 > 天文地理

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1