Linux下串口通信编程
07实验七 Linux环境下的串行通信实验
连接驱动器的使能端,使得当RTS设置成高(逻辑1)时,有效RS485驱动器;设置RTS为低 时,使驱动器处于三态,这时候实际上从总线上断开了驱动器,从而允许其他节点可以使 用同一传输线。当使用RTS时,必须确保发送数据前将RTS设置成高,在发送完数据的最 后一位后,将RTS线设成低。。另一种可选方法是自动发送数据控制。这种方法要求特殊 的电路,当数据传输时自动使能或无效驱动器。它减少了软件开销和程序员的潜在错误。
五、基础知识
串行通信 1、基本原理 串行端口的本质功能是作为CPU和串行设备间的编码转换器。当数据从CPU经过串行 端口发送出去时,字节数据转换为串行的位。在接收数据时,串行的位被转换为字节数据。 串口是系统资源的一部分,应用程序要使用串口进行通信,必须在使用之前向操作系统提 出资源申请要求(打开串口),通信完成后必须释放资源(关闭串口)。 2、串口通信的基本任务 (1) 实现数据格式化:因为来自CPU的是普通的并行数据,所以,接口电路应具有实 现不同串行通信方式下的数据格式化的任务。在异步通信方式下,接口自动生成起止式的 帧数据格式。在面向字符的同步方式下,接口要在待传送的数据块前加上同步字符。 (2) 进行串-并转换:串行传送,数据是一位一位串行传送的,而计算机处理数据是 并行数据。所以当数据由计算机送至数据发送器时,首先把串行数据转换为并行数才能送 入计算机处理。因此串并转换是串行接口电路的重要任务。 (3) 控制数据传输速率:串行通信接口电路应具有对数据传输速率——波特率进行选 择和控制的能力。 (4) 进行错误检测:在发送时接口电路对传送的字符数据自动生成奇偶校验位或其他 校验码。在接收时,接口电路检查字符的奇偶校验或其他校验码,确定是否发生传送错误。 (5) 进行TTL与EIA电平转换:CPU和终端均采用TTL电平及正逻辑,它们与EIA采用
linux串口编程参数配置详解
linux串口编程参数配置详解1.linux串口编程需要的头文件#include <stdio.h> //标准输入输出定义#include <stdlib.h> //标准函数库定义#include <unistd.h> //Unix标准函数定义#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h> //文件控制定义#include <termios.h> //POSIX中断控制定义#include <errno.h> //错误号定义2.打开串口串口位于/dev中,可作为标准文件的形式打开,其中:串口1 /dev/ttyS0串口2 /dev/ttyS1代码如下:int fd;fd = open(“/dev/ttyS0”, O_RDWR);if(fd == -1){Perror(“串口1打开失败!”);}//else//fcntl(fd, F_SETFL, FNDELAY);除了使用O_RDWR标志之外,通常还会使用O_NOCTTY和O_NDELAY这两个标志。
O_NOCTTY:告诉Unix这个程序不想成为“控制终端”控制的程序,不说明这个标志的话,任何输入都会影响你的程序。
O_NDELAY:告诉Unix这个程序不关心DCD信号线状态,即其他端口是否运行,不说明这个标志的话,该程序就会在DCD信号线为低电平时停止。
3.设置波特率最基本的串口设置包括波特率、校验位和停止位设置,且串口设置主要使用termios.h头文件中定义的termios结构,如下:struct termios{tcflag_t c_iflag; //输入模式标志tcflag_t c_oflag; //输出模式标志tcflag_t c_cflag; //控制模式标志tcflag_t c_lflag; //本地模式标志cc_t c_line; //line disciplinecc_t c_cc[NCC]; //control characters}代码如下:int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, B384 00, B19200, B9600, B4800, B2400, B1200, B300, };int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9 600, 4800, 2400, 1200, 300, };void SetSpeed(int fd, int speed){int i;struct termios Opt; //定义termios结构if(tcgetattr(fd, &Opt) != 0){perror(“tcgetattr fd”);return;}for(i = 0; i < sizeof(speed_arr) / sizeof(int); i++){if(speed == name_arr[i]){tcflush(fd, TCIOFLUSH);cfsetispeed(&Opt, speed_arr[i]);cfsetospeed(&Opt, speed_arr[i]);if(tcsetattr(fd, TCSANOW, &Opt) != 0){perror(“tcsetattr fd”);return;}tcflush(fd, TCIOFLUSH);}}}注意tcsetattr函数中使用的标志:TCSANOW:立即执行而不等待数据发送或者接受完成。
linux_虚拟串口实现方法_概述及解释说明
linux 虚拟串口实现方法概述及解释说明1. 引言1.1 概述本文将介绍Linux下实现虚拟串口的方法,并对每种方法进行解释说明。
虚拟串口指的是一种软件仿真的串口设备,可以模拟物理串口的功能,实现数据的收发和传输。
在Linux系统中,使用虚拟串口可以满足一些特定场景下的需求,如开发、测试和调试等。
1.2 文章结构本文按照以下结构进行组织:- 第一部分为引言,对文章进行概述,并介绍文章的结构和目标;- 第二部分将介绍虚拟串口的背景知识,包括串口通信原理、虚拟串口定义与作用以及Linux中虚拟串口的应用场景;- 第三部分将详细介绍Linux下实现虚拟串口的三种方法:内核模块方式、用户空间模拟方式和设备树(DT)方式;- 第四部分将对每种实现方法进行解释说明,包括其原理、特点和适用情况;- 第五部分为总结与展望,对文章内容进行总结并展望未来发展方向。
1.3 目的本文旨在提供一个全面且清晰的介绍Linux下实现虚拟串口方法的资料,帮助读者理解虚拟串口的概念和原理,并根据实际需求选择合适的实现方法。
通过阅读本文,读者将了解到不同实现方法的优缺点,以及它们在不同场景下的应用情况。
同时,本文也对未来虚拟串口技术的发展进行展望。
2. 虚拟串口的背景:2.1 串口通信的基本原理:串口是一种用于在计算机和外部设备之间进行数据传输的通信接口。
它通过一个物理连接,使用一组控制信号和数据信号来实现双向通信。
串口通信具有简单、可靠、广泛应用等特点,因此在许多领域都得到了广泛应用,如电脑与打印机、调制解调器、路由器等设备之间的连接。
2.2 虚拟串口的定义与作用:虚拟串口是对物理串口进行仿真或模拟的一种技术。
它通过软件方式模拟了一个不存在的串行接口,使得应用程序可以通过虚拟串口与外部设备进行通信。
虚拟串口具有操作灵活、易于扩展等特点,可以提供与物理串口相似或更强大的功能。
2.3 虚拟串口在Linux中的应用场景:在Linux系统中,虚拟串口广泛应用于各种嵌入式系统开发和调试场景。
嵌入式操作系统Linux中的串口应用编程
I
嵌入式操作系统 L x 的审口应用编程 iu 中 n
■ 厦 门 大 学 唐 建 东 卢 贵 主
针 对 嵌 入 式 Linux 操 作 系统 的 特 点 , 分 析 在 该 系统 下 串行 通 信 口编 程 控 制 的 方 法 , 总 结 程 序
摘
要
设 计 的 步 骤 ; 在 嵌 入 式 Linux 系 统 上 , 编 写控 制 程 序 , 成 功 地 实 现 嵌 入 式 系统 与微 机 系 统
4
Te s I s r m e s, U SA .TM ¥3 0C X / X / xa n t u nt 2 l C2
更详 细 的 内容 在 此 不 再 多述 , 本 人将 另 文 介 绍 。■ _
参考 文献
l 彭 启 琮 , 李 玉 柏 ,管 庆 .DS P与 实 时 数 字 信 号 处 理 .成 都 :电 子 科 技 大 学 出版 社 , l 9 5 9 2 戴 明 桢 .数 字 信 号 处理 的 硬 件 实现 . 北 京 :
根 据 不 同 条 件 控 制 不 同 的 设 备 。 基 于 美 国 电 子 工 业 协 会 E A 的 串 口通 信 标 准 一 I RS 3 , 是 目前 广 泛 使 22 用 的 设备 控 制 通 信 接 口 。在 嵌 入 式 系统 中实 现 串 口 通 信 , 可 延 伸 系 统 的 应 用 触 角 , 扩 大 系 统 的 数 据 采
# k od iln m e il tpe u b r um b r m n f e a f ey n m e n l e2
1 嵌 入式 操作 系统 L n x串 口模 块 u i
L n x操 作 系 统 的 主 要 优 点 是 稳 定 、 内 核 可 重 iu 新 编 译 、 提 供 开 放 的 内 核 源 代 码 。 Li u 内 核 采 用 n x
嵌入式linux串口应用程序编写流程
嵌入式linux串口应用程序编写流程嵌入式Linux系统提供了丰富的串口接口,可以通过串口与其他设备进行通信,这为开发嵌入式系统提供了很多可能性。
下面是编写嵌入式Linux串口应用程序的流程:1. 确定串口设备:首先要确定要使用的串口设备,可以使用命令`ls /dev/tty*`来查看系统中可用的串口设备列表。
根据需要选择合适的串口设备。
2. 打开串口设备:在Linux系统中,使用文件的方式来操作串口设备。
可以使用C语言中的open函数来打开串口设备文件,并返回串口设备的文件描述符。
例如:`int serial_fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);`。
其中,`O_RDWR`表示以读写模式打开串口设备,`O_NOCTTY`表示打开设备后不会成为该进程的控制终端,`O_NDELAY`表示非阻塞模式。
3. 配置串口参数:打开串口设备后,需要配置串口参数,包括波特率、数据位、停止位、校验位等。
可以使用C语言中的termios库来进行串口参数的配置。
例如:```cstruct termios serial_config;tcgetattr(serial_fd, &serial_config);cfsetispeed(&serial_config, B115200);cfsetospeed(&serial_config, B115200);serial_config.c_cflag |= CS8;serial_config.c_cflag &= ~PARENB;serial_config.c_cflag &= ~CSTOPB;tcsetattr(serial_fd, TCSANOW, &serial_config);```上述代码将波特率设置为115200,数据位设置为8位,无校验位,一个停止位。
Linux下串口通信详解(上)打开串口和串口初始化详解
Linux下串口通信详解(上)打开串口和串口初始化详解Linux下串口通信主要有下面几个步骤串口通信流程图下面我会一一介绍这几个步骤。
1.打开串口代码(串口为ttyUSB0)[java] view plain copy1.//打开串口2.int open_port(void)3.{4.int fd;5.6.fd=open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NON BLOCK);//O_NONBLOCK设置为非阻塞模式,在read时不会阻塞住,在读的时候将read放在while循环中,下一节篇文档将详细讲解阻塞和非阻塞7.// printf("fd=%d\n",fd);8.9.if(fd==-1)10.{11.perror("Can't Open SerialPort");12.}13.14.return fd;15.}打开串口时也可以多加一些内容,比如判断串口为阻塞状态、测试是否为终端设备等,这些是必要的,所以较上面的基本的打开串口的代码,更加完整健壮一些的代码流程如下所示:打开串口较完整流程图代码:[cpp] view plain copy1./**2.* open port3.* @param fd4.* @param comport 想要打开的串口号5.* @return 返回-1为打开失败6.*/7.int open_port(int fd,int comport)8.{9.char *dev[]={"/dev/ttyUSB0","/dev/ttyS1","/dev/ttyS2"};10.11.if (comport==1)//串口112.{13.fd = open( "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_N DELAY);14.if (-1 == fd)15.{16.perror("Can't Open Serial Port");17.return(-1);18.}19.}20.else if(comport==2)//串口221.{22.fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDEL AY); //没有设置<span style="font-family: Arial, Helvetica, sans-serif;">O_NONBLOCK非阻塞模式,也可以设置为非阻塞模式,两个模式在下一篇博客中具体说明</span>23.24.if (-1 == fd)25.{26.perror("Can't Open Serial Port");27.return(-1);28.}29.}30.else if (comport==3)//串口331.{32.fd = open( "/dev/ttyS2", O_RDWR|O_NOCTTY|O_NDEL AY);33.if (-1 == fd)34.{35.perror("Can't Open Serial Port");36.return(-1);37.}38.}39./*恢复串口为阻塞状态*/40.if(fcntl(fd, F_SETFL, 0)<0)41.printf("fcntl failed!\n");42.else43.printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));44./*测试是否为终端设备*/45.if(isatty(STDIN_FILENO)==0)46.printf("standard input is not a terminal device\n");47.else48.printf("isatty success!\n");49.printf("fd-open=%d\n",fd);50.return fd;51.}关键函数解释:功能描述:用于打开或创建文件,成功则返回文件描述符,否则返回-1,open返回的文件描述符一定是最小的未被使用的描述符[cpp] view plain copy1.#include<fcntl.h>2.int open(const char *pathname, int oflag, ... );参数解释:pathname:文件路径名,串口在linux中被看做是一个文件oflag:一些文件模式选择,有如下几个参数可以设置•O_RDONLY只读模式•O_WRONLY只写模式•O_RDWR读写模式上面三个参数在设置的时候必须选择其中一个下面的是可选的•O_APPEND每次写操作都写入文件的末尾•O_CREAT如果指定文件不存在,则创建这个文件•O_EXCL如果要创建的文件已存在,则返回 -1,并且修改 errno 的值•O_TRUNC如果文件存在,并且以只写/读写方式打开,则清空文件全部内容•O_NOCTTY如果路径名指向终端设备,不要把这个设备用作控制终端。
linux下的串口通信原理及编程实例
linux下的串⼝通信原理及编程实例linux下的串⼝通信原理及编程实例⼀、串⼝的基本原理1 串⼝通讯串⼝通讯(Serial Communication),是指外设和计算机间,通过数据信号线、地线等,按位进⾏传输数据的⼀种通讯⽅式。
串⼝是⼀种接⼝标准,它规定了接⼝的电⽓标准,没有规定接⼝插件电缆以及使⽤的协议。
2 串⼝通讯的数据格式 ⼀个字符⼀个字符地传输,每个字符⼀位⼀位地传输,并且传输⼀个字符时,总是以“起始位”开始,以“停⽌位”结束,字符之间没有固定的时间间隔要求。
每⼀个字符的前⾯都有⼀位起始位(低电平),字符本⾝由7位数据位组成,接着字符后⾯是⼀位校验位(检验位可以是奇校验、偶校验或⽆校验位),最后是⼀位或⼀位半或⼆位停⽌位,停⽌位后⾯是不定长的空闲位,停⽌位和空闲位都规定为⾼电平。
实际传输时每⼀位的信号宽度与波特率有关,波特率越⾼,宽度越⼩,在进⾏传输之前,双⽅⼀定要使⽤同⼀个波特率设置。
3 通讯⽅式单⼯模式(Simplex Communication)的数据传输是单向的。
通信双⽅中,⼀⽅固定为发送端,⼀⽅则固定为接收端。
信息只能沿⼀个⽅向传输,使⽤⼀根传输线。
半双⼯模式(Half Duplex)通信使⽤同⼀根传输线,既可以发送数据⼜可以接收数据,但不能同时进⾏发送和接收。
数据传输允许数据在两个⽅向上传输,但是,在任何时刻只能由其中的⼀⽅发送数据,另⼀⽅接收数据。
因此半双⼯模式既可以使⽤⼀条数据线,也可以使⽤两条数据线。
半双⼯通信中每端需有⼀个收发切换电⼦开关,通过切换来决定数据向哪个⽅向传输。
因为有切换,所以会产⽣时间延迟,信息传输效率低些。
全双⼯模式(Full Duplex)通信允许数据同时在两个⽅向上传输。
因此,全双⼯通信是两个单⼯通信⽅式的结合,它要求发送设备和接收设备都有独⽴的接收和发送能⼒。
在全双⼯模式中,每⼀端都有发送器和接收器,有两条传输线,信息传输效率⾼。
显然,在其它参数都⼀样的情况下,全双⼯⽐半双⼯传输速度要快,效率要⾼。
Linux串口通信编程
2) 设置属性:奇偶校验位、数据位、停止位。
主要设置<termbits.h>中的termios3) 打开、关闭和读写串口。
串口作为设备文件,可以直接用文件描述符来进行网上的一个例子:/*串口设备无论是在工控领域,还是在嵌入式设备领域,应用都非常广泛。
而串口编程也就显得必不可少。
偶然的一次机会,需要使用串口,而且操作系统还要求是Linux,因此,趁着这次机会,综合别人的代码,进行了一次整理和封装。
具体的封装格式为C代码,这样做是为了很好的移植性,使它可以在C和C++环境下,都可以编译和使用。
代码的头文件如下: *//////////////////////////////////////////////////////////////////// //////////////filename:stty.h#ifndef__STTY_H__#define__STTY_H__//包含头文件#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<termios.h>#include<errno.h>#include<pthread.h>//// 串口设备信息结构typedef struct tty_info_t{int fd;// 串口设备IDpthread_mutex_t mt;// 线程同步互斥对象char name[24];// 串口设备名称,例:"/dev/ttyS0"struct termios ntm;// 新的串口设备选项struct termios otm;// 旧的串口设备选项}TTY_INFO;//// 串口操作函数TTY_INFO *readyTTY(int id);int setTTYSpeed(TTY_INFO *ptty,int speed);int setTTYParity(TTY_INFO *ptty,int databits,int parity,int st opbits);int cleanTTY(TTY_INFO *ptty);int sendnTTY(TTY_INFO *ptty,char*pbuf,int size);int recvnTTY(TTY_INFO *ptty,char*pbuf,int size);int lockTTY(TTY_INFO *ptty);int unlockTTY(TTY_INFO *ptty);#endif/*从头文件中的函数定义不难看出,函数的功能,使用过程如下:(1)打开串口设备,调用函数setTTYSpeed();(2)设置串口读写的波特率,调用函数setTTYSpeed();(3)设置串口的属性,包括停止位、校验位、数据位等,调用函数setTTYParity ();(4)向串口写入数据,调用函数sendnTTY();(5)从串口读出数据,调用函数recvnTTY();(6)操作完成后,需要调用函数cleanTTY()来释放申请的串口信息接口;其中,lockTTY()和unlockTTY()是为了能够在多线程中使用。
slcan linux c 协议代码
slcan linux c 协议代码SLCAN(Serial Line CAN)是一种用于串行线路上的CAN (Controller Area Network)通信协议。
本文将介绍SLCAN在Linux系统下的C语言实现。
我们来了解一下CAN总线和SLCAN协议的基本概念。
CAN总线是一种常用于汽车、工业控制和嵌入式系统等领域的通信协议,它具有高可靠性和实时性的特点。
CAN总线上的设备可以通过发送和接收CAN帧来进行通信。
SLCAN协议是一种在串行线路上模拟CAN总线通信的协议,它将CAN 帧转换为串行数据进行传输。
在Linux系统中,我们可以使用C语言编写SLCAN协议的实现代码,以实现与CAN设备的通信。
在C语言代码实现中,我们需要使用串口通信库来控制串口设备。
在Linux系统中,可以使用termios库来进行串口通信的配置和操作。
通过设置串口的波特率、数据位、停止位和校验位等参数,我们可以实现与CAN设备的通信。
在代码中,我们首先需要打开串口设备,使用open函数打开串口文件,并使用tcgetattr和tcsetattr函数来配置串口的参数。
然后,我们可以使用read和write函数来读取和写入串口数据。
在SLCAN协议中,CAN帧被转换为串行数据进行传输。
我们可以使用一些特定的字符来表示CAN帧中的各个字段。
例如,字符's'表示“开始”,字符't'表示“帧类型”,字符'l'表示“数据长度”,字符'z'表示“数据”,字符'G'表示“过滤器”,字符'W'表示“写入”,字符'F'表示“帧”,字符'A'表示“确认”,字符'V'表示“版本”。
在C语言代码中,我们可以使用switch语句来处理接收到的串口数据。
根据接收到的数据类型,我们可以执行相应的操作。
例如,当接收到字符's'时,表示开始传输,我们可以进行一些初始化操作;当接收到字符't'时,表示接收到一个CAN帧,我们可以解析帧类型、数据长度和数据,并进行相应的处理;当接收到字符'W'时,表示写入数据,我们可以将数据发送给CAN设备。
Linux C 串口编程
Linux C 串口编程arch/arm/include/asm/termbits.hstruct termios {tcflag_t c_iflag; /* input mode flags */tcflag_t c_oflag; /* output mode flags */tcflag_t c_cflag; /* control mode flags */tcflag_t c_lflag; /* local mode flags */cc_t c_line; /* line discipline */cc_t c_cc[NCCS]; /* control characters */ };串口的设置主要是设置struct termios结构体的各成员/***测试的时候应用程序在后台运行./serial_test &*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h> //文件控制定义#include <termios.h>//终端控制定义#include <errno.h>#define DEVICE "/dev/s3c2410_serial0"int serial_fd = 0;//打开串口并初始化设置init_serial(void){serial_fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);if (serial_fd < 0) {perror("open");return -1;}//串口主要设置结构体termios <termios.h>struct termios options;/**1. tcgetattr函数用于获取与终端相关的参数。
linux下485通讯c语言代码
linux下485通讯c语言代码Linux下的485通讯C语言代码在嵌入式系统和工控领域中,485通讯是一种常见的串行通讯方式。
Linux作为一种常用的操作系统,也提供了相应的接口和工具来支持485通讯。
本文将介绍在Linux下使用C语言实现485通讯的代码。
在开始编写485通讯的C语言代码之前,我们需要先了解一些基本的概念和原理。
485通讯是一种半双工的串行通讯方式,它使用两根信号线进行数据的传输,一根用于发送数据(TX),一根用于接收数据(RX)。
通常情况下,485通讯使用的波特率较低,例如9600bps或者19200bps。
在Linux下,我们可以通过打开串口设备文件来实现485通讯。
串口设备文件的命名规则为/dev/ttySx,其中x表示串口的编号。
例如,/dev/ttyS0表示第一个串口设备,/dev/ttyS1表示第二个串口设备。
我们可以使用open函数来打开串口设备文件,并使用read 和write函数来进行数据的读写操作。
下面是一个简单的示例代码,演示了如何在Linux下使用C语言实现485通讯:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <unistd.h>#include <termios.h>int main(){int fd;char data[10];// 打开串口设备文件fd = open("/dev/ttyS0", O_RDWR);if (fd == -1) {printf("无法打开串口设备文件\n");return -1;}// 配置串口参数struct termios options;tcgetattr(fd, &options);cfsetispeed(&options, B9600); // 设置波特率为9600bps cfsetospeed(&options, B9600);options.c_cflag |= CLOCAL | CREAD;options.c_cflag &= ~CSIZE;options.c_cflag |= CS8;options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;tcsetattr(fd, TCSANOW, &options);// 发送数据strcpy(data, "Hello");write(fd, data, strlen(data));// 接收数据read(fd, data, sizeof(data));printf("接收到的数据:%s\n", data);// 关闭串口设备文件close(fd);return 0;}```上述代码首先通过open函数打开了/dev/ttyS0这个串口设备文件,如果打开失败,则会提示无法打开串口设备文件并退出。
linux c语言编写modbus rtu例程 -回复
linux c语言编写modbus rtu例程-回复如何使用C语言在Linux下编写Modbus RTU例程,以实现数据的读取和写入。
Modbus是一种通信协议,用于在工业自动化系统中实现设备之间的数据通信。
RTU是Modbus协议的一种传输格式,其中数据以二进制形式传输。
在Linux系统中,我们可以使用C语言来编写Modbus RTU例程。
下面将一步一步回答如何实现数据的读取和写入。
第一步:设置串口参数在Linux中,我们可以使用串口来与Modbus设备进行通信。
首先,我们需要设置串口的波特率、数据位、停止位和校验位。
这可以通过C语言中的termios库函数来实现。
c#include <termios.h>int set_serial_port(int fd, int baudrate) {struct termios options;tcgetattr(fd, &options);cfsetispeed(&options, baudrate);cfsetospeed(&options, baudrate);options.c_cflag = (CLOCAL CREAD);options.c_cflag &= ~CSIZE;options.c_cflag = CS8;options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;options.c_cflag &= ~CRTSCTS;tcsetattr(fd, TCSANOW, &options);}以上代码中,`set_serial_port`函数用于设置串口参数。
`fd`参数为串口文件描述符,`baudrate`参数为波特率。
其中,`cfsetispeed`和`cfsetospeed`函数用于设置输入和输出速度,`CLOCAL`和`CREAD`标志用于使串口工作在本地模式和可读模式,`CS8`标志用于设置8位数据位,`PARENB`标志用于禁用奇偶校验,`CSTOPB`标志用于设置停止位为1位,`CRTSCTS`标志用于禁用硬件流控制。
基于linux和Qt的串口通信调试器调的设计及应用
基于linux和Qt的串口通信调试器调的设计及应用摘要:目前基于Linux操作系统的应用开发越来越广泛,Qt是一个跨平台的C++图形用户界面应用程序框架,它可以开发基于Linux上的图形应用程序。
Linux操作系统对串行口提供了很好的支持,为了在Linux系统下能让串口与其它硬件设备方便直观地进行通信,本文介绍了在Ubuntu10.10系统平台Qt-4.7及Qt Creator2.0编程环境下串口调试界面的设计及程序的编写。
关键词:串口通信Linux QT1 Qextserialport 类介绍在Qt类库中并没有特定的串口基础类,现在很多人使用的是第三方写的qextserialport类,它是一个跨平台的串口类,可以很方便地在Qt 中对串口进行读写操作。
本文也使用了该类。
文件下载地址: /projects/qextserialport/files/下载到的文件名为qextserialport-1.2win-alpha。
在linux平台中,我们只需用到其中的四个文件:qextserialbase.cpp和qextserialbase.h以及posix_qextserialport.cpp和posix_qextserialport.h。
其中前两个文件定义了一个QextSerialBase 类,它提供了操作串口所必需的一些变量和函数等;后两个文件定义了一个Posix_QextSerialPort 类,Posix_QextSerialPort类添加了Linux平台下操作串口的一些功能。
2 串口的基本设置串口的基本参数在posix_qextserialport.cpp文件里的构造函数中进行设置,它的最后一个构造函数:Posix_QextSerialPort::Posix_QextSerialPort(const QString & name, const PortSettings&settings, QextSerialBase::QueryMode mode)它共有3个参数,第一个是串口名,第二个是对串口参数的基本设置,第三个是读取串口的方式。
简单的Linux串口通信程序
int fd; /*以读写方式打开串口*/ fd = open( "/dev/ttyS0", O_RDWR); if (-1 == fd){ perror("error"); }
17:43
3. 设置串口
最基本的设置串口包括波特率设置,校验位和停止位设置,数 据位。串口的设置主要是设置struct termios结构体的各成员值。
1
• 实验步骤
– 1.阅读理解源码
• 源码位置:serial\serial.c • 阅读源码方法
– Linux下使用gedit编辑器 – windows下使用SourceInsight软件
– 2.编译应用程序
2
【基础知识】
Linux操作系统从一开始就对串行口提供了很好的支持,为进行
串行通讯提供了大量的函数,本实验主要是为掌握在Linux中进行 串行通讯编程的基本方法。
2. 打开串口
在Linux 下串口文件是位于/dev 下,com1为/dev/ttyS0 ,com2 为/dev/ttyS1 操作系统 串口1 Windows COM1 Linux /dev/ttyS0 串口2 COM2 /dev/ttyS1 USB/RS-232转换器 /dev/ttyUSB0
打开串口是通过使用标准的文件打开函数操作:
struct termios { unsigned short c_iflag; /* 输入模式标志*/ unsigned short c_oflag; /* 输出模式标志*/ unsigned short c_cflag; /* 控制模式标志*/ unsigned short c_lflag; /* local mode flags */ unsigned char c_line; /* line discipline */ unsigned char c_cc[NCC]; /* control characters */ };
基于linux (fedora 17)的QT串口通信实例
2.解压下载的文件到当前目录
# unzip qextserialport-1.2win-alpha.zip
这里不对压缩包内的详细信息及qextserialport类的结构做详细介绍,直接说明需要用到的源文件
linux下:
myCom->setParity(PAR_NONE);
//奇偶校验设置,我们设置为无校验
myCom->setStopBits(STOP_1);
//停止位设置,我们设置为1位停止位
myCom->setFlowControl(FLOW_OFF);
//数据流控制设置,我们设置为无数据流控制
ui(new Ui::MainWindow){
ui->setupUi(this);
//myCom = new Win_QextSerialPort("COM1",QextSerialBase::EventDriven);
//【windows下使用】定义串口对象,指定串口名和查询模式,这里使用事件驱动EventDriven
3.打开Qt Creator集成开发环境,新建工程Qt4 Gui Application ,工程名为com ,其他默认即可。
4.将上述linux下需要用到的4个文件拷贝至com工程目录下,然后将该4个文件添加至工程。
5.将整个工程编译,会报错如下:
error: 'struct PortSettings' has no member named 'Timeout_Sec'
qextserialbase.cpp qextserialbase.h posix_qextserialport.cpp posix_qextserialport.h
在Linux串口编程的一些问题解决
在Linux串口编程的一些问题解决其实在linux下对串口的设置主要是通过termios这个结构体实现的,但是这个结构体却没有提供控制RTS或获得CTS等串口引脚状态的接口,可以通过ioctl系统调用来获得/控制。
获得:ioctl(fd, TIOCMGET, &controlbits);if (controlbits & TIOCM_CTS)printf(“有信号\n”);elseprintf(“无信号\n”);设置:ioctl(fd, TIOCMGET, &ctrlbits);if (flag)ctrlbits |= TIOCM_RTS;elsectrlbits &= ~TIOCM_RTS;ioctl(fd, TIOCMSET, &ctrlbits);其实TIOCM_RTS有效后是把串口的RTS设置为有信号,但串口的电平为低时是有信号,为高时为无信号,和用TIOCMGET获得的状态正好相反,也就是说TIOCMGET/TIOCMSET只是获得/控制串口的相应引脚是否有信号,并不反应当前串口的真实电平高低。
网上许多流行的linux串口编程的版本中都没对c_iflag (termios成员变量)这个变量进行有效的设置,这样传送ASCII码时没什么问题,但传送二进制数据时遇到0x0d,0x11和0x13却会被丢掉。
不用说也知道,这几个肯定是特殊字符,被用作特殊控制了。
关掉ICRNL和IXON选项即可解决。
c_iflag &= ~(ICRNL | IXON);0x0d 回车符CR0x11 ^Q VSTART字符0x13 ^S VSTOP字符ICRNL 将输入的CR转换为NLIXON 使起动/停止输出控制流起作用在《UNIX环境高级编程第二版》第18章第11小节看到把终端I/O设置为原始模式(串口通讯就是终端I/O的原始模式)时输入属性设置为term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);屏蔽了许多属性,怪不得有人说如果是使用串口通讯c_iflag 和c_oflag都设置为0就行了!以下是我的设置的一些重要的串口属性term.c_cflag |= CLOCAL | CREAD;term.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);term.c_oflag &= ~OPOST;term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);static void request_send(void){ioctl(fd,TIOCMGET, &status);status&= ~TIOCM_RTS;// RTS 引脚高电平ioctl(fd,TIOCMSET, &status);}static void clear_send(void) {ioctl(fd,TIOCMGET, &status);status |=TIOCM_RTS; //RTS 引脚低电平ioctl(fd,TIOCMSET, &status);}int main(int argc, char *argv[]){intfd;structtermios opt;intlen;charcmd;//待发送数据charsbuf[128]={"Hello,this is a Serial_Port test!\n\0"};//使用open函数打开串口,获得串口设备文件的文件描述符if((fd=open("/dev/ttyAMA1",O_RDWR| O_NOCTTY))==-1) {perror("Cannot open the serial port");return 1;}tcgetattr(fd, &opt);cfsetispeed(&opt,B115200 ); //指定输入波特率,9600bpscfsetospeed(&opt,B115200); //指定输出波特率,9600bpsopt.c_cflag&=~CSIZE;//将数据位修改为8bitopt.c_cflag|=CS8;opt.c_cflag|=CBAUD;// 无校验opt.c_cflag&= ~PARENB;opt.c_cflag |=IXON|IXOFF|IXANY;// 软件数据流控制//opt.c_cflag|= CRTSCTS;// 硬件数据流控制//opt.c_cflag &=~CRTSCTS; // 不使用数据流控制tcsetattr(fd, TCSANOW , &opt);intstatus;ioctl(fd,TIOCMGET, &status);printf("status = x\n", status);// status &=~TIOCM_RTS; // RTS 引脚高电平status |=TIOCM_RTS; //RTS 引脚低电平printf("status = x\n", status);ioctl(fd,TIOCMSET, &status);ioctl(fd,TIOCMGET, &status);printf("status = x\n", status);while(1){printf("sellect: w|r|q\n"); cmd = getchar(); switch(cmd){case 'w':printf("test write\n");//发送缓冲区字节数定义{len= write(fd,sbuf,strlen(sbuf)); if(len == -1)printf("Wirte sbuf error.\n"); elseprintf("Wirte:%s", sbuf);break;case 'r':printf("test read\n");len = read(fd, sbuf, sizeof(sbuf)); if(len == -1)printf("Read sbuf error.\n");elseprintf("Read:%s", sbuf); break;case 'q':close(fd);return 0;case '\n':break;default:printf("worry cmd!\n");break;}}close(fd);return0;}Linux下串口编程遇到的接收数据错误及原因近日在调试串口的时候发现,另一设备向我ARM板的串口发送0x0d,我接收之后变成了0x0a,这是问题一;另外当对方向我发送一串数据,如果其中有0x11,那么我总是漏收此数,这是问题二。
Linux串口select编程
Linux下串口程序开发串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。
常用的串口是RS-232-C接口(又称EIA RS-232-C)它是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。
它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准"该标准规定采用一个25个脚的DB25连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。
传输距离在码元畸变小于4%的情况下,传输电缆长度应为50英尺。
在linux文件中,所有的设备文件一般都位于/dev下,其中串口一、串口二分别对应的设备名依次为“/dev/ttyS0”、“/dev/ttyS1”,可以查看在/dev下的文件以确认。
在linux下面对于串口的读写就可以通过简单的read、write函数来完成,所不同的是只是需要对串口的其他参数另坐配置。
1.串口编程需要用到的头文件#include <stdio.h> // 标准输入输出定义#include <stdlib.h>#include <fcntl.h> // 文件控制定义,主要完成串口通信中对文件的读写操作#include <unistd.h> // linux标准函数定义#include <sys/ioctl.h>#include <termios.h> // POSIX终端控制定义#include <sys/time.h>#include <sys/types.h>2.串口终端函数2.1打开串口设备int fd;char *device = "/dev/tts/0"; // 设备路径,初始使用UART0for(t=1;t<argc;t++) // 获取程序入口时输入的参数{if(!strcmp(argv[t],"-d") && (argc > (t+1))){device = argv[t+1];}}if(!strcmp(device,"/dev/tts/1")) // 不允许使用UART1,因为它已和PC相连。
linux c语言编写modbus rtu例程
linux c语言编写modbus rtu例程如何在Linux下使用C语言编写Modbus RTU例程。
第一步:了解Modbus RTU协议Modbus RTU是一种用于串行通信的简单且广泛使用的协议,主要用于连接工业自动化设备。
该协议定义了一种在不同设备之间进行数据通信的标准方法。
Modbus RTU协议使用二进制编码来传输数据,其数据格式包括起始位、数据位、停止位和校验位。
第二步:安装C语言开发环境在Linux中使用C语言开发Modbus RTU例程之前,需要安装相应的开发环境。
常见的C语言开发环境包括GCC编译器和Make工具。
可以使用以下命令来检查是否安装了GCC编译器和Make工具:gcc -vmake -v如果显示相应的版本信息,则表示已经安装了开发环境。
如果没有安装,可以使用以下命令来安装:sudo apt-get install build-essential第三步:选择一个Modbus库在开始编写Modbus RTU例程之前,需要选择一个Modbus库来简化开发过程。
在Linux环境下,有许多可用的Modbus库可供选择,如libmodbus和libmodbus-ocaml等。
可以根据自己的需求选择合适的库。
以libmodbus为例,首先需要下载并安装该库。
可以使用以下命令来下载和安装libmodbus:git clonecd libmodbus./autogen.sh./configuremakesudo make install安装完成后,可以使用以下命令来检查是否安装成功:pkg-config cflags libs libmodbus如果显示相应的编译选项和链接选项,则表示安装成功。
第四步:编写Modbus RTU例程在安装好Modbus库之后,可以开始编写Modbus RTU例程。
首先,需要包含必要的头文件:c#include <stdio.h>#include <modbus.h>接下来,需要初始化一个Modbus连接:cmodbus_t *ctx;ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);if (ctx == NULL) {fprintf(stderr, "Unable to create the libmodbus context\n");return -1;}在这个例程中,我们使用/dev/ttyUSB0作为串口设备,并设置波特率为9600,数据位为8,停止位为1,无校验位。
linux串口收发程序
下面简单介绍了,在REDHAT9操作系统下的使用终端接收发送串口数据recive程序的使用,它通过串口接收其它计算机传送到本地计算机的数据,程序稳定可靠2.源代码:接收串口程序recive.c的源码#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <termios.h>#include <errno.h>#include <string.h>#define TRUE 1//初始化串口选项:void setTermios(struct termios * pNewtio, int uBaudRate){bzero(pNewtio, sizeof(struct termios)); /* clear struct for new port settings *///8N1pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;pNewtio->c_iflag = IGNPAR;pNewtio->c_oflag = 0;pNewtio->c_lflag = 0; //non ICANON/*initialize all control charactersdefault values can be found in /usr/include/termios.h, andare given in the comments, but we don't need them here*/pNewtio->c_cc[VINTR] = 0; /* Ctrl-c */pNewtio->c_cc[VQUIT] = 0; /* Ctrl-\ */pNewtio->c_cc[VERASE] = 0; /* del */pNewtio->c_cc[VKILL] = 0; /* @ */pNewtio->c_cc[VEOF] = 4; /* Ctrl-d */pNewtio->c_cc[VTIME] = 5; /* inter-character timer, timeout VTIME*0.1 */ pNewtio->c_cc[VMIN] = 0; /* blocking read until VMIN character arrives */ pNewtio->c_cc[VSWTC] = 0; /* '\0' */pNewtio->c_cc[VSTART] = 0; /* Ctrl-q */pNewtio->c_cc[VSTOP] = 0; /* Ctrl-s */pNewtio->c_cc[VSUSP] = 0; /* Ctrl-z */pNewtio->c_cc[VEOL] = 0; /* '\0' */pNewtio->c_cc[VREPRINT] = 0; /* Ctrl-r */pNewtio->c_cc[VDISCARD] = 0; /* Ctrl-u */pNewtio->c_cc[VWERASE] = 0; /* Ctrl-w */pNewtio->c_cc[VLNEXT] = 0; /* Ctrl-v */pNewtio->c_cc[VEOL2] = 0; /* '\0' */}#define BUFSIZE 512int main(int argc, char **argv){int fd;int nread;int input;int *p=&input;//char buff[BUFSIZE];char buff[1024];struct termios oldtio, newtio;struct timeval tv;char *dev ="/dev/ttyS0";fd_set rfds;if ((fd = open(dev, O_RDWR | O_NOCTTY))<0){printf("err: can't open serial port!\n");return -1;}tcgetattr(fd, &oldtio); /* save current serial port settings */setTermios(&newtio, B9600);tcflush(fd, TCIFLUSH);tcsetattr(fd, TCSANOW, &newtio);//printf("Please input an integer.");//scanf("%d",&input);//*p=input;//printf("The integer you input is %d\n",*p);//printf("The integer you input is %d\n",&input); _sec=30;_usec=0;while (TRUE){printf("wait...\n");FD_ZERO(&rfds);FD_SET(fd, &rfds);if (select(1+fd, &rfds, NULL, NULL, &tv)>0) {printf("wait...\n");if (FD_ISSET(fd, &rfds)){//nread=read(fd, buff, BUFSIZE);nread=read(fd, buff ,1024);printf("readlength=%d\n", nread);//buff[nread]='\0';//printf("%s\n", buff);// buff='\0';printf("date=%d\n",buff);//printf("%d\n",fd);printf("%d\n", buff[1]);printf("%d\n", buff[2]);printf("%d\n", buff[3]);printf("%d\n", buff[4]);printf("%d\n", buff[5]);printf("%d\n", buff[6]);printf("%d\n", buff[7]);printf("%d\n", buff[8]);printf("%d\n", buff[9]);printf("%d\n", buff[10]);printf("%d\n", buff[11]);printf("%d\n", buff[12]);printf("%d\n", buff[13]);printf("%d\n", buff[14]);printf("%d\n", buff[15]);printf("%d\n", buff[16]);printf("%d\n", buff[17]);printf("%d\n", buff[18]);printf("%d\n", buff[19]);//printf("%d\n", buff[20]);//printf("%d\n", buff[21]);//printf("%d\n", buff[22]);//printf("%d\n", buff[23]);//printf("%d\n", buff[24]);//printf("%d\n", buff[25]);//printf("%d\n", buff[26]);//printf("%d\n", buff[27]);//printf("%d\n", buff[28]);//printf("%d\n", buff[29]);//printf("%d\n", buff[30]);//printf("%d\n", buff[31]);//printf("%d\n", buff[32]);//printf("%d\n", buff[1]);//printf("%d\n", buff[2]);//printf("%d\n", buff[3]);//printf("%d\n", buff[4]);//printf("%d\n", buff[5]);//printf("%d\n", buff[6]);//printf("%d\n", buff[7]);//printf("%d\n", buff[8]);//printf("%d\n", buff[9]);//printf("%d\n", buff[10]);//printf("%d\n", buff[32]);//printf("%d\n", buff[12]);//printf("%d\n", buff[13]);//printf("%d\n", buff[14]);//printf("%d\n", buff[15]);//printf("%d\n", buff[16]);}}}tcsetattr(fd, TCSANOW, &oldtio); close(fd);}串口发送程序send.c的源码#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <termios.h>#include <errno.h>#include <string.h>//初始化串口选项:void setTermios(struct termios * pNewtio, int uBaudRate){bzero(pNewtio, sizeof(struct termios)); /* clear struct for new port settings */ //8N1pNewtio->c_cflag = uBaudRate | CS8 | CREAD | CLOCAL;pNewtio->c_iflag = IGNPAR;pNewtio->c_oflag = 0;pNewtio->c_lflag = 0; //non ICANON/*initialize all control charactersdefault values can be found in /usr/include/termios.h, andare given in the comments, but we don't need them here*/pNewtio->c_cc[VINTR] = 0; /* Ctrl-c */pNewtio->c_cc[VQUIT] = 0; /* Ctrl-\ */pNewtio->c_cc[VERASE] = 0; /* del */pNewtio->c_cc[VKILL] = 0; /* @ */pNewtio->c_cc[VEOF] = 4; /* Ctrl-d */pNewtio->c_cc[VTIME] = 5; /* inter-character timer, timeout VTIME*0.1 */ pNewtio->c_cc[VMIN] = 0; /* blocking read until VMIN character arrives */ pNewtio->c_cc[VSWTC] = 0; /* '\0' */pNewtio->c_cc[VSTART] = 0; /* Ctrl-q */pNewtio->c_cc[VSTOP] = 0; /* Ctrl-s */pNewtio->c_cc[VSUSP] = 0; /* Ctrl-z */pNewtio->c_cc[VEOL] = 0; /* '\0' */pNewtio->c_cc[VREPRINT] = 0; /* Ctrl-r */pNewtio->c_cc[VDISCARD] = 0; /* Ctrl-u */pNewtio->c_cc[VWERASE] = 0; /* Ctrl-w */pNewtio->c_cc[VLNEXT] = 0; /* Ctrl-v */pNewtio->c_cc[VEOL2] = 0; /* '\0' */}int main(int argc, char **argv){int fd;int input;int *p=&input;int nCount, nTotal, i;struct termios oldtio, newtio;char *dev ="/dev/ttyS0";//if ((argc!=3) || (sscanf(argv[1], "%d", &nTotal) != 1))//{//printf("err: need tow arg =%d!\n", argc );//return -1;//}//sscanf(argv[1], "%d", &nTotal)//{//printf("send date!\n", argc );//return -1;//}if ((fd = open(dev, O_RDWR | O_NOCTTY))<0){printf("err: can't open serial port!\n");return -1;}while (1) //循环读取数据{tcgetattr(fd, &oldtio); /* save current serial port settings */ setTermios(&newtio, B9600);tcflush(fd, TCIFLUSH);tcsetattr(fd, TCSANOW, &newtio);//for (i=0; i<nTotal; i++)//{//nCount=write(fd, argv[2], s]trlen(argv[2]));//argv[]={010*********d5ca};printf("Please input an integer.");scanf("%d",&input);*p=input;//nCount=write(fd,argv[p],strlen(argv[]));printf("The integer you input is %d\n",*p);printf("The integer you input is %d\n",&input);nCount=write(fd,"010*********d5ca/r",512);nCount=write(fd,p,1024);nCount=write(fd,&input,1024);printf("send date *p");printf("send date input");printf("send date 010*********d5ca\n"); //sleep(1);}tcsetattr(fd, TCSANOW, &oldtio); close(fd);return 0;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux下串口通信编程一、什么是串口通信?串口通信是指计算机主机与外设之间以及主机系统与主机系统之间数据的串行传送。
使用串口通信时,发送和接收到的每一个字符实际上都是一次一位的传送的,每一位为1或者为0。
二、串口通信的分类串口通信可以分为同步通信和异步通信两类。
同步通信是按照软件识别同步字符来实现数据的发送和接收,异步通信是一种利用字符的再同步技术的通信方式。
2.1 同步通信同步通信是一种连续串行传送数据的通信方式,一次通信只传送一帧信息。
这里的信息帧与异步通信中的字符帧不同,通常含有若干个数据字符。
它们均由同步字符、数据字符和校验字符(CRC)组成。
其中同步字符位于帧开头,用于确认数据字符的开始。
数据字符在同步字符之后,个数没有限制,由所需传输的数据块长度来决定;校验字符有1到2个,用于接收端对接收到的字符序列进行正确性的校验。
同步通信的缺点是要求发送时钟和接收时钟保持严格的同步。
2.2 异步通信异步通信中,数据通常以字符或者字节为单位组成字符帧传送。
字符帧由发送端逐帧发送,通过传输线被接收设备逐帧接收。
发送端和接收端可以由各自的时钟来控制数据的发送和接收,这两个时钟源彼此独立,互不同步。
接收端检测到传输线上发送过来的低电平逻辑"0"(即字符帧起始位)时,确定发送端已开始发送数据,每当接收端收到字符帧中的停止位时,就知道一帧字符已经发送完毕。
在异步通行中有两个比较重要的指标:字符帧格式和波特率。
(1)字符帧,由起始位、数据位、奇偶校验位和停止位组成。
1.起始位:位于字符帧开头,占1位,始终为逻辑0电平,用于向接收设备表示发送端开始发送一帧信息。
2.数据位:紧跟在起始位之后,可以设置为5位、6位、7位、8位,低位在前高位在后。
3.奇偶校验位:位于数据位之后,仅占一位,用于表示串行通信中采用奇校验还是偶校验。
(2)波特率,波特率是每秒钟传送二进制数码的位数,单位是b/s。
异步通信的优点是不需要传送同步脉冲,字符帧长度也不受到限制。
缺点是字符帧中因为包含了起始位和停止位,因此降低了有效数据的传输速率。
三、什么是RS-232?RS-232-C 接口(又称EIA RS-232-C)它是在1970 年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。
它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准"该标准规定采用一个25 个脚的DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。
传输距离在码元畸变小于4% 的情况下,传输电缆长度应为50 英尺。
四、计算机串口引脚说明引出号说明1 接地2 TXD输出3 RXD输入4 RTS请求发送5 CTS请求接收6 DSR数据序列就绪7 GND逻辑地8 DCD数据负载检测9 保留10 保留11 未定义12 后备DCD13 后备CTS14 后备TXD15 传输时钟16 后备RXD17 接收时钟18 未定义19 后备RTS20 DTR数据终端就绪21 信号质量检测22 闹钟检测23 数据速率选择24 传输时钟25 未定义五、全双工与半双工1.全双工,表示机器可以同时发送数据也可以接收数据,有两个独立的数据通道(一个用于发送,一个用于接收)2.半双工,表示机器不能在发送数据的同时也接收数据。
六、流量控制1.使用软件方法使用特殊的字符来标记数据流的开始和结束,比如XON,DC1,八进制021来标志开始,用X0FF,DC3,八进制023来标志结束。
2.使用硬件方法使用RS232的CTS和RTS信号来代替特殊字符控制。
当接收方准备接收更多数据时,设置CTS为0,反之设置成1。
对应的发送端准备发送数据时,设置RTS为0。
七、串口的访问串口设备在LINUX下与所有设备一样都是通过设备文件来进行访问。
7.1打开串口LINUX系统下串口设备是通过open函数来打开的,不过需要注意的是,一般用户是没有权限访问设备文件的,需要将打开的串口设备的访问权限设置成一般用户可以访问的权限。
open函数头文件#include#include#include函数原型int open(const char *pathname, int oflag, .../*, mode_t mode*/);参数const char *pathname - 要打开文件的文件名称,例如/dev/ttyS0int oflag - 文件打开方式,可用标志如下:O_RDONLY 以只读方式打开文件O_WRONLY 以只写方式打开文件O_RDWR 以读写方式打开文件O_APPEND 写入数据时添加到文件末尾O_CREATE 如果文件不存在则产生该文件,使用该标志需要设置访问权限位mode_tO_EXCL 指定该标志,并且指定了O_CREATE标志,如果打开的文件存在则会产生一个错误O_TRUNC 如果文件存在并且成功以写或者只写方式打开,则清除文件所有内容,使得文件长度变为0O_NOCTTY 如果打开的是一个终端设备,这个程序不会成为对应这个端口的控制终端,如果没有该标志,任何一个输入,例如键盘中止信号等,都将影响进程。
O_NONBLOCK 该标志与早期使用的O_NDELAY标志作用差不多。
程序不关心DCD 信号线的状态,如果指定该标志,进程将一直在休眠状态,直到DCD信号线为0。
O_SYNC 对I/O进行写等待返回值成功返回文件描述符,如果失败返回-1例如:以可读写方式打开/dev/ttyS0设备int fd; /* 文件描述符*/fd = open("/dev/ttyS0", O_RDWR | 0_NOCTTY | O_NONBLOCK);7.2关闭串口Linux系统下通过close函数来关闭串口设备close函数头文件#include函数原型int close(int filedes);参数int filedes - 文件描述符返回值成功返回0,否则返回-1例如:关闭打开的串口设备fdint ret; /* 返回标志,用于判断是否正常关闭设备*/ret = close(fd);7.3写串口写串口是通过write函数来完成的write函数头文件#include函数原型ssize_t write(int filedes, const void *buff, size_t nbytes);参数int filedes - 文件描述符const void *buff - 存储写入数据的数据缓冲区size_t nbytes - 写入数据字节数返回值ssize_t - 返回写入数据的字节数,该值通常等于nbytes,如果写入失败返回-1 例如:向终端设备发送初始化命令int n = 0; /* 写入字节数*/n = write(fd, "ATZ\r", 4);if(n == -1){fprintf(stderr, "Wirte ATZ command error.\n");}7.4读串口读串口是通过read函数来完成的read函数头文件#include函数原型ssize_t read(int filedes, void *buff, size_t nbytes);参数int filedes - 文件描述符void *buff - 存储读取数据的数据缓冲区size_t nbytes - 需要读取的字节数返回值ssize_t - 成功读取返回读取的字节数,否则返回-1注意,在对串口进行读取操作的时候,如果是使用的RAW模式,每个read系统调用将返回当前串行输入缓冲区中存在的字节数。
如果没有数据,将会一致阻塞到有字符达到或者间隔时钟到期,或者发生错误。
如果想使read函数在没有数据的时候立即返回则可以使用fcntl函数来设置文件访问属性。
例如:fcntl(fd, F_SETFL, FNDELAY);这样设置后,当没有可读取的数据时,read函数立即返回0。
通过fcntl(fd, F_SETFL, 0)可以设置回一般状态。
例如:从终端读取5个字节的应答数据int nRead; /* 从终端读取的字节数*/char buffer[256]; /* 接收缓冲区*/nRead = read(fd, buffer, 5);if(nRead == -1){fprintf(stderr, "Read answer message error.\n");}八、终端配置8.1 POSIX终端接口大多数系统都支持POSIX终端接口,POSIX终端通过一个termios结构来进行控制,该结构定义在termios.h文件中。
termios结构struct termios{tcflag_t c_iflag; /* 输入选项标志*/tcflag_t c_oflag; /* 输出选项标志*/tcflag_t c_cflag; /* 控制选项标志*/tcflag_t c_lflag; /* 本地选项标志*/cc_t c_cc[NCCS]; /* 控制特性*/};c_iflag成员Flag DescriptionGNBRK 忽略输入中的BREAK状态BRKINT 如果设置了IGNBRK,将忽略BREAK。
如果没有设置,但是设置了BRKINT,那么BREAK将使得输入和输出队列被刷新,如果终端是一个前台进程组的控制终端,这个进程组中所有进程将收到SIGINT信号。
如果既未设置IGNBRK也未设置BRKINT,BREAK 将视为NUL同义字符,除非设置了PARMRK,这种情况下被视为序列\377\0\0IGNPAR 忽略桢错误和奇偶校验错误PARMRK 如果没有设置IGNPAR,在有奇偶校验错误或者桢错误的字符前插入\377\0。
如果既没有设置IGNPAR也没有设置PARMRK,将所有奇偶校验错误或者桢错误的字符视为\0。
INPCK 启用输入奇偶校验检测。
ISTRIP 去掉第八位。
INLCR 将输入的NL翻译为CR。
IGNCR 忽略输入中的回车。
ICRNL 将输入中的回车翻译为新行字符(除非设置了IGNCR)。
IUCLC (不属于POSIX)将输入中的大写字母映射为小写字母。
IXON 启用输出的XON/XOFF流控制IXANY (不属于POSIX。
1;XSI)允许任何字符来重新开始输出。
IXOFF 启用输入的XON/XOFF流控制IMAXBEL (不属于POSIX)当输入队列满时响铃。
LINUX没有实现该位,总是将其视为已设置。
c_oflag成员Flag DescriptionOPOST 启用具体实现自行定义的输出。