4. 配置串口驱动实现控制台输出

任务说明

在VxWorks BSP开发中,串口驱动是系统启动后最早需要工作的外设驱动之一,其核心作用是将内核日志与应用程序的printf输出重定向到串口终端。本案例目标是在BSP中完成串口驱动的初始化与字符发送逻辑,使printf能够通过串口输出到终端。

实现原理

VxWorks的printf最终通过consoleFd或iosDevAdd注册的设备驱动调用底层输出函数。在BSP层面,最小实现需要完成:串口寄存器初始化、字符发送函数、以及将发送函数挂接到系统控制台输出路径。本案例以典型的16550 UART为例,实现轮询方式的字符发送。

关键完整代码

/* 串口寄存器地址(以x86 PCI串口为例,实际地址由BSP配置决定) */
#define UART_BASE       0x3F8
#define REG_THR         (UART_BASE + 0)   /* 发送保持寄存器 */
#define REG_LSR         (UART_BASE + 5)   /* 线路状态寄存器 */
#define LSR_THRE        0x20              /* 发送保持寄存器空标志 */

/* 串口初始化:8位数据位、无校验、1停止位、波特率115200 */
void uartInit(void)
    {
    /* 设置波特率除数锁存 */
    *(volatile unsigned char *)(UART_BASE + 3) = 0x80;  /* DLAB=1 */
    *(volatile unsigned char *)(UART_BASE + 0) = 0x01;  /* 除数低字节 (115200) */
    *(volatile unsigned char *)(UART_BASE + 1) = 0x00;  /* 除数高字节 */
    *(volatile unsigned char *)(UART_BASE + 3) = 0x03;  /* 8N1, DLAB=0 */
    *(volatile unsigned char *)(UART_BASE + 2) = 0xC7;  /* 使能FIFO并清空 */
    *(volatile unsigned char *)(UART_BASE + 4) = 0x0B;  /* 使能IRQ, RTS/DSR */
    }

/* 单字符发送(轮询方式) */
void uartPutChar(char ch)
    {
    /* 等待发送保持寄存器为空 */
    while (!(*(volatile unsigned char *)REG_LSR & LSR_THRE))
        ;
    *(volatile unsigned char *)REG_THR = ch;
    }

/* 字符串发送 */
void uartPutString(const char *str)
    {
    while (*str)
        {
        if (*str == '\n')
            uartPutChar('\r');   /* 输出回车,避免终端显示异常 */
        uartPutChar(*str++);
        }
    }

/* 将串口输出挂接到VxWorks控制台输出路径 */
#include <vxWorks.h>
#include <iosLib.h>
#include <sysLib.h>

/* 控制台设备驱动表 */
LOCAL int uartIoctl(int fd, int request, int arg)
    {
    return OK;
    }

LOCAL int uartOpen(int dev, int flags, int mode)
    {
    return (int)dev;
    }

LOCAL int uartWrite(int fd, char *buffer, int nBytes)
    {
    int i;
    for (i = 0; i < nBytes; i++)
        uartPutChar(buffer[i]);
    return nBytes;
    }

LOCAL int uartClose(int fd)
    {
    return OK;
    }

/* 设备描述符 */
LOCAL DEV_HDR uartDevHdr = {0};

void consoleUartInit(void)
    {
    /* 初始化串口硬件 */
    uartInit();

    /* 创建设备并注册到I/O系统 */
    uartDevHdr.name = "/tyCo/0";
    iosDevAdd(&uartDevHdr, "/tyCo/0", 0);

    /* 注册驱动函数 */
    iosDrvInstall(uartOpen, uartClose, uartWrite, uartIoctl);

    /* 将标准输出重定向到串口设备 */
    ioGlobalStdSet(STD_OUT, open("/tyCo/0", O_WRONLY, 0));
    ioGlobalStdSet(STD_ERR, open("/tyCo/0", O_WRONLY, 0));
    }

编译与集成

将上述代码保存为uartConsole.c,在BSP的config.h中确保包含INCLUDE_PC_CONSOLE未定义(避免冲突),并在BSP的启动代码(通常是usrInit或usrRoot)中调用consoleUartInit()。编译时将该文件加入BSP的makefile源文件列表。

验证方法

  1. 将开发板串口通过USB转串口线连接至PC,终端软件(如PuTTY)设置波特率115200、8N1。
  2. 上电启动VxWorks,观察终端是否出现引导信息(如BSP版本号、内存检测等)。
  3. 在VxWorks shell中执行printf("Hello UART\n"),终端应显示Hello UART。
  4. 若终端无输出,检查串口线连接、终端参数、以及UART_BASE地址是否与硬件实际地址一致。

通过标准:终端能正确显示VxWorks启动日志,且shell中printf输出正常显示,无乱码或丢失字符。