关于串口编程,在各大操作系统下的流程基本是一致的,只是针对不同的操作系统,函数接口可能有所差异而已,下面讲述VxWorks操作系统下对于串口编程步骤和代码:

  1. 打开串口
  2. 设置串口raw模式,清空输入输出的缓冲区
  3. 设置波特率,数据位,停止位,校验方式
  4. 读和写
打开串口:

fd = open("/tyCo/0", O_RDWR, 0);

"/tyCo/0" 串口1的设备名,O_RDWR:open for reading and writing

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

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

ioctl这个函数解释如下:

function这个参数有如下:(tty)

FIOBAUDRATE 设置波特率,arg为一整数,表示要设定的波特率
FIOGETOPTIONS 取得设备控制字,arg表示读出的内容存放的位置
FIOSETOPTIONS 设置设备控制字,arg表示要设置的选项
FIOGETNAME 取得文件描述符对应的文件名,arg存放文件名的缓冲区
FIOREAD 取得输入缓冲区内未读取的字符数,arg用于接收结果的整型指针
FIOWRITE 取得输出缓冲区内的字符个数,arg用于接收结果的整型指针
FIOFLUSH 清空输入输出缓冲区的字符
FIOCANCEL 取消读和写

FIOSETOPTIONS对应的arg有OPT_LINE,OPT_RAW,OPT_ECHO等等

关于这些的定义,可以在sioLib.h,ioLib.h里寻找。

设置波特率,数据位,停止位,校验方式
  1. STOPB:两位停止位,默认是1位停止位
  2. PARENB:使能校验,未使能则是无校验
  3. PARODD:奇校验,使能后默认是偶校验
  4. CS5,CS6,CS7,CS8: 5,6,7,8位数据位
举例

CS8|PARENB :8位数据位,1位停止位,偶校验

CS8|PARENB|PARODD: 8位数据位,1位停止位,奇校验

CS8: 8位数据位,1位停止位,无校验

CS8|STOPB: 8位数据位,2位停止位,无校验

示例代码:


int SerialOps = 0;
ioctl(fd, FIOBAUDRATE, 9600); //9600波特率
SerialOps |= CS8; //8数据位, 1位停止位,无校验
ioctl(fd, SIO_HW_OPTS_SET, SerialOps); //设置

SIO_HW_OPTS_SET(设置硬件选项)是在XXDrv里的function

SIO_HW_OPTS_SET对应的arg:

CLOCAL 忽略modem控制信号
CREAD 启动接收器
CSIZE 指定数据位:CS5~CS8
HUPCL 最后关闭时挂断modem连接
STOPB 被设置时指定2位停止位,否则1位停止位
PARENB 被设置时启用奇偶校验,否则不进行奇偶校验
PARODD 被设置时启用奇校验,否则偶校验,(PARENB被设置时才有效)
读写

int read
    (
    int    fd,                /* file descriptor from which to read */
    char * buffer,            /* pointer to buffer to receive bytes */
    size_t maxbytes           /* max no. of bytes to read into buffer */
    )
int write
    (
    int    fd,                /* file descriptor on which to write */
    char * buffer,            /* buffer containing bytes to be written */
    size_t nbytes             /* number of bytes to write */
    )

关于串口的设置,需要参考tty和xxDrv。详细的还是需要看书的。

下面举个例子:在有些的设置需要如下:


fd = open(tyco,2,0);
logMsg("/n%s;fd=%d/n", tyco,fd,0,0,0,0); 
ioctl(fd, FIOOPTIONS, OPT_RAW);
ioctl(fd,FIOBAUDRATE,115200); //设置串口波特率为9600bps
ioctl(fd,FIOFLUSH,0);//清空输入输出缓冲
//ioctl(fd,SIO_HW_OPTS_SET,CS8|PARENB|PARODD|CLOCAL|CREAD); //设置 8 位数据位,1位停止位,带校验位,奇校验,没有流控制CLOCAL,使能读CREAD
//ioctl(fd,SIO_HW_OPTS_SET,CS8|PARENB|CLOCAL|CREAD); //设置 8 位数据位,1位停止位,带校验位,偶校验,没有流控制CLOCAL,使能读CREAD
ioctl(fd,SIO_HW_OPTS_SET,CS8|CLOCAL|CREAD); //设置 8 位数据位,1位停止位,带校验位,无校验,没有流控制CLOCAL,使能读CREAD
write(fd,str,48);//需放在清缓存后,mpc8280不用。和SIO_HW_OPTS_SET之后,因为会reset串口

上面粗字体,需要注意。有些需要,有些不需要的。

完整代码:

 

 
#include "ioLib.h"  
#include "stdio.h"  
#include "taskLib.h"  
#include "sioLib.h"  
#include "string.h"  
     
/*ioctl(com2_Fd,FIOSETOPTIONS,OPT_RAW);*/  
int tyRecv(int fd,int fd2)  
{  
    int readCnt1;  
    char rd;  
    char buff[512];  
    int i;  
    FOREVER  
    {  
        i=0;  
        taskDelay(25);  
        ioctl(fd,FIONREAD,&readCnt1); /* 判断com1接收数据缓冲区是否有数据到来 */  
        if(readCnt1>0)  
        {  
            while(readCnt1>0)  
            {  
                read(fd,&rd,1);  
                readCnt1--;  
                buff[i++]=rd;  
                taskDelay(1);  
            }  
            buff[i]='\0';  
            printf("read1 [%s] \n",buff);  
        }  
             
        i=0;  
        taskDelay(25);  
        ioctl(fd2,FIONREAD,&readCnt1); /* 判断com2接收数据缓冲区是否有数据到来 */  
        if(readCnt1>0)  
        {  
            while(readCnt1>0)  
            {  
                read(fd2,&rd,1);  
                readCnt1--;  
                buff[i++]=rd;  
                taskDelay(1);  
            }  
            buff[i]='\0';  
            printf("read2 [%s] \n",buff);  
        }  
    }  
}  
int tySend(int fd,int fd2)  
{  
    int wrtCount,i;  
    char buff[]=" I am god of war!"; /* 发送内容 */  
    for(i=0;i<10;i++)  
    {  
        buff[0] = '1'+i;  
        wrtCount = write(fd,buff,strlen(buff));  
        printf("write1 %d bytes \n",wrtCount); /* 写com1口,然后数据就会通过串口直连线发送到com2方了 */  
        taskDelay(60);  
        buff[0] = 'a'+i;  
        wrtCount = write(fd2,buff,strlen(buff));  
        printf("write2 %d bytes \n",wrtCount); /* 写com2口,然后数据就会通过串口直连线发送到com2方了 */  
        taskDelay(60);  
    }  
}  
     
int com1_Fd,com2_Fd;  
int taskID;  
int taskID2;  
int test()  
{  
     
    com1_Fd = open("/tyCo/0",2,0) ; /* 打开串口0,即serial<->com1 */  
    com2_Fd = open("/tyCo/1",2,0); /* 打开串口1,即serial2<->com2 */  
         
    ioctl(com1_Fd,FIOSETOPTIONS,OPT_RAW);  
    ioctl(com2_Fd,FIOSETOPTIONS,OPT_RAW);  
    /* 设置串口0,亦即com1的波特率9600,8数据为,1停止位,无校验位 */  
    if ( ERROR==ioctl(com1_Fd,FIOBAUDRATE,9600) )  
    {  
        printf("can not set BAUDRATE!\n") ;  
        return ERROR ;  
    }  
    if ( ERROR==ioctl(com1_Fd,SIO_HW_OPTS_SET,(CLOCAL|CREAD|CS8)&~(HUPCL|STOPB|PARENB)))  
    {  
        printf("can not set OPT!\n") ;  
        return ERROR ;  
    }  
    ioctl(com1_Fd,FIOFLUSH,0);  
         
         
    /* 设置串口1,亦即com2的波特率9600,8数据为,1停止位,无校验位 */  
    if ( ERROR==ioctl(com2_Fd,FIOBAUDRATE,9600) )  
    {  
        printf("can not set BAUDRATE!\n") ;  
        return ERROR ;  
    }  
    if ( ERROR==ioctl(com2_Fd,SIO_HW_OPTS_SET,(CLOCAL|CREAD|CS8)&~(HUPCL|STOPB|PARENB)))  
    {  
        printf("can not set OPT!\n") ;  
        return ERROR ;  
    }  
    ioctl(com2_Fd,FIOFLUSH,0);  
         
    printf("com1:0x%x com2:0x%x!\n",com1_Fd,com2_Fd) ;  
    /* 发起接受数据的任务 */  
         
    taskID = taskSpawn("recv",60,0,0x2000,(FUNCPTR)tyRecv,com1_Fd,com2_Fd,0,0,0,0,0,0,0,0);  
    /* 发起发送数据的任务*/  
    taskSpawn("send",80,0,0x2000,(FUNCPTR)tySend,com1_Fd,com2_Fd,0,0,0,0,0,0,0,0);  
     
     
         
}  
     
void del()  
{  
    taskDelete(taskID);  
    /*taskDelete(taskID2);*/  
    close(com1_Fd);  
    close(com2_Fd);  
}