linux串口开始3字节会丢失,Linux 串口编程

Linux串口编程老生常谈了,已经做过很多次,但有些细节没次都要翻遍百度才能找到答案,这里做笔记记录下

1.首先先包含一些头文件,这里只做应用的方法介绍,具体头文件怎么回事,自个百度

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

2.打开串口,在Linux下打开设备和打开文件一样

int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);

fd问串口的文件句柄,为整型,open函数打开设备,第一个参数为需要打开的设备名,一般在PC下的Linux为"/dev/ttySx",再嵌入式ARM上是"/dev/ttySACx",

接着就是打开这个设备的参数。

首先是读写模式,有三种:O_RDONLY 只读模式,O_WRONLY 只写模式,O_RDWR 读写模式,这里我用的是可读可写模式;

终端模式:O_NOCTTY 一般都要加上这个参数,就是不要把这个设备用作控制终端,如果设为控制终端,键盘上按下Ctrl+C会产生中止信号,

一般串口都只是用于传输数据就可以;

阻塞模式:O_NONBLOCK 非阻塞模式,O_NDELAY阻塞模式有两种方法可以控制串口阻塞性(同时控制read和write):1.在打开串口的时候,open函数是否带O_NDELAY;2.在打开串口之后通过fcntl()函数进行控制。

阻塞的定义:

对于read,当串口输入缓冲区没有数据的时候,read函数将会阻塞在这里,当串口输入缓冲区中有数据可读取,read读到了需要的字节数之后,返回值为读到的字节数;

对于write,当串口输出缓冲区满,或剩下的空间小于将要写入的字节数,则write将阻塞,一直到串口输出缓冲区中剩下的空间大于等于将要写入的字节数,执行写入操作,返回写入的字节数。

非阻塞的定义:

对于read,当串口输入缓冲区没有数据的时候,read函数立即返回,返回值为0。

对于write,当串口输出缓冲区满,或剩下的空间小于将要写入的字节数,则write将进行写操作,写入当前串口输出缓冲区剩下空间允许的字节数,然后返回写入的字节数。

3.设置串口参数

这里用到一个重要的结构体,串口的波特率、数据位、校验位、停止位的设置由这个结构体实现:

struct termios

{

tcflag_t  c_iflag;  //input flags

tcflag_t  c_oflag;  //output flags

tcflag_t  c_cflag;  //control flags

tcflag_t  c_lflag;  //local flags

cc_t      c_cc[NCCS]; //control characters

};

该结构体中c_cflag最为重要,可设置波特率、数据位、校验位、停止位。在设置波特率时需要在数字前加上'B',

如B9600,B15200.使用其需通过“与”“或”操作方式:

定义这个结构体,并分配内存空间

struct termios serialAttr;

memset(&serialAttr, 0, sizeof serialAttr);

接下来设置具体参数

输入模式c_iflag成员控制端口接收端的字符输入处理:

0818b9ca8b590ca3270a3433284dd417.png 我一般使用这种:

serialAttr.c_iflag = IGNPAR;

就是忽略奇偶校验

接下来就是重点c_cflag的设置了

c_cflag一些常数(复制来的~)

常量

描述

CBAUD

Bit mask for baud rate

B0

0 baud (drop DTR)

B50

50 baud

B75

75 baud

B110

110 baud

B134

134.5 baud

B150

150 baud

B200

200 baud

B300

300 baud

B600

600 baud

B1200

1200 baud

B1800

1800 baud

B2400

2400 baud

B4800

4800 baud

B9600

9600 baud

B19200

19200 baud

B38400

38400 baud

B57600

57,600 baud

B76800

76,800 baud

B115200

115,200 baud

EXTA

External rate clock

EXTB

External rate clock

CSIZE

Bit mask for data bits

CS5

5 data bits

CS6

6 data bits

CS7

7 data bits

CS8

8 data bits

CSTOPB

2 stop bits (1 otherwise)

CREAD

Enable receiver

PARENB

Enable parity bit

PARODD

Use odd parity instead of even

HUPCL

Hangup (drop DTR) on last close

CLOCAL

Local line - do not change "owner" of port

LOBLK

Block job control output

CNEW_RTSCTS/CRTSCTS

Enable hardware flow control (not supported on all platforms)

0818b9ca8b590ca3270a3433284dd417.png

一般的像下面都是这样设置就够了

serialAttr.c_cflag = B115200 | HUPCL | CS8 | CREAD | CLOCAL;

这里的意思是:设置波特率为115200,最后关闭时断开,发送8位的数据,启动接收装置,忽略解制;

字符数组c_cc里面包括了控制字符的定义和超时参数。这个数组的每个元素都是以常量定义的。

成员变量c_cc中的控制字符

常量

描述

VINTR

Interrupt

CTRL-C

VQUIT

Quit

CTRL-Z

VERASE

Erase

Backspace (BS)

VKILL

Kill-line

CTRL-U

VEOF

End-of-file

CTRL-D

VEOL

End-of-line

Carriage return (CR)

VEOL2

Second end-of-line

Line feed (LF)

VMIN

Minimum number of characters to read

-

VSTART

Start flow

CTRL-Q (XON)

VSTOP

Stop flow

CTRL-S (XOFF)

VTIME

Time to wait for data (tenths of seconds)

-

这个参数设置有点让人琢磨,其实也很简单,一般只关注两个参数设置,就是VMIN和VTIME,设置最少字符和等待时间,

如果串口已经设置成NDELAY阻塞状态了,这里的超时设置无效.

VMIN可以指定读取的最小字符数。如果它被设置为0,那么VTIME值则会指定每个字符读取的等待时间。

如果VMIN不为零,VTIME会指定等待第一个字符读取操作的时间。如果在这个指定时间中可以开始读取某个字符,直到VMIN个数的所有字符全部被读取,其他读取操作将会被阻塞(等待)。也就是说,一旦读取第一个字符,串口驱动的预期就是接收到整个字符包(一共VMIN字节)。如果在允许的时间内没有字符被读取,那么read(2)调用就会返回0。通过这个方法可以确切得告诉串口驱动程序需要读取N个字节,而且read(2)调用只会返回N或者0。然而,超时设置只对第一个字符的读取操作有效,所以,如果因为某些原因驱动程序在N字节的包中丢失某个字符的话,read(2)调用将会一直等下去。

VTIME可以以十分之一秒为单位指定等待字符输入的时间,即是毫秒~。如果VTIME设置为0(默认情况),除非open(2)或者fcntl(2)函数设置了NDELAY选项,否则read(2)将会永久得阻塞(等待)。

再啰嗦一点:

A.如果VTIME取0,VMIN定义了要求等待读取的最小字节数。函数read()只有在读取了VMIN个字节的数据或者收到一个信号的时候才返回。 B.如果VMIN取0,VTIME定义了即使没有数据可以读取,read()函数返回前也要等待几百毫秒的时间量。这时,read()函数不需要像其通常情况那样要遇到一个文件结束标志才返回0. C.如果VTIME和VMIN都不取0,VTIME定义的是当接收到第一个字节的数据后开始计算等待的时间量。如果当调用read函数时可以得到数据,计时器马上开始计时。如果当调用read函数时还没有任何数据可读,则等接收到第一个字节的数据后,计时器开始计时。函数read可能会在读取到VMIN个字节的数据后返回,也可能在计时完毕后返回,这主要取决于哪个条件首先实现。不过函数至少会读取到一个字节的数据,因为计时器是在读取到第一个数据时开始计时的。 D.如果VTIME和VMIN都取0,即使读取不到任何数据,函数read也会立即返回。同时,返回值0表示read函数不需要等待文件结束标志就返回了。

还有一个函数设置阻塞

阻塞:fcntl(fd,F_SETFL,0)

非阻塞:fcntl(fd,F_SETFL,FNDELAY)

好像这种方法比open里更有效

设置完串口后下面就很简单了

4.往串口发送数据

ssize_t write(int fd, const void *buf, size_t count);

参数:

fd:要进行写操作的文件描述词,即串口句柄

buf:需要输出的缓冲区,即需要发送的字符串

count:最大输出字节计数,一般为需要发送的字符串长度

返回写入串口的长度

5.从串口中读数据

ssize_t read(int fd, void *buf, size_t count); 与读类似,fd,句柄,buf,用来装载接收的数据,count,需要接收的长度,返回接收到的值得长度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值