在 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;
}