在 VxWorks 中,系统内核已经帮我们实现了串口驱动,所以可以用统一的接口函数和命令来配置串口相关参数,这一点相比 Linux 简单得多。

串口配置过程

打开串口

fd = open("/tyCo/0", O_RDWR, 0);
"/tyCo/0" 串口1的设备名,O_RDWR:open for reading and writing

设置串口raw模式,清空输入输出的缓冲区

在VxWorks中配置串口可以直接通过ioctl的控制命令来实现,

ioctl(fd,FIOSETOPTIONS,OPT_RAW); 
 ioctl(fd,FIOFLUSH,0); 
 ioctl(int fd,int function,int arg);


function的参数如下:

FIOBAUDRATE

设置波特率,arg为一整数,表示要设定的波特率

FIOGETOPTIONS

取得设备控制字,arg表示读出的内容存放的位置

FIOSETOPTIONS

设置设备控制字,arg表示要设置的选项

FIOGETNAME

取得文件描述符对应的文件名,arg存放文件名的缓冲区

FIOREAD

取得输入缓冲区内未读取的字符数,arg用于接收结果的整型指针

FIOWRITE

取得输出缓冲区内的字符个数,arg用于接收结果的整型指针

FIOFLUSH

清空输入输出缓冲区的字符

FIOCANCEL

取消读和写

设置波特率,数据位,停止位,校验方式

在 VxWorks 中设置串口也是用 ioctl 系统调用加控制命令实现,其控制命令为SIO_HW_OPTS_SET,第三个参数跟配置参数,如:数据位为8,停止位为1,无奇偶校验位,无流控可以这样配置

ioctl(fd,SIO_HW_OPTS_SET,CS8|PARENB|CLOCAL|CREAD);

具体各项参数意义如下:

CLOCAL

忽略modem控制信号

CREAD

启动接收器

CSIZE

指定数据位:CS5~CS8

HUPCL

最后关闭时挂断modem连接

STOP8

被设置时指定2位停止位,否则默认为1位停止位

PARENB

被设置时启用奇偶校验,否则默认为无奇偶校验

PARODD

被设置时启用奇校验,否则默认为偶校验(PARENB设置时才有效)

串口读写操作

在VxWorks中串口的读写操作非常简单,直接使用系统调用 read ()和write()就能实现串口的读写操作。
int read(int fd, char *buffer, size_t maxbytes )
参数说明:

  • fd:用open函数打开串口设备返回的文件描述符;
  • buffer:读取的内容将要存放的地址,为指针变量;
  • maxbytes:读取的最大字节数

int write(int fd, char *buffer, size_t nbytes)
参数说明:

  • fd:用open函数打开串口设备返回的文件描述符;
  • buffer:将要写的内容的地址,为指针变量。通常为字符串首地址;
  • nbytes: 将要写入的字节数,通常为要写入的字符串的长度。

实例

来贴上一个基于 VxWorks 的串口实例

#include "vxWorks.h"
#include "stdio.h"
#include "ioLib.h"
#include "taskLib.h"
#include "sioLib.h"
#include "sdLib.h"
#include "semLib.h"
#include "msgQLib.h"

char wbuf[] = "hello";

#define DEV_NAME "/tyCo/2"
#define MAX_BUF_SIZE    20
#define SD_COMMDATA_NAME    "share_data"
#define SD_COMMDATA_MUTEX   "share_sem"
#define SHARE_DATA_LENGTH 20

typedef struct unix_clock_struct 
{
    UINT32      sec;            /* ms */    
    UINT32      msec;       /* s */
    UINT8       quality;    /* 时标质量 */
} UNIX_CLOCK_STRUCT;

char *comdata;
int set_serial(int fd);
SEM_ID mutexComdata;

void taskUart(void);
int main(void)
{
    int ret;
    int sdCommId;
    char r_buff[MAX_BUF_SIZE];


    mutexComdata = semOpen(SD_COMMDATA_MUTEX, SEM_TYPE_MUTEX, SEM_FULL, SEM_Q_PRIORITY | SEM_DELETE_SAFE | \
                SEM_INVERSION_SAFE, OM_CREATE | OM_DELETE_ON_LAST_CLOSE, NULL);
    if(mutexComdata == NULL)
    {
        /*致命错误,无法创建互斥锁*/
        printf("ERROR TO OPEN SD_COMMDATA_MUTEX\n");
        taskExit(0);
    }   

    /* 申请公共数据共享内存  */
    sdCommId = sdOpen(SD_COMMDATA_NAME, SD_LINGER, OM_CREATE, SHARE_DATA_LENGTH, 0, SD_ATTR_RW|SD_CACHE_OFF, &comdata);
    if(sdCommId == NULL)    
    {
        /*致命错误,无法分配公共数据内存,报错退出*/
        printf("ERROR TO OPEN SD_COMMDATA\n");
        taskExit(0);
    }   

    if((ret = taskSpawn("taskUart",90,0x100, 20000, (FUNCPTR)taskUart,\
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) < 0)
    {
        printf("taskSpawn failed:ret = %s\n");
    }

    //return 0;
}

void taskUart(void)
{
    int ret;
    int fd = -1;
    UNIX_CLOCK_STRUCT w_buff;

    if((fd = open(DEV_NAME, O_RDWR,0)) < 0)
    {
        printf("open %s failed.\n",DEV_NAME);
    }


    /*配置串口参数*/
    if((ret = set_serial(fd)) < 0)
    {
        printf("ret = %d\nset_serial failed.\n");
    }

    while(1)
    {
        semRTake(mutexComdata,WAIT_FOREVER);
#if 0
        /*清空输入输出缓冲*/
        if((ret = ioctl(fd, FIOFLUSH, 0))<0)
        {
            printf(" ret = %d\nset FIOFLUSH failed.\n",ret);
        }


        memset(r_buff,0,sizeof(r_buff));
        /*读取串口中的值*/
        if((ret = read(fd,r_buff,sizeof(r_buff)))<0)
        {
            printf("ret = %d:read %s failed.\n",ret,DEV_NAME);
        }
        else
            printf("Received:%s\n",r_buff);
#endif  

#if 1
        /*清空输入输出缓冲*/
        if((ret = ioctl(fd, FIOFLUSH, 0))<0)
        {
            printf(" ret = %d\nset FIOFLUSH failed.\n",ret);
        }

        if(NULL == bzero(&w_buff,sizeof(w_buff)))
        {
            printf("memset failed.\n");
        }

        if(NULL == memcpy(&w_buff,comdata,sizeof(w_buff)))
        {
            printf("memset failed.\n");
        }

        if(&w_buff != NULL)
        {
            /*往串口中写值*/
            if((ret = write(fd, &w_buff.sec, sizeof(ret)))<0)
           // if((ret = write(fd, wbuf, sizeof(wbuf)))<0)
            {
                printf("ret = %d:write %s failed.\n",ret,DEV_NAME);
            }
            else
            {
                printf("write success:%d\n",w_buff.sec);
            }
        }

        semGive(mutexComdata);
#endif
        taskDelay(sysClkRateGet()*2);
   }
}

int set_serial(int fd)
{
    int error = -1;
    int ok = 0;
    int ret;

    if(fd<0)
    {
        printf("error:fd is %d\n",fd);
    }
    /*设定波特率为9600*/
    if((ret = ioctl(fd, FIOBAUDRATE, 9600))<0)
    {
        printf("ret = %d\n set baudrate failed\n",ret);
        return error;
    }

    /*设定:数据位为8,无奇偶校验,1位停止位*/
    /*CLOCAL:忽略modem控制信号
     * CREAD:启动接收器
     * CS8:设定数据位为8*/
    if((ret = ioctl(fd, SIO_HW_OPTS_SET,CREAD|CS8 |CLOCAL))<0)
    {
        printf("ret = %d\nset SIO_HW_OPTS_SET failed.\n");
        return error;
    }

    return ok;
}