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。

宿主机防火墙常拦截 TFTP 的 69 端口和 FTP 的 21 端口,导致“连接成功但下载失败”。排障时应先临时关闭防火墙或放行这两个端口,再重试下载。

第一个工业控制程序:下载与运行

下面以一个典型的工业控制示例——周期性读取模拟量并输出控制字——来说明完整流程。程序通过 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 个参数,多传或少传都可能导致异常。

VxWorks 开发环境通路与首个控制程序运行链路 宿主机(Windows/Linux) Workbench IDE + workspace 交叉工具链 arm-wrs-vxworks-gcc Target Manager 连接配置 以太网通道 TFTP/FTP 下载 ctrl.out 串口通道 115200-8-N-1 控制台 目标机(工业控制板) VxWorks 内核 + BootROM tCtrl 任务(100 ms 周期) ADC 采集 / DAC 控制字输出 首个控制程序下载与运行链路 编写 ctrl.c 编译生成 ctrl.out Target Manager Download ctrl.out Shell 执行 ctrlStart i / sp tCtrl 查看任务状态 日志输出 adc/err/out 判断依据:日志周期打印、任务在 READY/DELAY 间切换、控制字随模拟量变化 注:图中 IP、周期、设定值均为教学示例参数

至此,宿主机、工具链、目标机三者已经连通,第一个控制程序也完成了从编译、下载到运行验证的闭环。后续更复杂的工业控制应用,都是在这条通路之上叠加驱动、通信和实时性设计。