C语言串口接收GPS数据

news/2024/10/28 21:18:17/

要在C语言中接收GPS数据,需要使用串口通信来与GPS设备进行数据交互。一个简单的串口通信代码主要包含了以下几个部分:

1.标准库头文件

stdio.h:包含输入输出函数,如 printf

string.h:包含字符串处理函数,如 memset

unistd.h:包含 POSIX 操作系统 API,如 readclose

fcntl.h:包含文件控制相关函数,如 openfcntl

termios.h:包含串口配置和控制的结构体和常量。

2.串口控制变量

fd:用于存储串口文件描述符。

fd主要用于描述状态,比如打开文件是否成功

optionstermios 结构体,用于配置串口的参数。

buffer:用于存储从串口读取的数据。

termios 结构体说明

termios结构体中,该结构体一般包括如下的成员:
tcflag_t       c_iflag;      
tcflag_t       c_oflag;      
tcflag_t       c_cflag;      
tcflag_t       c_lflag;     
cc_t            c_cc[NCCS];
  

(1)c_iflag:输入模式标志,控制终端输入方式。

c_iflag参数表
键值说明
IGNBRK       忽略BREAK键输入
BRKINT       如果设置了IGNBRK,BREAK键的输入将被忽略,如果设置了BRKINT ,将产生SIGINT中断
IGNPAR       忽略奇偶校验错误
PARMRK     标识奇偶校验错误
INPCK        允许输入奇偶校验
ISTRIP       去除字符的第8个比特
INLCR        将输入的NL(换行)转换成CR(回车)
IGNCR       忽略输入的回车
ICRNL        将输入的回车转化成换行(如果IGNCR未设置的情况下)
IUCLC        将输入的大写字符转换成小写字符(非POSIX)
IXON         允许输入时对XON/XOFF流进行控制
IXANY        输入任何字符将重启停止的输出
IXOFF        允许输入时对XON/XOFF流进行控制
IMAXBEL   当输入队列满的时候开始响铃,Linux在使用该参数而是认为该参数总是已经设置

(2)c_oflag:输出模式标志,控制终端输出方式。


c_oflag参数
键值说明
OPOST       处理后输出
OLCUC      将输入的小写字符转换成大写字符(非POSIX)
ONLCR      将输入的NL(换行)转换成CR(回车)及NL(换行)
OCRNL      将输入的CR(回车)转换成NL(换行)
ONOCR      第一行不输出回车符
ONLRET      不输出回车符
OFILL         发送填充字符以延迟终端输出
OFDEL       以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符将是NUL(‘/0’)(非POSIX)
NLDLY       换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)
CRDLY       回车延迟,取值范围为:CR0、CR1、CR2和 CR3
TABDLY     水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3
BSDLY       空格输出延迟,可以取BS0或BS1
VTDLY       垂直制表符输出延迟,可以取VT0或VT1
FFDLY       换页延迟,可以取FF0或FF1

(3)c_cflag:控制模式标志,指定终端硬件控制信息。


c_oflag参数
键值说明
CBAUD             波特率(4+1位)(非POSIX)
CBAUDEX        附加波特率(1位)(非POSIX)
CSIZE              字符长度,取值范围为CS5、CS6、CS7或CS8
CSTOPB         设置两个停止位
CREAD           使用接收器
PARENB         使用奇偶校验
PARODD        对输入使用奇偶校验,对输出使用偶校验
HUPCL           关闭设备时挂起
CLOCAL         忽略调制解调器线路状态
CRTSCTS         使用RTS/CTS流控制


(4)c_lflag:本地模式标志,控制终端编辑功能。


c_lflag参数
键值说明
ISIG                  当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
ICANON           使用标准输入模式
XCASE            在ICANON和XCASE同时设置的情况下,终端只使用大写。如果只设置了XCASE,则输入字符将被转换为小写字符,除非字符使用了转义字符(非POSIX,且Linux不支持该参数)
ECHO               显示输入字符
ECHOE            如果ICANON同时设置,ERASE将删除输入的字符,WERASE将删除输入的单词
ECHOK            如果ICANON同时设置,KILL将删除当前行
ECHONL          如果ICANON同时设置,即使ECHO没有设置依然显示换行符
ECHOPRT        如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
TOSTOP           向后台输出发送SIGTTOU信号

3.打开串口设备

fd = open("/dev/pts/7", O_RDWR | O_NOCTTY | O_NDELAY);

open()函数

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

open()函数是在学习文件IO中的第一个函数。作用是打开一个文件,或者创建出一个文件。

能实现这种功能的函数有两套,一个是系统IO提供的open(),还有一个是标准的fopen()函数。

flags:标志(本质上是一个数字)

O_RDONLY 以只读方式打开文件
 O_WRONLY 以只写方式打开文件
 O_RDWR 以可读写方式打开文件.
// 上述三种旗标是互斥的, 也就是不可同时使用,
// 但可与下列的旗标利用 OR(|)运算符组合.
 O_CREAT 若欲打开的文件不存在则自动建立该文件.
 O_EXCL 如果 O_CREAT 也被设置, 此指令会去检查文件是否存在. 文件若不存在则建立该文件, 否
 O_NOCTTY 如果欲打开的文件为终端机设备时, 则不会将该终端机当成进程控制终端机.
 O_TRUNC 若文件存在并且以可写的方式打开时, 此旗标会令文件长度清为 0, 而原来存于该文件的资
 O_APPEND 当读写文件时会从文件尾开始移动, 也就是所写入的数据会以附加的方式加入到文件后面
 O_NONBLOCK 以不可阻断的方式打开文件, 也就是无论有无数据读取或等待, 都会立即返回进程之中
 O_NDELAY 同 O_NONBLOCK.
 O_SYNC 以同步的方式打开文件.
 O_NOFOLLOW 如果参数 pathname 所指的文件为一符号连接, 则会令打开文件失败.

 (1)O_RDONLY,O_WRONLY,O_RDWR三个互斥:

不可以同时使用,也不能添加 | (本质上都占用了两个同样的数字位),其余的旗标是可以加 | 的(占用不同的数字位)。

例如:8bit控制位,控制读写的在第1,2bit,xxxxxx00表示读数据,xxxxxx01表示写数据,xxxxxx11表示读写。这时O_RDONLY | O_WRONLY (00 | 01)还是只能得到数字01(O_WRONLY),对这三个旗标用 | 进行操作意义不大。

(2)O_CREAT | O_EXCL 常用组合作用解析

调用 open("abc.c",O_CREAT|O_EXCL);

系统会自动检测当前路径下"abc.c"文件是否存在。

如果存在,就返回 -1 (文件打开错误)。

如果不存在,就自动创建文件并返回文件当前进程ID。

(3)O_TRUNC 与 O_APPEND

写入文件时,系统默认将光标移动到文件开头。

O_TRUNC:作用是在光标移动的同时将文件长度清零(清空文件)。

O_APPEND:作用是在尾部追加内容,即将光标移动到文件末尾。

(4)O_NONBLOCK解析

在文件处于阻塞状态时强行打开文件。

例如我写了个只有从串口接收到数据才能关闭并且保存文件的程序,如果程序迟迟没有从串口中接收到数据,那么文件就会一直处于阻塞状态中等待数据,这个时候文件无法正常打开,需要添加此旗标。

fcntl函数()

int fcntl(int fd, int cmd, ... /* arg */ );// arg表示可变参数,由cmd决定

fcntl()的第三个参数是可选。是否需要此参数由cmd决定。所需的参数类型在每个cmd名称后面的括号中指示(在大多数情况下,所需的类型是int,我们使用名称arg来标识参数),如果不需要参数,则指定void。

以下某些操作仅在特定的Linux内核版本之后才受支持。检查主机内核是否支持特定操作的首选方法是使用所需的cmd值调用fcntl(),然后使用EINVAL测试调用是否失败,这表明内核无法识别该值。

主要介绍下面4个功能:

1、复制文件描述符(F_DUPFD、F_DUPFD_CLOEXEC);

(1)F_DUPFD(int)


F_DUPFD(int) 表示使用 F_DUPFD 作为cmd时,第三个参数需要传入int型数据。

cmd为F_DUPFD表示复制文件描述符fd。调用成功会返回新的描述符。新描述符使用大于或等于arg参数的编号最低的可用文件描述符复制文件描述符fd。新描述符与f似共享同一文件表项。但是,新描述符有它自己的一套文件描述符标志,其FD_CLOEXEC文件描述符标志被清除〈这表示该描述符在 exec 时仍保持打开状态)。

(2 )F_DUPFD_CLOEXEC(int)

F_DUPFD_CLOEXEC(int) 表示使用 F_DUPFD_CLOEXEC 作为cmd时,第三个参数需要传入int型数据。

cmd为F_DUPFD_CLOEXEC的功能与F_DUPFD类似,区别在于F_DUPFD_CLOEXEC在复制的同时会设置文件描述符标志FD_CLOEXEC,表示在执行exec系列函数后,该描述符会关闭。

2、获取/设置文件描述符标志(F_GETFD、F_SETFD);

当前只定义了一个文件描述符标志FD_CLOEXEC。用来表示该描述符在执行完fork+exec系列函数创建子进程时会自动关闭,以防止它们被传递给子进程。为什么要这样做呢?

因为当一个进程调用exec系列函数(比如execve)来创建子进程时,所有打开的文件描述符都会被传递给子进程。如果文件描述符没有设置FD_CLOEXEC标志,这些文件将保持打开状态并继续对子进程可见。这可能导致潜在的安全风险或者意外行为。

F_GETFD(void) :表示使用 F_GETFD 作为cmd时,不需要传入第三个参数。
功能:获取文件描述符标志。
返回值:

成功返回文件描述符标志
失败返回 -1.


F_SETFD(int):表示使用 F_SETFD 作为cmd时,传入第三个参数是int型的。
功能:设置文件描述符标志,第三个参数传入新的标志值。
返回值:

成功返回 0
失败返回 -1.


文件描述符的FD_CLOEXEC标志可以通过三个方法得到:

1、调用open函数是,指定 O_CLOEXEC
2、通过fcntl函数使用F_DUPFD_CLOEXEC复制文件描述符,新的描述符就是FD_CLOEXEC
3、通过fcntl函数使用F_SETFD直接设置FD_CLOEXEC。

3、获取/设置文件状态标志(F_GETFL、F_SETFL);

文件状态标志如下表:

F_GETFL(void) :表示使用 F_GETFL 作为cmd时,不需要传入第三个参数。
功能:获取文件状态标志。
返回值:

成功返回文件状态标志
失败返回 -1.
访问方式标志:O_RDONLY 、O_WRONLY、O_RDWR。这3个值是互斥的,因此首先必须用屏蔽O_ACCMODE取得访问方式位,然后将结果与这3个值中的每一个相比较。

F_SETFL(int):表示使用 F_SETFL 作为cmd时,传入第三个参数是int型的。
功能:设置文件状态标志,第三个参数传入新的文件状态标志值。
返回值:

成功返回 0
失败返回 -1.
在Linux上,只能设置这5个文件状态标志:O_APPEND、 O_ASYNC、 O_DIRECT、 O_NOATIME、O_NONBLOCK,其中最常用的是将文件描述符设置成非阻塞(O_NONBLOCK),特别是在网络编程中很常见。

4、获取/设置记录锁(F_GETLK、F_SETLK、F_SETLKW);

Linux实现了POSIX标准化的传统(“进程相关”)UNIX记录锁。
记录锁(record locking)的功能是:当一个进程正在读或修改文件的某个部分时,它可以阻止其他进程修改同一文件区。对于UNIX系统而言,“记录”这个词是一种误用,因为UNIX系统内核根本没有使用文件记录这种概念。更适合的术语可能是字节范围锁(byte-rangelocking),因为它锁定的只是文件中的一个区域(也可能是整个文件)。

F_SETLK、F_SETLKW和F_GETLK用于获取、释放和测试记录锁(也称为字节范围、文件段或文件区域锁)的存在。使用记录锁时,第三个参数是指向struct flock结构的指针。

struct flock
{...short l_type;//锁的类型:F_RDLCK(读锁)、F_WRLCK(写锁)、F_UNLCK(解锁)short l_whence;//偏移的起点:SEEK_SET、SEEK_CUR、SEEK_END off_t l_start; //锁区偏移,从l_whenceoff_t l_len;  //锁区长度(字节)pid_t l_pid; //阻塞我们加锁的进程ID...
}

F_SETLK(struct flock *):表示使用 F_SETLK 作为cmd时,传入第三个参数是struct flock *型的。
在锁的l_where、l_start和l_len字段指定的字节上设置锁(当l_type为F_RDLCK或F_WRLCK时)或释放锁(当l_type为F_UNLOCK时)。如果另一个进程持有冲突锁,则此调用返回-1并将errno设置为EACCES或EAGAIN。(本例中返回的错误因实现而异,因此POSIX需要一个可移植的应用程序来检查这两个错误。)

F_SETLKW(struct flock *):表示使用 F_SETLKW 作为cmd时,传入第三个参数是struct flock *型的。
类似于F_SETLK(命名中的W表示等待(wait)),但如果文件上持有冲突的锁,则等待该锁释放。如果在等待时捕获到信号,则调用将中断,并且(在信号处理程序返回后)立即返回(返回值为-1,errno设置为EINTR;)。

F_GETLK(struct flock *):表示使用 F_GETLK 作为cmd时,传入第三个参数是struct flock *型的。
判断由struct flock *(第三个参数)所描述的锁是否会被另外一把锁所排斥(阻塞)。如果存在一把锁,它阻止创建由第三个参数(struct flock *)所描述的锁,则把该现存锁的信息写到第三个参数(struct flock *)指向的结构中。如果不存在这种情况,则除了将l_type设置为F_UNLCK之外,第三个参数所指向结构中的其他信息保持不变。

tcgetattr()和tcsetattr()函数

头文件<termios.h>

tcgeattr()

tcgetattr函数,用来获取终端参数,成功返回零;失败则返回非零,发生失败接口将设置errno标识。

tcsetattr()
tcsetattr函数,用来设置终端参数,成功返回零;失败则返回非零,发生失败接口将设置errno标识。

cfsetispeed()和cfsetospeed()、cfsetspeed()函数

头文件<termios.h>和<unistd.h>需要用到termios结构体

cfsetispeed()函数

设置输入波特率。

注:设置波特率有专门的函数,用户不能直接通过位掩码来操作。

cfsetospeed()函数

设置输出波特率。

注:设置波特率有专门的函数,用户不能直接通过位掩码来操作。

cfsetspeed()函数

设置波特率。

注:设置波特率有专门的函数,用户不能直接通过位掩码来操作。

4.配置控制标志c_cflag

options.c_cflag |=(CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~CRTSCTS;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;

常见的配置操作

这里讲一下 |= 和| 以及&=和&

|=|&=& 是用于位运算的操作符,通常用于修改、设置、或清除变量中的特定位。

|(按位或运算符)

|按位或运算符,对两个数的二进制位逐位进行比较,如果其中一个位为 1,则结果的对应位为 1,否则为 0

int a = 5;  // 二进制:0101
int b = 3;  // 二进制:0011
int c = a | b; // 结果:0111,即 7

|=(按位或赋值运算符)

|=按位或赋值运算符,用于将变量与另一个值进行按位或运算,并将结果赋值回该变量。

int a = 5;    // 二进制:0101
a |= 3;       // 二进制:0011
// a = 0101 | 0011 = 0111,即 7

&(按位与运算符)

&按位与运算符,对两个数的二进制位逐位比较,只有当对应位都为 1 时,结果的该位才为 1,否则为 0。

int a = 5;  // 二进制:0101
int b = 3;  // 二进制:0011
int c = a & b; // 结果:0001,即 1

&=(按位与赋值运算符)

&=按位与赋值运算符,将变量与另一个值按位与运算,并将结果赋值回该变量。

int a = 5;    // 二进制:0101
a &= 3;       // 二进制:0011
// a = 0101 & 0011 = 0001,即 1

|=通常同于设置控制位,&= 通常用于清除(置零)特定位~FLAG 是取反操作,用于生成 FLAG 的反码,即将 FLAG 位清零。

5.While循环读取串口数据

read()函数

头文件 <unistd.h>

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

read函数是Linux系统API中的一员,它的作用是:从指定的文件中读取数据。
参数:fd //传入的是一个文件描述符,它是open函数的返回值。可通过open函数得到
参数:buf //传入的是一个数组的名字,是用来暂存已经读取到的数据用的。
参数:count //一次性读取多少个数据到数组中,一般是数组的大小。

如果成功,则返回实际读取到的字节数。(是一个ssize_t类型的一个数)
如果失败,返回-1,并且将errno设置为合适的错误原因。

close()函数

头文件 <unistd.h>

int close(int fd);

返回值:成功返回0,出错返回-1并设置errno

参数fd是要关闭文件描述符。当一个进程终止时,内核对该进程所有尚未关闭的文件描述符调用close关闭,所以即使用户程序不调用close,在终止时内核也会自动关闭它打开的所有文件。

由open返回的文件描述符一定是该进程尚未使用的最小的描述符。


附上完整串口通信打印数据代码

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
int main()
{int	fd;struct termios options;//termios结构体一般包括char buffer[255];fd =open("/dev/pts/7",O_RDWR | O_NOCTTY | O_NDELAY);//O_RDWR:以读写模式打开文件或设备
//O_NOCTTY:不将打开的文件或设备分配为进程的控制终端
//O_NDELAY:非阻塞模式if (fd ==-1){printf("Error opening serial port!\n");return -1;}fcntl(fd,F_SETFL,0);//fcntl系统调用可以用来对已打开的恩间描述符进行各种控制操作以改变已打开文件的各种属性,//F_SRTFL:设置文件状态标志tcgetattr(fd,&options);//获取终端相关参数//设置输入串口波特率cfsetispeed(&options,B9600);//设置输出串口波特率cfsetospeed(&options,B9600);//|:按为或 |=:按位或赋值options.c_cflag |=(CLOCAL | CREAD);//&:按位与  &=:按位与赋值操作//用于清除 c_cflag 中的PARENB标志位options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;options.c_cflag &= ~CSIZE;options.c_cflag |= CS8;options.c_cflag &= ~CRTSCTS;options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);options.c_oflag &= ~OPOST;tcsetattr(fd,TCSANOW,&options);while(1){int bytes_read =read(fd,buffer,sizeof(buffer));if(bytes_read>0){//如果读取到的数据量 bytes_read 大于 0,则数据被写入 buffer,添加字符串终止符 \0 后输出到终端。buffer[bytes_read]='\0';printf("%s",buffer);}}close(fd);return 0;}


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

相关文章

Django-中间件(切面编程AOP)

自定义中间件 官网&#xff1a;中间件 | Django 文档 | Django 中间件使用多就在主应用创建&#xff0c;仅限于子应用就在子引用中创建中间件文件.py 之后在settings.py文件中去配置中间件,运行的时候会自动调用中间件 def simple_middleware(get_response):def middleware…

在 .NET 8 Web API 中实现 Entity Framework 的 Code First 方法

本次介绍分为3篇文章&#xff1a; 1&#xff1a;.Net 8 Web API CRUD 操作.Net 8 Web API CRUD 操作-CSDN博客 2&#xff1a;在 .Net 8 API 中实现 Entity Framework 的 Code First 方法https://blog.csdn.net/hefeng_aspnet/article/details/143229912 3&#xff1a;.NET …

rtp协议:rtcp包格式和传输间隔

RTP Control Protocol -- RTCP-rtp控制协议 实时传输控制协议&#xff08;RTCP&#xff09;基于对会话中的所有参与者定期传输控制包&#xff0c;使用与数据包相同的分发机制。底层协议必须提供数据包和控制包的多路复用&#xff0c;例如使用UDP时使用不同的端口号。RTCP执行四…

shodan搜索引擎——土豆片的网安之路

工作原理&#xff1a; 在服务器上部署了各种扫描器&#xff0c;如漏洞扫描器&#xff0c;硬件扫描器&#xff0c;目录扫描器等等&#xff0c;24小时不停的扫描&#xff0c;批量对IP地址扫描 优点&#xff1a;方便&#xff0c;很快得到最新扫描结果&#xff0c;漏洞信息 缺点…

数据挖掘:基于电力知识图谱的客户画像构建实施方案

基于电力知识图谱的客户画像构建实施方案 本技术方案分为两大部分。第一部分为基于电力知识图谱的客户画像研究技术。第一部分主要介绍该项目将用到的技术&#xff0c;包括整体框架、知识图谱技术、客户画像技术。 第二部分为基于电力知识图谱的客户画像标签体系。第二部分将…

论文阅读(二十六):Dual Attention Network for Scene Segmentation

文章目录 1.Introduction3.DANet3.1Position Attention Module3.2Channel Attention Module 论文&#xff1a;Dual Attention Network for Scene Segmentation   论文链接&#xff1a;Dual Attention Network for Scene Segmentation   代码链接&#xff1a;Github 1.Intr…

华为交换机堆叠

堆叠方式 堆叠卡堆叠&#xff1a; 堆叠卡堆叠又可以分为两种情况&#xff1a; 交换机之间通过专用的堆叠插卡ES5D21VST000及专用的堆叠线缆连接。堆叠卡集成到交换机后面板上&#xff0c;交换机通过集成的堆叠端口及专用的堆叠线缆连接。 业务口堆叠&#xff1a; 业务口堆…

UWA Gears:Frame Capture模式 - 着色器查看器

UWA Gears 是UWA最新发布的无SDK性能分析工具。针对移动平台&#xff0c;提供了实时监测和截帧分析功能&#xff0c;帮助您精准定位性能热点&#xff0c;提升应用的整体表现。 在上周的文章中&#xff0c;我们详细介绍了网格查看器的功能&#xff0c;介绍如何通过网格数据优化…