Linux C/C++串口读写_linux c++ 串口收发-程序员宅基地

技术标签: 其他  

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' */
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/AAA375/article/details/100096490

智能推荐

k8s自定义资源CRD-程序员宅基地

文章浏览阅读266次。在K8S系统扩展点中,开发者可以通过CRD(CustomResourceDefinition)来扩展K8SAPI,其功能主要由APIExtensionServer负责。使用kubernetes的 CustomResourceDefinition 就可以定义出属于我们自己的 kind.使⽤CRD扩展资源分为三步:注册⾃定义资源:开发者需要通过K8S提供的⽅式注册⾃定义资源,即通过CRD进⾏注册,注册之后,K8S就知道我们⾃定义资源的存在了,然后我们就可以像使⽤K8S内置资源⼀样使⽤⾃定义资源(CR)

lombok---类上使用@Getter和@Setter_@getter 依赖-程序员宅基地

文章浏览阅读452次。1.添加对lombok的依赖在pom.xml中的<dependencies>下添加一下代码 <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>2.sts安装插件(1)在项目文件点击右键 -> Maven -> Updata Project(2)选中你的项目,点击ok(这里是确保lo_@getter 依赖

Android 在后台无法启动Activity_此应用没有可供打开的activity 小黑屋-程序员宅基地

文章浏览阅读1.4w次,点赞14次,收藏46次。前言前几天接触的一个闹钟APP项目,闹钟触发从后台启动一个activity,执行之后的响铃操作,但是却失效了,闹钟并没有按时响铃。最后发现是系统拦截了从后台启动的Activity。具体原因一、AndroidQ从后台启动Activity的限制Android 10 (API 级别 29) 及更高版本对后台应用可启动 Activity进行限制。Android10中, 当App的Activit..._此应用没有可供打开的activity 小黑屋

【推荐算法论文阅读】BERT4Rec: Sequential Recommendation with Bidirectional Encoder Representations from Trans-程序员宅基地

文章浏览阅读1.8k次。一、背景之前基于RNN的推荐模型都是按照从左到右单向建模的,单向结构限制了用户行为序列中隐藏表示的能力——它们通常假定一个严格有序的序列,而这并不总是实用的。本文提出了 bert4rec,应用deep biderectional self-attention 来对用户的行为序列进行建模的。为了避免信息泄露,高效的训练双向模型,我们采用Cloze目标来进行顺序推荐,预测序列中的随机mask项,通过对其上下文的联合条件进行预测序列中随机mask的items。二、Bert4Rec1. 问题定义U={u1_bert4rec: sequential recommendation with bidirectional encoder representatio

以太网PCB布局布线_以太网pcb布线要求-程序员宅基地

文章浏览阅读9.7k次,点赞17次,收藏157次。我们现今使用的网络接口均为以太网接口,目前大部分处理器都支持以太网口。目前以太网按照速率主要包括10M、10/100M、1000M三种接口,10M应用已经很少,基本为10/100M所代替。目前以太网接口类型主要采用双绞线的RJ45接口,且基本应用于工控领域,因工控领域的特殊性,所以我们对以太网的器件选型以及PCB设计相当考究。从硬件的角度看,以太网接口电路主要由MAC(Media Access C..._以太网pcb布线要求

PHP||PHP概述与开发运行环境搭建&PHP数组的应用-程序员宅基地

文章浏览阅读922次,点赞26次,收藏18次。1.简述PHP程序运行过程中,PHP预处理器、Web服务器和数据库各自的功能。① PHP预处理器:实现对PHP文件的解析和编译,将PHP程序中的代码解释为文本信息。② Web服务器:主要用于存储大量的网络资源(例如图片、视频等资源)供用户访问和处理HTTP请求。③ 数据库:存储和管理数据的容器。2.常见的Web服务器和数据库服务器都有哪些?① Web服务器:Apache、Nginx、IIS。

随便推点

计算机网络两个基本问题,计算机网络技术包含的两个主要技术是什么-程序员宅基地

文章浏览阅读2.4k次。计算机网络技术包含的两个主要技术是计算机技术和通信技术。计算机网络具有共享硬件、软件和数据资源的功能,具有对共享数据资源集中处理及管理和维护的能力。本文操作环境:windows10系统、thinkpad t480电脑。(学习视频分享:编程入门)计算机网络技术是通信技术与计算机技术相结合的产物。计算机网络是按照网络协议,将地球上分散的、独立的计算机相互连接的集合。连接介质可以是电缆、双绞线、光纤、微..._计算机网络格式包含的两个主要

創新組合型的架構設計(Part-5):以架構設計推動Agile敏捷_創新部架構-程序员宅基地

文章浏览阅读759次。相關文件:1.高老師的=>A段架構設計_雋語集2.高老師的新書《思考軟件,創新設計:A段架構師的思考技術》==>請看目錄 3.欢迎访问 =>高老师的ADT技术论坛EE EE _創新部架構

python调用海康工业相机并用opencv显示 出现no data[0x80000007]-程序员宅基地

文章浏览阅读2.7k次,点赞4次,收藏15次。前一段时间做项目用的是海康工业相机,想在python代码中调用相机拍照,参考了这篇文章:python调用海康工业相机并用opencv显示(整体实现)_J&A~ing的博客-程序员宅基地_python调用海康工业相机代码大致是需要循环调用相机拍照,以拍到的照片作为条件调用Vision Master软件特定模板。在进行一次循环之后,发现运行代码出现了如下问题:no data[0x80000007]通过查询海康的官方文件,发现状态码0x80000007表示无数据。_no data[0x80000007]

融合 反走样 雾_计算机图形学雾化和反走样定义-程序员宅基地

文章浏览阅读830次。15.1、融合  15.1.1 Alpha值与融合(Blending)  Alpha值在前面几章中已经提到过,但是几乎所有例程都将它设置为1.0,没有详细讨论它为其它值时的情况。融合,是本章的重点,它是透明技术、数字合成和计算机绘画技术的核心。固名思义,融合就是指两种颜色各分量依据一定的比例混在一起合二为一。而这种比例就来源于Alpha值,即RGBA中的A或(r、g、b、a)中的a值,通常称a_计算机图形学雾化和反走样定义

python视觉识别定位_机器视觉以及验证码识别-程序员宅基地

文章浏览阅读821次。机器视觉从 Google 的无人驾驶汽车到可以识别假钞的自动售卖机,机器视觉一直都是一个应用广 泛且具有深远的影响和雄伟的愿景的领域。我们将重点介绍机器视觉的一个分支:文字识别,介绍如何用一些 Python库来识别和使用在线图片中的文字。我们可以很轻松的阅读图片里的文字,但是机器阅读这些图片就会非常困难,利用这种人类用户可以正常读取但是大多数机器人都没法读取的图片,验证码 (CAPTCHA)就出现..._pytesseract定位识别

三角函数的振幅、周期、频率_三角函数求振幅-程序员宅基地

文章浏览阅读1.7k次。三角函数的频率f=1/T: wx+t表示三角函数的。举个栗子:p(t)=90+20sin(160πt)在w>0的条件下:A:表示。_三角函数求振幅

推荐文章

热门文章

相关标签