2. VxWorks开发环境搭建
VxWorks 的软件开发与常见的桌面程序开发有一个根本区别:编译发生在宿主机(通常是 Windows 或 Linux 工作站),而运行发生在目标机(工业控制板卡、x86 工控机或 ARM 核心板)。因此“开发环境搭建”这件事,本质上是把宿主机、交叉编译工具链、目标机三者连成一条可用的通路。本节围绕 Workbench 的安装与配置、交叉编译工具链的构成、目标机连接方式,以及第一个工业控制程序的下载与运行展开。
Workbench 的安装与工作空间配置
Workbench 是 Wind River 基于 Eclipse 框架提供的集成开发环境,VxWorks 6.x 与 7 分别对应不同版本的 Workbench。安装前需要确认三件事:宿主机操作系统版本是否在支持列表内、是否有可用的许可证文件(license)、以及安装路径中不要包含中文和空格。安装过程本身是向导式的,真正需要留意的是安装完成后的首次启动配置。
首次启动会要求指定 workspace(工作空间)目录。建议为每个项目单独建立工作空间,例如 D:\vxworks_ws\motor_ctrl,避免不同项目的工程配置互相污染。进入 Workbench 后,需要在 Window → Preferences → Wind River 中确认默认的 VxWorks 安装路径(如 C:\WindRiver\vxworks-7)和默认目标机类型。这一步决定了后续新建工程时能选到哪些 BSP 和工具链。
Workbench 的核心视图包括 Project Explorer(工程管理)、VxWorks Kernel Configuration(内核配置)、Target Manager(目标机管理)和 Debug 视图。工业控制项目通常还需要在 Preferences 中把编辑器编码设为 UTF-8,避免中文注释在编译时出现乱码警告。
交叉编译工具链的构成
交叉编译工具链是宿主机上生成目标机可执行代码的一整套工具。以 ARM 架构为例,典型前缀为 arm-wrs-vxworks,主要成员及其作用如下:
arm-wrs-vxworks-gcc:交叉编译器,把 C/C++ 源码编译为目标机汇编;arm-wrs-vxworks-as:汇编器,把汇编转换为可重定位目标文件;arm-wrs-vxworks-ld:链接器,把目标文件与 VxWorks 库链接为可执行映像;arm-wrs-vxworks-objdump / nm / size:用于查看符号表、段大小和反汇编,是排查链接错误和内存占用的常用工具。
工具链的关键参数是 -tune 与 -march,它们必须与目标 CPU 核心匹配。例如目标机是 Cortex-A9,则应使用 -mcpu=cortex-a9;若误用 Cortex-A7 的选项,程序可能在启动阶段就触发非法指令异常。此外,VxWorks 的编译还需要指定内核头文件路径,通常由 Workbench 工程自动带入,手工编译时才需要显式添加 -I 参数。
arm-wrs-vxworks-gcc -v,确认输出的 target 字段为 arm-wrs-vxworks 而非宿主机的 x86_64-w64-mingw32。若 target 不对,说明 PATH 中混入了其他工具链。目标机连接方式
Workbench 与目标机之间需要一条“下载与调试通道”和一条“控制台通道”。常见组合有三类:
| 连接方式 | 下载/调试通道 | 控制台通道 | 适用场景 |
|---|---|---|---|
| 以太网 + 串口 | Ethernet(TFTP/FTP) | RS-232 串口 | 最常用,适合带网口的工控板 |
| 纯串口 | Serial | 同一串口 | 无网口的老旧设备,速度慢 |
| JTAG + 以太网 | JTAG(用于 BootROM 烧写) | Ethernet | 裸板首次部署 |
以最常见的“以太网 + 串口”为例,配置要点是:目标机通过 BootROM 参数设定 boot device 为 motetsec 或 fei,host inet 指向宿主机 IP,target inet 为目标机 IP,二者必须在同一网段。串口参数通常为 115200-8-N-1。在 Workbench 的 Target Manager 中新建连接时,选择对应的目标机类型和 IP,连接成功后 Target Manager 会显示目标机状态为 Connected。
第一个工业控制程序:下载与运行
下面以一个典型的工业控制示例——周期性读取模拟量并输出控制字——来说明完整流程。程序通过 VxWorks 的任务机制实现 100 ms 周期控制,示例参数均为教学假设值。
#include <vxWorks.h>
#include <taskLib.h>
#include <sysLib.h>
#include <logLib.h>
#define CTRL_PERIOD_TICKS 10 /* 假设 1 tick = 10 ms,即 100 ms 周期 */
#define ADC_CHANNEL 0
#define SETPOINT 2048 /* 12 位 ADC 中点,示例设定值 */
void ctrlTask(void)
{
int adcVal, err, outWord;
while (1) {
adcVal = simAdcRead(ADC_CHANNEL); /* 读取模拟量 */
err = SETPOINT - adcVal; /* 偏差 */
outWord = (err > 0) ? 1 : ((err < 0) ? 2 : 0);
simDacWrite(outWord); /* 输出控制字 */
logMsg("adc=%d err=%d out=%d\n", adcVal, err, outWord, 0, 0, 0);
taskDelay(CTRL_PERIOD_TICKS);
}
}
int ctrlStart(void)
{
int tid = taskSpawn("tCtrl", 100, 0, 8192,
(FUNCPTR)ctrlTask, 0,0,0,0,0,0,0,0,0,0);
if (tid == ERROR) {
logMsg("ctrlStart failed\n", 0,0,0,0,0,0);
return ERROR;
}
return OK;
}
在 Workbench 中新建 Downloadable Kernel Module 工程,把上述源码加入工程,编译后生成 ctrl.out。随后在 Target Manager 中右键目标机,选择 Download,指定 ctrl.out。下载成功后,在目标机 Shell 中执行 ctrlStart,即可看到任务启动。用 i 命令查看任务列表,应能看到名为 tCtrl 的任务处于 READY 或 DELAY 状态;用 sp tCtrl 可查看其堆栈使用情况。
判断程序是否真正跑起来,可以观察三点:一是 Shell 中周期性打印的 adc=... err=... out=... 日志;二是 i 命令中任务状态在 READY 与 DELAY 之间切换;三是若目标机接有实际执行机构,控制字输出应随模拟量变化而变化。若日志不打印,优先检查 logMsg 的参数个数是否与格式串匹配——VxWorks 的 logMsg 要求固定传入 6 个参数,多传或少传都可能导致异常。
至此,宿主机、工具链、目标机三者已经连通,第一个控制程序也完成了从编译、下载到运行验证的闭环。后续更复杂的工业控制应用,都是在这条通路之上叠加驱动、通信和实时性设计。