一、简介

1.1 Linux串口编程主要是设置structtermios结构体的个成员值。Termios是在POSIX规范中定义的标准接口,表示终端设备(包括虚拟终端丶串口等),串口是一种终端设备,一般通过终端编程接口对其进行配置和控制。

串口的配置最重要的是以下结构体定义中标明红色的条目,配置方法如下:

  某几位清0:struct_name.flag&=  ~(MASK1 | MASK 2….)

  某几位置1:struc_name.flag|=    (MASK1 | MASK2…)

1.2例如:设置115200的波特率:

        Structtermios new_cfg;

        New_cfg.c_cflag|= B115200

1.3本文写作目的旨在方便查阅串口设置结构体的组成,方便开发

二、结构体定义

#include<termios.h>

Struct termios{

Unsigned short c_iflag;            //输入模式标志

Unsigned short c_oflag;          //输出模式标志

Unsigned short c_cflag;           //控制模式标志

Unsigned short c_lflag;          //本地模式标志

Unsigned char c_line;           //线路规程

Unsigned char c_cc[NCC];       //控制特性

Speed_t c_ispeed;              //输入速度

Speed_t c_ospreed;            //输出速度

}

  2.1 输入模式标志(c_iflag16bit

  

INPCK

奇偶校验使能

IGNPAR

忽略奇偶校验错误

PARMRK

奇偶校验错误掩码

ISTRIP

裁剪掉第8比特

IXON

启动输出软件控制流

IXOF

启动输入软件控制流

IXANY

输入任意字符可以重新启动输入(默:起始字符)

IGNBRK

忽略输入终止条件

BRKINT

当检测到输入终止条件时发送SIGINT信号

INLCR

当收到NL(换行符)转换CR(回车符)

IGNCR

忽略收到的CR

ICRNL

当收到CR转换为NL

IUCLC

讲接收到的大写字符映射为小写字符

IMAXBEL

当输入队列满时响铃

2.2输出模式标志(c_oflag :16bit)

OPOST

启动输出处理功能,如果不设置,其他位忽略

OLCUC

将输出中的大写字符转换成小写字符

ONLCR

将输出中的换行符(‘\n’)转换成回车符(‘\r’)

ONOCR

如果当前列号为0,则不输出回车字符

OCRNL

将输出中的回车符转换成换行

ONLRET

不输出回车符

OFILL

发送填充字符以提供延时

OFDEL

如果设置该标志,则表示填充字符为DEL字符,否则为NUL

NLDLY

换行延时掩码

CRDLY

回车延时掩码

TABDLY

制表符延时掩码

BSDLY

水平退格符延时掩码

VTDLY

垂直退格符延时掩码

FFLDY

换页符延时掩码

2.3控制模式标志(c_cflag:16bit)

CBAUD

波特率的位掩码

B0

0波特率(放弃DTR)

B1800

1800的波特率

B2400

2400的波特率

B4800

4800的波特率

B9600

9600的波特率

B19200

19200的波特率

B38400

38400的波特率

B57600

57600的波特率

B115200

115200的波特率

EXTA

外部时钟率

EXTB

外部时钟率

CSIZE

数据位的位掩码

CS5

5个数据位

CS6

6个数据位

CS7

7个数据位

CS8

8个数据位

CSTOPB

2个停止位(不设置则是一个)

GREAD

接收使能

PARENB

PARODD

校验使能位

使用奇校验而不是偶校验

HUPCL

最后关闭时挂线(放弃DTR)

CLOCAL

本地连接(不改变端口所有者)

CRTSCTS

硬件流控

 

 

2.4本地模式标志(c_lflag:16bit)

ISIG

若收到信号字符(INTR,QUIT等)则会产生相应的信号

ICANON

启动规范模式

ECHO

启动本地回显功能

ECHOE

若设置ICANON则允许退格操作

ECHOK

若设置ICANON,则KILL字符会删除当前行

ECHONL

若设置ICANON,则允许回显换行符

ECHOCTL

若设置ECHO,则控制字符会显示成^x,其中x的ASCII码等于给相应的控制字符的ASCII码加上0x40.

ECHOPRT

若设置ICANON和IECHO,则删除字符和被删除的字符都会被显示

ECHOKE

若设置ICANON,则允许回显在ECHOE和ECHOPRT中设定的KILL字符

NOFLASH

在通常情况下,当接收到INTR,QUIT,SUSP控制字符时,会清空输入和输出队列。如果设置改标志,则所有的队列不会被清空

TOSTOP

若一个后台进程师徒向他的控制终端进行写操作,则系统向改后台进程的进程组发送SIGTTOU信号。该信号通常终止进程的执行

IEXTEN

启动输入处理功能

2.5控制特性(c_cc[])

VINTR

中断控制字符,对应的键位ctrl+c

VQUIT

退出操作符,对应的键为ctrl+z

VERASE

删除操作符,对应Backspace

VKILL

删除行符,对应的键为ctrl+u

VEOF

文件结尾符,对应的键为ctrl+d

VEOL

附加行结尾符,对应的键为carriage return

VEOL2

第二行结尾符,对应的键为line feed

VMIN

指定最少读取的字符数

VTIME

指定读取的每个字符之间的超时时间

三、串口配置基本流程

3.1保存串口配置

  int tcgetattr(int fd, struct termios *termios_p);

3.2激活选项

 CLOCAL和CREAD分别用于本地连接和接收使能,因此要先通过位掩码的方式激活这两个选项:

newtio.c_cflag |=CLOCAL |CREAD;

3.3设置波特率

   波特率的设置不能直接通过掩码来设定,有提供设置函数:

 cfsetispeed(&new_cfg,B115200);

cfsetospeed(&new_cfg,B115200);

3.4设置数据位

首先去掉数据位中的位掩码,再重新按要求设置:

New_cfg.c_cflag &=~CSIZE;

New_cfg.c_cflag |=CS8;

3.5设置奇偶校验位

 New_cfg.c_cflag|=(PARODD | PARENB)     //激活校验位使能

New_cfg.c_iflag                         //激活对输入数据的奇偶校验使能

3.6设置停止位

New_cfg.c_cflag  &= ~CSTOPB            //讲奇偶校验位设置一个比特

New_cfg.c_cflag |=CSTOPB                //讲奇偶校验位设置两个比特

3.7设置最少字符和等待时间

New_cfg.c_cc[VTIME]=0;

New_cfg.c_cc[VMIN]=0;

3.8清除串口缓存

由于串口在重新设置之后,需要对当前的串口设备进行适当的处理,这时就可以调用在<termios.h>中声明的tcdrain(),tcflow(),tcflush()等函数来处理目前串口缓冲中的数据,格式如下:

int tcdrain(int fd)  //使程序阻塞,直到输出缓冲区的数据全部发送完毕

int tcflow(int fd,int action)    //用于暂停或者重新开始输出

int tcflush(int fd,int queue_selector)  //用于清空输入输出缓冲区

3.9激活配置

tcsetattr(int fd,int option_action,conststruct terios *termrios_p)

Param :

Optional_options:

               TCSCANOW:配置的修改立即生效

                                TCSADRAIN:配置的修改在所有写入fd的输出都传输完毕之后生效

               TCSAFLUSH:所有已接受但未读入的输出都将在修改生效之前被丢弃

Return:

   0:成功

  -1:失败

3.10使用串口

串口配置完成后就可以像文件一样读写数据,使用read(),write()函数

四、串口配置实例(通用函数封装)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include<stdbool.h>
#include <termios.h>

/*@ Fn uartOpen

   @param     uartDevicePath      设备文件

   @param     speed                       波特率,默认115200

   @param     dataWidth                数据位宽,默认8bit

   @param     stopBit                      停止位,true:2bit;    false:1bit;

 

   @return       fd                               打开文件描述符

*/ 

int uartOpen(char *uartDevicePath,int speed,int dataWidth,bool stopBit)
{
 //Info
int fd=-1;
struct termios new_cfg,old_cfg; 
printf("uart path=%s\n",uartDevicePath);  


 //open device
fd=open(uartDevicePath,O_RDWR | O_NOCTTY );
if(fd==-1)
printf("open failed!\n");


//preserve the old configuration
if(tcgetattr(fd,&old_cfg)!=0)
  printf("Old config preserve failed!\n");


//set mode
new_cfg.c_cflag |=CLOCAL |CREAD;


//set baudrate
switch(speed){
  case 1800:{
   cfsetispeed(&new_cfg,B1800);
   cfsetospeed(&new_cfg,B1800);
}break;
  case 2400:{
   cfsetispeed(&new_cfg,B2400);
   cfsetospeed(&new_cfg,B2400);
}break;
  case 4800:{
   cfsetispeed(&new_cfg,B4800);
   cfsetospeed(&new_cfg,B4800);
}break;
  case 9600:{
   cfsetispeed(&new_cfg,B9600);
   cfsetospeed(&new_cfg,B9600);
}break;
  case 19200:{
   cfsetispeed(&new_cfg,B19200);
   cfsetospeed(&new_cfg,B19200);
  }break;
  case 38400:{
   cfsetispeed(&new_cfg,B38400);
   cfsetospeed(&new_cfg,B38400);
}break;
  case 57600:{
   cfsetispeed(&new_cfg,B57600);
   cfsetospeed(&new_cfg,B57600);
}break;
  case 115200:{
   cfsetispeed(&new_cfg,B115200);
   cfsetospeed(&new_cfg,B115200);
}break;
  default:{
  cfsetispeed(&new_cfg,B115200);
  cfsetospeed(&new_cfg,B115200);
  }break;
}
//set size of data
new_cfg.c_cflag &=~CSIZE;
switch(dataWidth){
case 5:{
new_cfg.c_cflag |=CS5;
}break;
case 6:{
new_cfg.c_cflag |=CS6;
}break;
case 7:{
new_cfg.c_cflag |=CS7;
}break;
case 8:{
new_cfg.c_cflag |=CS8;
}break;
default :{
new_cfg.c_cflag |=CS8;
}break;
}
//set stopbit:true 2 stopbit,false 1 stopbit
if(stopBit)
new_cfg.c_cflag |=(CSTOPB);
else
new_cfg.c_cflag &=~(CSTOPB);
//set others
new_cfg.c_cc[VTIME]=0;
new_cfg.c_cc[VMIN]=0;
//start
if(-1==tcsetattr(fd,TCSANOW,&new_cfg))
printf("Uart setting failed!\n");


return fd;
}
void main()
{
int fd=uartOpen("/dev/ttyUSB0",115200,8,true);


while(1){
;
//handle here
}
}

Logo

更多推荐