一、串口的基本原理
1 串口通讯

串口通讯(Serial Communication),是指外设和计算机间,通过数据信号线、地线等,按位进行传输数据的一种通讯方式。
    串口是一种接口标准,它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。

2 串口通讯的数据格式


    一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以“起始位”开始,以“停止位”结束,字符之间没有固定的时间间隔要求。
    每一个字符的前面都有一位起始位(低电平),字符本身由7位数据位组成,接着字符后面是一位校验位(检验位可以是奇校验、偶校验或无校验位),最后是一位或一位半或二位停止位,停止位后面是不定长的空闲位,停止位和空闲位都规定为高电平。实际传输时每一位的信号宽度与波特率有关,波特率越高,宽度越小,在进行传输之前,双方一定要使用同一个波特率设置。

3 通讯方式
    单工模式(Simplex Communication)的数据传输是单向的。通信双方中,一方固定为发送端,一方则固定为接收端。信息只能沿一个方向传输,使用一根传输线。
半双工模式(Half Duplex)通信使用同一根传输线,既可以发送数据又可以接收数据,但不能同时进行发送和接收。数据传输允许数据在两个方向上传输,但是,在任何时刻只能由其中的一方发送数据,另一方接收数据。因此半双工模式既可以使用一条数据线,也可以使用两条数据线。半双工通信中每端需有一个收发切换电子开关,通过切换来决定数据向哪个方向传输。因为有切换,所以会产生时间延迟,信息传输效率低些。
    全双工模式(Full Duplex)通信允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。在全双工模式中,每一端都有发送器和接收器,有两条传输线,信息传输效率高。
    显然,在其它参数都一样的情况下,全双工比半双工传输速度要快,效率要高。

4 偶校验与奇校验
    在标准ASCII码中,其最高位(b7)用作奇偶校验位。所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1;偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。

5 停止位
    停止位是按长度来算的。串行异步通信从计时开始,以单位时间为间隔(一个单位时间就是波特率的倒数),依次接受所规定的数据位和奇偶校验位,并拼装成一个字符的并行字节;此后应接收到规定长度的停止位“1”。所以说,停止位都是“1”,1.5是它的长度,即停止位的高电平保持1.5个单位时间长度。一般来讲,停止位有1,1.5,2个单位时间三种长度。

6 波特率
    波特率就是每秒钟传输的数据位数。
    波特率的单位是每秒比特数(bps),常用的单位还有:每秒千比特数Kbps,每秒兆比特数Mbps。串口典型的传输波特率600bps,1200bps,2400bps,4800bps,9600bps,19200bps,38400bps。
    PLC/PC与称重仪表通讯时,最常用的波特率是9600bps,19200bps。PLC/PC或仪表与大屏幕通讯时,最常用的波特率是600bps。

7 典型的串口通讯标准
    EIA RS232(通常简称“RS232”): 1962年由美国电子工业协会(EIA)制定。
    EIA RS485(通常简称“RS485”): 1983年由美国电子工业协会(EIA)制定。

8 RS232串口
    RS232是计算机与通信工业应用中最广泛一种串行接口。它以全双工方式工作,需要地线、发送线和接收线三条线。RS232只能实现点对点的通信方式。
8.1 RS232串口缺点
    ●接口信号电平值较高,接口电路芯片容易损坏。
    ●传输速率低,最高波特率19200bps。
    ●抗干扰能力较差。
    ●传输距离有限,一般在15m以内。
    ●只能实现点对点的通讯方式。
8.2 RS232串口接口定义
    RXD:接收数据,TXD:发送数据,GND/SG:信号地。
8.3 电脑DB9针接口定义
    电脑DB9针接口是常见的RS232串口,其引脚定义如下:
    2号脚:RXD(接收数据)
    3号脚:TXD(发送数据)
    5号脚:SG或GND(信号地)
    其它脚:我们不用

电脑RS232串口与仪表串口连接图:
 
    

9 RS485串口
9.1 RS485串口特点
    ●RS485采用平衡发送和差分接收,具有良好的抗干扰能力,信号能传输上千米。
    ●RS485有两线制和四线制两种接线。采用四线制时,只能实现点对多的通讯(即只能有一个主设备,其余为从设备)。四线制现在很少采用,现在多采用两线制接线方式。
    ●两线制RS485只能以半双式方式工作,收发不能同时进行。
    ●RS485在同一总线上最多可以接32个结点,可实现真正的多点通讯,但一般采用的是主从通信方式,即一个主机带多个从机。
    ●因RS485接口具有良好的抗干扰能力,长的传输距离和多站能力等优点使其成为首选的串行接口。

10 串口通讯硬件常见的注意事项
    ●通讯电缆端子一定接牢,不可有任何松动,否则,可能会烧坏仪表或上位机的通讯板。
    ●不可带电拔插通讯端子,否则,可能会烧坏仪表或上位机的通讯板,一定要关闭仪表电源后才能去拔插通讯端子或接通讯线。
    ●通讯用的屏蔽电缆最好选用双层隔离型屏蔽电缆,其次选用单层屏蔽电缆,最好不要选用无屏蔽层的电缆,且电缆屏蔽层一定要能完全屏蔽,有些质量差的电缆,屏蔽层很松散,根本起不到屏蔽的作用。单层屏蔽的电缆屏蔽层应一端接地,双层屏蔽的电缆屏蔽层其外层(含铠装)应两端接地,内层屏蔽则应一端接地。
    ●仪表使用RS232通讯时,通讯电缆长度不得超过15米。
    ●一般RS485协议的接头没有固定的标准,可能根据厂家的不同引脚顺序和管脚功能可能不尽相同,用户可以查阅相关产品RS485的引脚图。
    ●RS485通讯电缆最好选用阻阬匹配、低衰减的RS485专用通讯电缆(双绞线),不要使用普通的双绞电缆或质量较差的通讯电缆。因为普通电缆或质量差的通讯电缆,可能阻抗不匹配、衰减大、绞合度不够、屏蔽层太松散,这样会导致干扰将非常大,会造成通讯不畅,甚至通讯不上。
    ●仪表使用RS485通讯时,每台仪表必须手牵手地串下去,不可以有星型连接或者分叉,如果有星型连接或者分叉,干扰将非常大,会造成通讯不畅,甚至通讯不上。

●485总线结构理论上传输距离达到1200米,一般是指通讯线材优质达标,波特率9600,只有一台485设备才能使得通讯距离达到1200米,而且能通讯并不代表每次通讯都正常,所以通常485总线实际的稳定通讯距离远远达不到1200米。负载485设备多,线材阻抗不同时,通讯距离更短。
    ●仪表使用RS485通讯时,必要时,请接入终端电阻,以增强系统的抗干扰性,典型的终端电阻阻值是120欧。

11 串口通讯软件设置要点
11.1 有关通讯的一些基本概念
    ●主机与从机:在通讯系统中起主要作用、发布主要命令的称为主机,接受命令的称为从机。
    ●连续方式:指主机不需要发布命令,从机就能自动地向主机发送数据。
    ●指令方式:指主机向从机发布命令,从机根据指令执行动作,并将结果“应答”给主机的模式。
    ●输出数据类型:指在连续方式通讯时,从机输出给主机的数据类型。
    ●通讯协议:指主机与从机通讯时,按哪一种编码规则来通讯。
    ●波特率:主从机之间通讯的速度。
    ●数据位:每次传输数据时,数据由几位组成。
    ●校验位:数据传输错误检测,可以是奇校验、偶校验或无校验。
    ●地址:每一台从机的编号。
11.2 主从机之间通讯设置要点
    ●要点一:主/从RS232/485硬件有无设置正确,通讯线有无接对。有些通讯板卡是RS422与RS485共用的,依靠板上跳线来实现的,有些仪表RS232/485也需要通讯跳线来实现。
    ●要点二:主机上的通讯端口有无设置正确;超时(一般设置为2s)、通讯延时(一般设置为5~20ms)、ACK信号延时(一般设置为0ms)有无设置正确。
    ●要点三:主/从机通讯协议有无选择正确。
    ●要点四:主/从机波特率有无选择正确。
    ●要点五:主/从机数据位有无选择正确。数据位可以选择7位,8位。
    ●要点六:主/从机校验位有无选择正确。校验位一般可选择偶校验、奇校验、无校验。
    ●要点七:主/从机停止位有无选择正确。停止位可以选择1位、1.5位还是2位。
    ●要点八:从机地址有无选择正确。
    ●要点九:主/从机的通讯方式有无选择正确。

    进行通讯测试的时候经常会进行线路测试,测试所用的串口线是否可用,方法有二如下:
 
1> 把串口线接到不同的串口,用串口调试工具从一个串口发数据,另一个能正常收到说明串口线是OK的。
2> 把串口线的一端短接(用金属把2,3号脚连通),用万用表测另一端的2,3号如果正常的话会有嘀嘀的短接报警声。

二、linux下串口的基本操作

1、串口的操作

1.1打开:fd = open("/dev/ttySAC1", O_RDWR | O_NOCTTY | O_NDELAY);
              O_RDWR 读写方式打开;
              O_NOCTTY 不允许进程管理串口(不太理解,一般都选上);
              O_NDELAY 非阻塞(默认为阻塞,打开后也可以使用fcntl()重新设置)

1.2写入:n = write(fd, "linux", 5);
                n实际写入字节数;

1.3读取:res = read(fd,buf,len);
                 res 读取的字节数;

1.4设置:fcntl(fd, F_SETFL, FNDELAY); //非阻塞
                 fcntl(fd, F_SETFL, 0); // 阻塞

1.5关闭:close(fd);

2、串口配置

struct termios options;  // 串口配置结构体
tcgetattr(fd,&options); //获取当前设置
bzero(&options,sizeof(options));
options.c_cflag  |= B115200 | CLOCAL | CREAD; // 设置波特率,本地连接,接收使能
options.c_cflag &= ~CSIZE; //屏蔽数据位
options.c_cflag  |= CS8; // 数据位为 8 ,CS7 for 7
options.c_cflag &= ~CSTOPB; // 一位停止位, 两位停止为 |= CSTOPB
options.c_cflag &= ~PARENB; // 无校验
 //options.c_cflag |= PARENB; //有校验
//options.c_cflag &= ~PARODD // 偶校验
//options.c_cflag |=  PARODD    // 奇校验
options.c_cc[VTIME] = 0; // 等待时间,单位百毫秒 (读)。后有详细说明
options.c_cc[VMIN] = 0; // 最小字节数 (读)。后有详细说明
tcflush(fd, TCIOFLUSH); // TCIFLUSH刷清输入队列。
                                       TCOFLUSH刷清输出队列。 
                                       TCIOFLUSH刷清输入、输出队列。
tcsetattr(fd, TCSANOW, &options); // TCSANOW立即生效;
                                                        TCSADRAIN:Wait until everything has been transmitted;
                                                        TCSAFLUSH:Flush input and output buffers and make the change

3、VTIME 和  VMIN

VTIME  定义要求等待的零到几百毫秒的值(通常是一个8位的unsigned char变量)。
VMIN 定义了要求等待的最小字节数, 这个字节数可能是0。
只有设置为阻塞时这两个参数才有效,仅针对于读操作。
说起来比较复杂,举个例子吧,设置为阻塞状态,写操作未进行实验,这里仅讨论读操作,
read(fd,&buf,8); // 读串口

3.1
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 0;
VMIN = 0,当缓冲区字节数 >= 0 时进行读操作,实际上这时读串口操作并未被阻塞,因为条件始终被满足。

3.2
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 1;
VMIN = 1,当缓冲区字节数 >= 1 时进行读操作,当没有数据时读串口操作被阻塞。

3.3
options.c_cc[VTIME] = 0;
options.c_cc[VMIN] = 4;
VMIN = 4,当缓冲区字节数 >= 4 时进行读操作,否则读串口操作被阻塞。每次读出的最大字节数由read函数中第三个参数决定。直到缓冲区剩下的数据< read 第三个参数 并且< 4 (如果这时read第三参数为 1 则进行4次读操作直至读完缓冲区,如read第三参数为2,连续进行读操作,直至缓冲区空或还剩一个字符)。没有设置VTIME,剩下的字符没有确定的期限,直到下次满足读条件的时候才被读出。

----------------------------------考虑VTIME-----------------------------

3.4
options.c_cc[VTIME] = 10; //单位百毫秒
options.c_cc[VMIN] = 4;
同3.3的区别就是,没满足条件或读缓冲区中剩下的数据会在1秒(10百毫秒)后读出。另外特别注意的是当设置VTIME后,如果read第三个参数小于VMIN ,将会将VMIN 修改为read的第三个参数,即使用read(fd,&buf,2);,以上设置变为:
options.c_cc[VTIME] = 10;
options.c_cc[VMIN] = 2;

==================================================================================================================================

1>打开串口函数open_port()中要实现的函数:
(1)open("/dev/ttys0",O_RDWR | O_NOCTTY | O_NDELAY);/*打开串口0*/
(2)fcntl(fd,F_SETFL,0)/*恢复串口为阻塞状态*/
(3)isatty(STDIN_FILENO) /*测试是否为中断设备 非0即是中断设备*/

2> 配置串口参数函数set_opt()中要实现的函数:
(1)保存原先有串口配置
tcgetattr(fd,&oldtio);

(2)先将新串口配置清0
bzore(&newtio,sizeof(newito));

(3)激活选项CLOCAL和CREAD 并设置数据位大小
newtio.c_cflag |=CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |=CS8;

(4)设置奇偶校验
奇校验:
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
偶校验:
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PAREND;
newtio.c_cflag &= ~PARODD;
无奇偶校验:
newtio.c_cflag &= ~PARENB;

(5) 设置停止位
newtio.c_cflag &= ~CSTOPB; /*停止位为1*/
newtio.c_cflag |= CSTOPB;/*停止位为0*/

(6)设置波特率:
cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);

(7)设置等待时间和最小接受字符:
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 0;

(8)处理为接收字符:
tcflush(fd,TCIFLUSH);

(9)激活新配置:
tcsetattr(fd,TCSANOW,&newtio);
3.读写串口
write(fd,buff,8);
read(fd,buff,8);

三、串口编程实例:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
/* 五个参量 fd打开文件 speed设置波特率 bit数据位设置   neent奇偶校验位 stop停止位 */struct termios newtio,oldtio;if ( tcgetattr( fd,&oldtio) != 0) {perror("SetupSerial 1");return -1;}bzero( &newtio, sizeof( newtio ) );newtio.c_cflag |= CLOCAL | CREAD;newtio.c_cflag &= ~CSIZE;switch( nBits ){case 7:newtio.c_cflag |= CS7;break;case 8:newtio.c_cflag |= CS8;break;}switch( nEvent ){case 'O':newtio.c_cflag |= PARENB;newtio.c_cflag |= PARODD;newtio.c_iflag |= (INPCK | ISTRIP);break;case 'E':newtio.c_iflag |= (INPCK | ISTRIP);newtio.c_cflag |= PARENB;newtio.c_cflag &= ~PARODD;break;case 'N':newtio.c_cflag &= ~PARENB;break;}
switch( nSpeed ){case 2400:cfsetispeed(&newtio, B2400);cfsetospeed(&newtio, B2400);break;case 4800:cfsetispeed(&newtio, B4800);cfsetospeed(&newtio, B4800);break;case 9600:cfsetispeed(&newtio, B9600);cfsetospeed(&newtio, B9600);break;case 115200:cfsetispeed(&newtio, B115200);cfsetospeed(&newtio, B115200);break;default:cfsetispeed(&newtio, B9600);cfsetospeed(&newtio, B9600);break;}if( nStop == 1 )newtio.c_cflag &= ~CSTOPB;else if ( nStop == 2 )newtio.c_cflag |= CSTOPB;newtio.c_cc[VTIME] = 0;newtio.c_cc[VMIN] = 0;tcflush(fd,TCIFLUSH);if((tcsetattr(fd,TCSANOW,&newtio))!=0){perror("com set error");return -1;}printf("set done!\n");return 0;
}
int open_port(int fd,int comport)
{
/* fd 打开串口 comport表示第几个串口 */char *dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};long vdisable;if (comport==1){    fd = open( "/dev/ttyS0", O_RDWR|O_NOCTTY|O_NDELAY);if (-1 == fd){perror("Can't Open Serial Port");return(-1);}elseprintf("open ttyS0 .....\n");}else if(comport==2){    fd = open( "/dev/ttyS1", O_RDWR|O_NOCTTY|O_NDELAY);if (-1 == fd){perror("Can't Open Serial Port");return(-1);}elseprintf("open ttyS1 .....\n");}else if (comport==3){fd = open( "/dev/ttyS2", O_RDWR|O_NOCTTY|O_NDELAY);if (-1 == fd){perror("Can't Open Serial Port");return(-1);}elseprintf("open ttyS2 .....\n");}if(fcntl(fd, F_SETFL, 0)<0)printf("fcntl failed!\n");elseprintf("fcntl=%d\n",fcntl(fd, F_SETFL,0));if(isatty(STDIN_FILENO)==0)printf("standard input is not a terminal device\n");elseprintf("isatty success!\n");printf("fd-open=%d\n",fd);return fd;
}
int main(void)
{int fd;int nread,i;char buff[]="Hello\n";if((fd=open_port(fd,1))<0){perror("open_port error");return;}if((i=set_opt(fd,115200,8,'N',1))<0){perror("set_opt error");return;}printf("fd=%d\n",fd);
//    fd=3;nread=read(fd,buff,8);printf("nread=%d,%s\n",nread,buff);close(fd);return;}

linux下的串口通信相关推荐

  1. STM32串口通信代码、ASCII码、XU4串口通信,printf只会转换为无符号类型,linux下的串口通信程序

    1.其里面的的通信协议是是自己定的,这里 是检测到数据的结尾是以0x0d.0x0a结尾,则表示接受的数据完成了,这个数据是我想要的,这样子就不会出现一些错乱的数据信息.其中的0x8000.0x4000 ...

  2. linux下rs422串口通信,RS232/RS422/RS485通信接口區別

    一 串口控制 通常我們對於視頻服務器.錄像機.切換台等直接播出.切換控制主要使用串口進行,主要使用到RS-232.RS-422與RS-485三種接口控制.下面就串口的接口標准以及使用和外部插件和電纜進 ...

  3. C——Linux下的串口编程

    原 C--Linux下的串口编程 2017年06月06日 19:30:50 C_Aya 阅读数:11537 <span class="tags-box artic-tag-box&qu ...

  4. Linux操作系统下的串口通信

    1 Linux操作系统下的串口通信学习笔记   一.什么是串口通信 串口通信是指计算机主机与外设之间以及主机系统与主机系统之间数据的串行传送.使用 串口通信时,发送和接收到的每一个字符实际上都是一次一 ...

  5. 串口通信协议和Linux下的串口编程

    一.串口通信介绍: 串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节,尽管比按位字节(byte)的并行通信慢,但是串口可以使用一根线发送数据的同时 ...

  6. 关于嵌入式linux下的串口通讯问题---回车、换行、缓冲

    嵌入式Linux串口通讯测试问题:   经过实验,从Linux(PC)通过串口向嵌入式Linux开发板发送数据时,串口初始化完毕后遇到回车(0x0d)或换行(0x0a)才开始从串口接收数据,回车或换行 ...

  7. 详解Linux下的串口

    简介 串口也称串行通信接口(通常指COM接口),是实际工作中经常使用的一个接口,比如Linux下使用的debug串口,它用来登录Linux系统,输出log.另外也会使用串口和外部的一些模块通信,比如G ...

  8. linux下发送hex数据的串口调试软件,linux下模拟串口向计算机发送数据

    本人新手   从网上找了个串口通信程序改了改  本来是用单片机向串口发数据测试   但现在手头没有   请问有没有什么别的方法可以用? 非常感谢 | 一.使用工具 Windows XP 串口调试器 C ...

  9. linux 嵌入式串口通信设计目的,基于linux的嵌入式串口通信.doc

    PAGE 天津电子信息职业技术学院 <嵌入式软件编程>课程报告 课程名称:基于linux的嵌入式串口通信 课程代码: 115229 姓 名: 甘琦 学 号: 48 专 业: 物联网应用技术 ...

最新文章

  1. Caffe源码中common文件分析
  2. 【STL源码剖析读书笔记】【第5章】关联式容器之set、map、multiset和multimap
  3. python3:module
  4. 系统优化-----sysctl.conf文件内核设置参数详解
  5. 一个fork的面试题 转
  6. 马斯克的SpaceX星链网遇散热危机,气温过高自动关机
  7. MySQL学习-MySQL条件查询
  8. 接口测试第二课(Fiddler实现APP抓包)
  9. 旅游规划 (25 分)(Dijkstra)
  10. 如何在Linux启动jar 包
  11. steam错误代码 -118 ; 443/80或其他端口被占用,请关闭占用该端口的进程后再点击启动服务 ; 关闭端口进程
  12. PB中导入EXCEL数据
  13. ATM自动取款机系统的功能需求分析
  14. 三阶魔方中心互换_魔方中的数学2-置换的定义
  15. PS对图片的基本处理
  16. 【微机原理与接口技术】
  17. 麦克风阵列仿真环境的搭建
  18. 微信又更新了,这次新增了一个大家喜闻乐见的新功能?
  19. ReadProcessMemory Types of actual and formal var parameters must be identical
  20. Python 字符串格式化 f-string f“{}“ .format

热门文章

  1. 基于Java毕业设计一中体育馆管理系统源码+系统+mysql+lw文档+部署软件
  2. js判断输入是否含有空格
  3. 微信小程序阶段总结一
  4. win7系统使用经验
  5. 《OSPF和IS-IS详解》一1.1 星际网络
  6. python抓取网页数据并截图_网络爬虫-使用Python抓取网页数据
  7. 使用CAD旋转复制命令绘制图形
  8. 14.Flink1.11 安装部署及Release 文档解读
  9. m基于POCS算法的空域序列图像超分辨率重建matlab仿真
  10. 先锋机器人学习笔记_1-4 Pioneer SDK与VS2010编程配置