Linux C/C++串口读写

news/2024/11/16 21:37:25/

1.串口简介
串行通信接口(简称“串口”)是计算机一种常用的接口,因其连接线少、通讯简单的特点而得到广泛使用。常用的串口是 RS-232-C接口(又称EIA RS-232-C),它是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准,全称为“数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准”。该标准规定采用一个25个脚的DB25 连接器,对连接器的每个引脚的信号内容加以规定,并且还对各种信号的电平加以规定。传输距离在码元畸变小于4%的情况下,传输电缆长度应为50英尺(即15.24米)。
Linux 操作系统从一开始就对串行口提供了很好的支持,下表为计算机串口的引脚说明。

序号

信号名称

符号

流向

功能

2

发送数据

TXD

DTEDCE

DTE发送串行数据

3

接收数据

RXD

DTEDCE

DTE接收串行数据

4

请求发送

RTS

DTEDCE

DTE请求DCE将线路切换到发送方式

5

允许发送

CTS

DTEDCE

DCE告诉DTE线路已接通可以发送数据

6

数据设备准备好

DSR

DTEDCE

DCE准备好

7

信号地

 

 

信号公共地

8

载波检测

DCD

DTEDCE

表示DCE接收到远程载波

20

数据终端准备好

DTR

DTEDCE

DTE准备好

22

振铃指示

RI

DTEDCE

表示DCE与线路接通,出现振铃

2.串口操作
(1)串口头文件:以下是串口操作需要的头文件。

#include <stdio.h>      /*标准输入输出*/
#include <string.h>     /*标准字符串处理*/
#include <stdlib.h>     /*标准函数库*/
#include <unistd.h>     /*Unix标准函数*/
#include <sys/types.h>  /*数据类型定义,比如一些XXX_t的类型*/
#include <sys/stat.h>   /*返回值结构*/
#include <fcntl.h>      /*文件控制*/
#include <termios.h>    /*PPSIX终端控制*/
#include <errno.h>      /*错误号*/

 (2)串口打开:Linux串口文件位于/dev目录下,串口0为/dev/ttyS0,串口1为/dev/ttyS1,打开串口需要使用标准的文件打开函数open。

/*串口打开*/
int open_dev(char *Dev)
{int fd = 0;fd = open(Dev, O_RDWR|O_NOCTTY| O_NDELAY);if(-1 == fd){perror("open COM error");return -1;}return fd;
}

(3)串口设置:最基本的串口设置包括波特率、校验位和停止位,主要是设置结构体struct termios各成员的值,以下是结构体struct termios组成。

struct termio
{tcflag_t c_iflag;    /*输入模式标志,unsigned short*/tcflag_t c_oflag;    /*输出模式标志,unsigned short*/ tcflag_t c_cflag;    /*控制模式标志,unsigned short*/  tcflag_t c_lflag;    /*本地模式标志,unsigned short*/  cc_t  c_line;        /*线路规程,unsigned char*/cc_t  c_cc[NCCS];    /*控制字符,unsigned char*/speed_t c_ispeed;    /*输入波特率,unsigned int*/speed_t c_ospeed;    /*输出波特率,unsigned int*/
};

波特率设置。

/*波特率设置*/
struct termios Opt = {0};
tcgetattr(fd, &Opt);            /*获得当前设备模式与终端相关的参数,fd=0标准输入*/
cfsetispeed(&Opt, B19200);      /*设置结构termios输入波特率为19200Bps*/
cfsetospeed(&Opt, B19200);      /*设置结构termios输出波特率为19200Bps*/
tcsetattr(fd, TCANOW, &Opt);    /*设置终端参数,TCANOW修改立即发生*//*设置串口通信速率*/
int set_speed(int fd, int speed)
{int index = 0;int status = 0;int speed_arr[] = {B38400, B19200,B9600, B4800,B2400, B1200,B300, B38400,B19200, B9600,B4800, B2400,B1200, B300,};int name_arr[] = {38400, 19200,9600, 4800,2400, 1200,300, 38400, 19200, 9600,4800, 2400,1200, 300,};struct termios Opt = {0};tcgetattr(fd, &Opt);for(index = 0; index < sizeof(speed_arr)/sizeof(int); index++){if(speed == name_arr[index]){/*tcflush函数刷清(抛弃)输入缓存(终端驱动程序已接收到,但用户程序尚未读)或输出缓存(用户程序已经写,但尚未发送)。queue参数应是下列三个常数之一:TCIFLUSH刷清输入队列,TCOFLUSH刷清输出队列,TCIOFLUSH刷清输入输出队列。*//*设置前flush*/tcflush(fd, TCIOFLUSH);cfsetispeed(&Opt, speed_arr[index]);cfsetospeed(&Opt, speed_arr[index]);/*tcsetattr(串口描述符, 立即使用或者其他标示, 指向termios的指针),通过tcsetattr函数把新的属性设置到串口上。*/status = tcsetattr(fd, TCSANOW, &Opt);if(0 != status){       perror("tcsetattr COM error");return -1;}/*设置后flush*/tcflush(fd, TCIOFLUSH);return 0;}}return 0;
}

校验位和停止位设置。

/*校验位和停止位设置*/
struct termios Opt = {0};/*无校验,8位*/
Opt.c_cflag &= ~PARENB;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= ~CS8;/*奇校验(Odd),7位*/
Opt.c_cflag |= ~PARENB;
Opt.c_cflag &= ~PARODD;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= ~CS7;/*偶校验(Even),7位*/
Opt.c_cflag &= ~PARENB;
Opt.c_cflag |= ~PARODD;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= ~CS7;/*Space校验,7位*/
Opt.c_cflag &= ~PARENB;
Opt.c_cflag &= ~CSTOPB;
Opt.c_cflag &= &~CSIZE;
Opt.c_cflag |= CS8;/*设置数据位、停止位和校验位*/
int set_parity(int fd, int databits, int stopbits, int parity)
{struct termios Opt = {0};if(0 != tcgetattr(fd, &Opt)){perror("tcgetattr COM error");return -1;}/*设置数据位,取值为7或8*/Opt.c_cflag &= ~CSIZE;switch(databits){case 7:Opt.c_cflag |= CS7;break;case 8:Opt.c_cflag |= CS8;break;default:fprintf(stderr, "Unsupported data size\n");return -1;break;}/*设置停止位,取值为1或2*/switch(stopbits){case 1:Opt.c_cflag &= ~CSTOPB;break;case 2:Opt.c_cflag |= CSTOPB;break;default:fprintf(stderr,"Unsupported stop bits\n");return -1;break;}/*设置校验位,取值为E,N,O,S*/switch(parity){case 'e':case 'E':{Opt.c_cflag |= PARENB; /*Enable parity*/Opt.c_cflag &= ~PARODD; /*转换为偶效验*/Opt.c_iflag |= INPCK; /*Disnable parity checking*/}break;case 'n':case 'N':{Opt.c_cflag &= ~PARENB; /*Clear parity enable*/Opt.c_iflag &= ~INPCK; /*Enable parity checking*/}break;case 'o':case 'O':{Opt.c_cflag |= (PARODD | PARENB); /*设置为奇效验*/Opt.c_iflag |= INPCK; /*Disnable parity checking*/}break;case 's': /*as no parity*/case 'S': /*as no parity*/{Opt.c_cflag &= ~PARENB;Opt.c_cflag &= ~CSTOPB;}break;default:fprintf(stderr, "Unsupported parity\n");return -1;break;}/*设置结构体输入校验位*/if('n' != parity){Opt.c_iflag |= INPCK;}tcflush(fd, TCIFLUSH);Opt.c_cc[VTIME] = 150; /*设置超时15秒*/Opt.c_cc[VMIN] = 0; /*更新结构体并立即执行*/if(0 != tcsetattr(fd, TCSANOW, &Opt)){perror("tcsetattr COM error");return -1;}return 0;
}

如果不是开发终端之类的,串口仅用于传输数据,不需要处理数据,可将串口设置为原始模式(Raw Mode)进行通讯。

/*原始模式设置*/
struct termios Opt = {0};
Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
Opt.c_oflag &= ~OPOST; /*Output*/

(4)串口读写:读写串口需要使用标准的文件读写函数read和write。
(5)串口关闭:关闭串口需要使用标准的文件关闭函数close。

3.demo

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>  int main(int argc, char const *argv[])
{int fd = 0;int nread = 0;char buff[512] = {0};char *dev = "/dev/ttyS0"; /*串口0*/fd = open_dev(dev);set_speed(fd, 19200);set_parity(fd, 8, 1, 'N');while(1){nread = read(fd, buff, 512);buff[nread+1] = '\0';printf("fd:%d, nread:%d, buff:%s\n", fd, nread, buff);}close(fd);return 0;
}

4.其他
(1)虚拟机下使用串口的方法:VMware默认串口设备是未添加的,通过VMware将设备加入即可正常使用串口。虚拟机串口打开后,可能会占用Windows下的串口。此外,虚拟机的串口收发速度比正常速度要慢很多。
(2)消除Linux串口收发的一些规则
Linux串口收发有许多模式,比如:
①接收返回模式,如果串口没有接收到数据,read()函数不返回;
②数据接收\n才返回接收的数据,否则read()函数返回0;
③特殊字符解析问题,部分特殊字符接收或发送时会被屏蔽或者转义;
④接收反馈,串口接收到数据后会立即将该数据发送出去。
解决方法是:将串口参数初始化,可消除默认规则,如果需要保留部分参数,参考如下。

struct termios Opt;/*消除收发模式规则*/
Opt.c_lflag = 0;
Opt.c_oflag = 0;
Opt.c_iflag = 0;/*消除字符屏蔽规则*/
Opt.c_cc[VINTR] = 0;        /* Ctrl-c*/
Opt.c_cc[VQUIT] = 0;        /* Ctrl-\ */
Opt.c_cc[VERASE] = 0;       /* del */
Opt.c_cc[VKILL] = 0;        /* @ */
Opt.c_cc[VEOF] = 4;         /* Ctrl-d */
Opt.c_cc[VTIME] = 5;        /* inter-character timer, timeout VTIME*0.1 */
Opt.c_cc[VMIN] = 0;         /* blocking read until VMIN character arrives */
Opt.c_cc[VSWTC] = 0;        /* '\0' */
Opt.c_cc[VSTART] = 0;       /* Ctrl-q */
Opt.c_cc[VSTOP] = 0;        /* Ctrl-s */
Opt.c_cc[VSUSP] = 0;        /* Ctrl-z */
Opt.c_cc[VEOL] = 0;         /* '\0' */
Opt.c_cc[VREPRINT] = 0;     /* Ctrl-r */
Opt.c_cc[VDISCARD] = 0;     /* Ctrl-u */
Opt.c_cc[VWERASE] = 0;      /* Ctrl-w */
Opt.c_cc[VLNEXT] = 0;       /* Ctrl-v */
Opt.c_cc[VEOL2] = 0;        /* '\0' */

http://www.ppmy.cn/news/560924.html

相关文章

飞思卡尔MC9S12G64串口发送接收驱动

因为之前刚入职&#xff0c;对串口调试不了解&#xff0c;下面整理一下书上的串口程序。 移植性还比较强 使用说明&#xff1a;MC9S12系列的串口有两种查询方式 1》使用中断方式查询 2》在主函数中使用轮询的方式的方法进行查询 这两种方法在下面函数中都有体现&#xff0c;需…

C#读取RS232串口扫描枪

扫描对于工业商业的主要输入设备很常见&#xff0c;与扫描枪的通讯也非常简单。之前看到网上有很多人问&#xff0c;但大多说人没有给出确切的回答&#xff0c;其实也就是源代码啦。 我刚好做了一个项目用到了这种扫描枪&#xff0c;现在把做的步骤和代码上传上来&#xff0c;…

CH340串口驱动(包含各系统平台)

CH340转串口芯片支持的平台驱动齐全&#xff0c;支持 Windows/Linux/Android/MacOS/WinCE 等操作系统。各平台下驱动官网链接和说明如下&#xff0c;各平台的安装与使用问题可参见其他博文。 Windows驱动 下载链接&#xff1a;CH340/CH341 Windows 驱动链接http://www.wch.cn/…

Linux——进程控制:创建、终止、等待、替换

进程创建 fork #include <unistd.h> pid_t fork(void);操作系统做了什么&#xff1f; 调用fork之后&#xff0c;内核的工作&#xff1a; 分配新的内存块和内核数据结构给子进程将父进程部分数据结构内容拷贝至子进程添加子进程到系统进程列表当中fork返回&#xff0c…

服务器系统怎么打驱动精灵,win7系统如何使用驱动精灵?教你在win7系统使用驱动精灵的方法...

驱动精灵是一款驱动管理软件&#xff0c;功能性非常强&#xff0c;可以帮助用户安装驱动、备份驱动、卸载驱动等等。好多小伙伴在win7系统上安装驱动精灵却不知道如何使用&#xff1f;网上也有很多相关教程&#xff0c;但不够详细&#xff0c;因此&#xff0c;这里系统城小编来…

微波炉控制器的设计(EDA课程设计)

微波炉控制器的设计&#xff08;Quartus 9.1&#xff09; 1.设计一个具有定时和信息显示功能的微波炉控制器。 2.要求改微波炉控制器能够在任意时刻取消当前工作&#xff0c;复位为初始状态。 3.可以根据需要设置烹调时间的长短&#xff0c;系统最长的烹调时间为59分59秒&…

蠕动泵的常见参数及常用电机驱动芯片---Trinamic(TMC)

蠕动泵是一种可控制流速的液体输送装置&#xff0c;因为可以稳定控制流体的流速&#xff1b;无污染输送流体&#xff1b;维护简单便宜&#xff0c; 且具有输送精度高、较强的耐腐蚀性、剪切作用小、操作简单及易于维护等优势&#xff0c; 所以广泛应用在科研、制药、化工、环…

服务器系统安装蓝牙驱动,win10蓝牙驱动怎么安装?-win10蓝牙驱动的安装教程 - 河东软件园...

蓝牙是现在设备连接中使用的比较广泛的硬件之一&#xff0c;除了需要硬件支持以外&#xff0c;我们的电脑上也需要安装蓝牙驱动&#xff01;在我们将电脑升级到Win10之后&#xff0c;系统中是自带了蓝牙驱动的&#xff0c;不过据很多使用正式版系统的用户反映&#xff0c;电脑中…