嵌入式Linux平台下电力载波路由器的软件设计
扫描二维码
随时随地手机看文章
电力载波(PLC)是电力系统通信的一种基本方式,广泛应用于电力行业的自动化抄表系统中。由于电力载波是利用电力线来作为传输媒介,因此,电力线路的距离长短和用户的用电负荷都会对电力载波通信效果造成影响,而通过载波模块实现对一台区下所有电表的直抄是不可能的。目前常用的解决方法是为每块电表安装带中继转发功能的载波模块,不能直抄的表可以通过距离远近或信号质量较佳的表对其进行中继转发抄收。电力载波通信信道,其载波通信信号衰减大、干扰严重、不稳定,如何根据线路状态以及通信距离的远近自动分配各电表的中继节点并动态维护这些节点是进行中继转发抄收时应解决的问题。因此有必要设计一种电力载波通信路由器以实现对一台区下各节点中继路径的智能制定及其维护,以方便其上级采集器对所有节点的抄收。
1 系统拓扑结构
载波集抄系统拓扑图。
2 电力载波路由器的软件设计
2.1 DLT/645—2007多功能电表通信规约
本通信规约规定了多功能电表与手持单元(HHU)或其他数据终端设备之间的物理连接、通信链路及应用技术规范,适用于本地系统中多功能电表与手持单元或其他数据终端设备进行点对点或一主多从的数据交换方式[1]。645协议规定了通信采用异步串行的通信方式,其每个字节包含有1个起始位、8个数据位、1个偶校验位及1个停止位,缺省通信速率为2 400 b/s,传输时先传低位,后传高位。应用规定了如图2所示的每一帧的信息格式。
在图2中,68H为帧的起始符;A0~A5为通信端的物理地址,一共是6个字节;L为数据域的长度;DATA为数据域;16H为帧的结束符;CS表示校验码,校验码是从第1帧起始符开始到校验码之前的所有各字节的模256的和,即各字节二进制算术和,不计超过256的算术值;C为控制码,控制码一共有8 位,在保留645协议中对控制码各位定义的基础上,本设计针对中继功能的使用重新定义了控制码。同时为了保障载波通信的可靠性,还省去了645协议中关于后续帧的定义。控制码的格式。
2.2 路由算法的设计
路由的目的是要建立一张各节点的最优路径表,此表记录了台区下每个节点的中继级别、各级的中继地址及目的地址。这种路由表是动态的,存放在RAM中,每隔5 min会自动更新一次。路由表的初始值各项均为0,其格式如图4所示。
路由表的建立是软件中最核心的部分,本设计采用了多叉树遍历寻优[3]算法,从路由器节点开始逐层搜索。其算法描述如下:
(1)路由器先将网络中的所有节点建成一个带有头节点的单向链表,然后开始向网络中所有节点依次发送直抄查询命令,并等待回应。若能在规定时间内(10 s)收到节点的应答信息,则表明该节点可以进行直抄;然后将可以进行直抄的电表从链表中删除,并将删除的节点重新组成一个新的链表。路由表建立示意图。
单个节点的属性如下:
struct mac_list
{
U8_t mac[6]; //节点的MAC地址
U8_t flag;
//flag表示路由表中已建立该MAC对应的路由项
int use_tim;
//此项只在中继转发时有用,表示转发过程所花费的时间
U8_t num; //节点的序号
U8_t respond_num[10];
//记录可以与自身进行通信的电表序号
struct mac_list *next;
};
完成第一次遍历直抄搜索后,建立了以Head 1为首的单向链表(称为第一层)。第一层中的各节点都可以直抄,它们在路由表中只要填写中继级别和目的地址即可。由于是可以直抄的节点,所以中继级别填为0;
(2)对剩下的节点进行一级中继遍历搜索,依照链表中各节点的序列顺序,依次选取第一层中单个节点作为剩下节点的一级中继,对余下的节点进行转发抄收测试。
在一级中继节点确定的过程中,第一层中的每个节点都会尝试对剩下的节点进行一级中继转发,若剩下的节点中,存在能对中继转发帧作出回应的节点,则表明该节点可以进行一级中继抄收。通常一个节点的中继抄收路径存在好几条,这时需要通过计算中继抄收时间来选择一条用时最短的路径,这样才能保证采集器抄收时用时最短。经过对剩下节点进行一级中继遍历抄收搜索后,剩下的节点中可以进行一级中继抄收的节点将会组成第二层。同样,第二层由从Head中删除的一级中继抄收节点组成,并顺序存储在以Head2为头节点的链表中,建立好的第二层结构。
(3)对剩下的节点进行二级中继遍历搜索。一般而言,二级中继可以做到对一台区下所有节点的覆盖。剩下的节点要进行中继路径的确定,首先要确定它的父节点(二级中继节点),父节点是从建立好的第二层来选择的;然后确定它的一级中继节点,而一级中继节点是从第一层中选择的。由图7可知,一级中继路由建立完成之后,第一层与第二层有着确定的连接关系,所以在节点的属性中设置了respond_num数组来记录可以与自身进行通信的电表序号。这样,建立二级中继时可通过比较从路由器发送二级中继转发命令到目的节点作出的响应,即这个通信过程所花费的时间来确定中继路径。建立二级中继的过程示意图。
2.3 嵌入式Linux平台下路由器的多线程程序设计
Linux是一种完全开源的32位操作系统,它几乎支持所有体系架构的处理器。由于它具有开源、可定制、安全、稳定等特征,所以可对其进行裁剪、修改使之能够稳定运行在嵌入式开发平台上。针对电力载波通信路由器的实际应用需求,本设计移植了Linux-2.6.29.4内核至ARM9平台上,并配置了 EXT2/VFAT/NFS文件系统及串口和网络通信驱动。为了使路由器能够更快速和稳定地进行路由、路由表动态维护、抄表查询等工作,本文提出了一种多线程的解决方案,利用Linux对多线程的支持很好地解决了各项任务的快速切换、相互通信等问题。[!--empirenews.page--]
Linux系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,链接时需要使用库libpthread.a[4]。在程序中,本文给路由表的建立分配了id_route线程,为串口2和网络UDP通信分别分配了id_com和 id_net线程。这三个线程是相互独立的,其中串口2和网络UDP线程以阻塞的方式来等待采集器发出的抄表查询指令。线程的初始化工作均由 pthread_creat函数来开启,id_route线程开启后,串口1开始对外发送直抄、一级中继抄表、二级中继抄表的数据命令帧并根据接收到的节点响应数据帧来建立台区下相应节点的路由信息。id_route线程结束后会激活id_reroute线程,这个线程主要是为下次路由表更新进行定时,定时时间设为20 min,即每隔20 min,更新一次路由表。id_route线程的主要功能就是不停地查询20 min定时有没有到,如果定时到,则关闭20 min定时器,并开启id_route线程。程序多线程化后,就要考虑线程间的同步问题,如线程id_route正从文本文件中读取当中记录的各个节点的 MAC地址、id_net线程正试图向文本文件中添加某一节点的MAC地址。如果两个线程不加以同步,必会导致节点MAC地址的混乱。本设计采用一种称为 “互斥锁”的同步方式,它可以保证任一时刻只有一个线程能访问它,利用这一性质可以保护共享数据。建立路由表的线程流程图。
本文提出了一种路由路径寻优算法并在嵌入式Linux平台下实现了这种路由算法,该算法可以保证节点搜索的不重复性、路由建立的快速性和数据抄收的正确性。利用Linux对多线程编程的支持及强大的网络通信功能,实现了路由维护与网络、串口通信的并发运行,很好地满足了自动化抄表系统中对网络通信和抄表实时性的要求。