1 概 述
嵌入式系统具有专用性强、外围设备多样的特性,这决定了其应用的硬件环境差异性较大。系统软件模块与硬件之间的接口是嵌入式实时系统的主要特征,是系统设计过程中的必需环节,也是影响嵌入式系统应用前景的关键问题之一。硬件抽象层(Hardware Abstraction Layer,HAL)的引入可有效解决这一问题。HAL是将硬件平台与应用软件隔离开来的软件层次,通过硬件抽象技术实现硬件相关和硬件无关两部分程序代码的隔离,为应用软件提供一个没有硬件特性的接口。硬件抽象层的引入不仅是系统体系结构设计方法的改进,更直接关系到整个系统的开发模式以及嵌入式操作系统的可移植性。硬件抽象层的引入大大推动了嵌入式系统开发的规范化进程。
EMC是一个开放源代码的用于机床或机器人等运动控制系统的计算机控制软件。它能同时驱动9轴电机。其运动控制特性包括:刀具半径和长度补偿、轴同步运动、自适应进给速度、恒速度控制等。EMC2在原有EMC软件的基础上加入了许多新的特性和功能,其中包括了HAL和软件PLC模块ClassicLadder。ClassicLadder是一个基于LGPL协议的梯形图解释器。它随着EMC2一起发布,可以与EMC2的HAL一起工作。本文中的控制系统利用EMC2的HAL为软PLC中的应用程序提供底层硬件操作支持,提高了应用程序的平台无关性与可移植性。
2 硬件架构
控制器是锂电池卷绕恒张力控制器,采用符合PC/104总线规范的单板计算机(以下简称PC104)与基于FPGA的专用主机板相结合的方法构建系统硬件。PC104中运行实时Linux,ClassicLadder及HAL作为实时模块加载到Linux系统中。
系统硬件框图如图1所示。其中ADS8361为12位模/数转换器,用于采集张力值等模拟量;AD5624为数/模转换器,用于控制直流电机转速及气压阀压力值;FPGA控制所有外围芯片,并产生电机脉冲方向信号,同时对电机编码器信号进行计数;CPLD控制I/O输入/输出点,并与FPGA交换信息。利用EMC2中HAL的实现原理,可编写组件将硬件系统所有设备抽象成引脚和函数的形式,供软PLC在需要时加载。
3 EMC2中HAL的基本概念
EMC2的HAL提供了一种简便方法,将一些已有软硬件模块进行加载和组合形成一个复杂的系统,从而使EMC2更容易配置,以使用各种硬件设备。硬件资源在HAL中被封装成特定组件,随时被控制系统载入使用。EMC2中的HAL有以下基本概念:
Component,组件。是定义好输入、输出及行为的软件模块,可以在需要时安装及连接。
Parameter,参数。许多硬件组件有可调整参数需要进行访问。HAL有输入及输出两种类型的参数。
Pin,引脚。硬件组件用于互联的连接端子。所有Pin都有名称,并在连接时使用。HAL的Pin是只存在于计算机内的软件实体。
Physical_Pin,物理引脚。许多I/O设备有真正的物理引脚或终端连接到外部硬件,这些被称为物理引脚。
Signal,信号。现实中硬件组件使用导线互连。在HAL中导线相当于“信号”。HAL的信号将HAL的引脚连接在一起,可以随意断开或重新连接。
Type,类型。引脚和信号都有类型属性,即信号只能连接到相同类型的引脚。目前,HAL有4种类型:BIT、FLOAT、U32、S32。
Function,函数。每个函数是一个执行具体行为的代码块,执行读取输入、计算输出等操作。系统设计者可以使用“线程”对一系列函数加以调度,以使其按照特定的顺序及时间间隔运行。
Thread,线程。作为一个实时任务的组成部分,线程是一个以特定时间间隔运行的函数序列。函数可以添加到线程并在每次线程运行时调用。4 HAL架构
系统软件架构如图2所示。用HAL将各I/O通道、ADC通道、DAC通道、脉冲通道、编码器通道抽象成Pin,将对硬件各模块的操作抽象成各个Function,将Pin和Function封装在命名为hal_CNC的Component中。
硬件在Component中被映射为如下数据结构:
由上述结构可以看出,每个Pin对应一个相应类型的指针,该指针指向的内存区便存放该引脚的值。
5 基于HAL的驱动程序编写
hal_CNC由源文件hal_CNC.c和hal_CNC.h构成。hal_CNC.c定义了对hal_CNC的初始化、底层硬件驱动函数、hal_CNC退出时的操作等。rtapi_app_main()函数是载入Component时的程序入口。
首先申请当前Component的ID号,对Component的每个操作都由该ID号索引。
comp_id=hal_init(“hal_CNC”);
//hal_CNC为Component的名字
其次,分配组件运行时所需内存,代表Pin的指针指向的内存区域便是在此分配:
CNC_driver=hal_malloc(sizeof(CNC_struct));
接着将所定义Pin导出到HAL。该操作通过调用自定义的export()函数来完成。以DAC模块为例,操作如下:
for(n=0;n<8;n++)
export_dac(n,CNC_driver); //导出Pin
每次调用export_dac()时,都会调用如下语句注册一个Pin。
rtapi_snprintf(buf,HAL_NAME_LEN,“CNC.DAC.%d.value”,num);
hal_pin_float_new(buf,HAL_IN,&(addr->dac_value[num]),comp_id);
其中“CNC.DAC.XXX.value”是Pin的名称。软PLC通过该名称对此Pin进行引用。hal_pin_float_new()是HAL提供的函数,在新建Type为FLOAT型的Pin时使用。该函数一共有4个参数,依次是Pin名、Pin方向、Pin内存指针地址、Component ID。引脚方向HAL_IN表示该值是从软件层“输入”到HAL中的,该方向针对软件层与HAL层而言。
对Pin进行操作的Function也要导出到HAL:
hal_export_[unct(“CNC.DAC.write”,CNC_dac_write,CNC_driver,1,0,comp_id);其中“CNC.DAC.write”为软件层使用该Function时引用的名字;CNC_dac_write为函数在C源文件中实际对应的C函数名称;CNC_driver为Component的内存指针;1表示函数用到了浮点数;0表示该函数不可重入;comp_id为Component ID。
依照上述做法将所有硬件功能模块全部导出到HAL后,在rtapi_app_main()的最后调用hal_ready(comp_id),表明该Component已经初始化完毕,可以开始使用了。
在关闭Component退出时,系统会自动调用hal_CNC.C中编写的rtapi_app_exit()。其实现如下:
void rtapi_app_exit(void){hal_exit(comp_id);)
hal_exit()关闭并释放HAL及RTAPI使用到的系统资源,使这些资源可被重新使用。
用EMC2自带的工具comp对源文件hal_CNC.c和hal_CNC.h进行编译,即可得到名为hal_CNC的Compo-nent。该组件自动放入EMC2的模块库中,随时可被其他软件模块调用。
6 HAL的使用
以DAC为例,在Linux下的命令行输入“halrun”进入EMC2的HAL运行界面,输入:
loadrt threads namel=thread periodl=1000000
创建名为“thread”的线程,该线程执行周期为1 ms。
执行:
loadrt hal_CNC
将所编写的硬件系统组件调入,执行:
addf CNC.DAC.write thread
将DAC的写函数加入到前面创建的线程thread,使之以与thread相同的执行周期被调用。然后使可通过控制DAC的引脚来输出相应的电压。如:
setp CNC.DAC.0.value 1
该语句将使电路板上的DAC输出端子输出1 V的电压。
用类似的方法将其他软件模块通过与HAL的引脚连接,便实现了其他软件对HAL的调用。
7 HAL在ClassicLadder中的调用
以从DAC输出5 V为例,将classicladder的一个名为“classicladder.0.s320ut-00”的有符号32位整型Pin赋值为5。该值经过HAL中的一个类型转换Component“s32tofloat”变为浮点数,再连接到hal_CNC中的DAC单元的引脚“CNC.DAC.0.value”,便在实际硬件电路板的DAC输出端输出5 V的电压。引脚连接如表1所列。
其中“→”和“←”表示引脚之间的连接,用HAL中的Sig-nal实现。
在软PLC中设置变量W10的值为5,则在DA输出端子引脚上用万用表测到5 V的电压。软PLC中的操作输出如图3所示。
其中4个窗口表示DAC的4个通道,分别令DAC输出5 V、2 V、3 V、4 V的电压。
8 结 论
实践证明,HAL的引入可极大提高嵌入式软件实现的硬件无关性。从软件的角度来看,其面向的硬件具有同质的接口,对硬件的操作具有相似的方法与架构,极大地简化了软件对硬件的控制,方便了同类软件在不同硬件平台间的移植。这就为软硬件同步设计、分工协作奠定了良好的基础。该架构已成功应用在文中所述的锂电池卷绕恒张力控制器中,取得了良好效果。