C语言实现串口通信


前言

       在学习4G拨号前,首先要了解清楚串口通信的工作原理。搞明白了之后,在现有一个Rx链接了Tx的一个串口上调试实现自收自发的串口通信程序。


一、要掌握的知识

1.串口通信

      在上一篇博客中写了关于串口通信方面的的知识。总的来说,我们在Linux下编写串口通信程序时,必须对起始位、数据位、奇偶校验位、停止位、波特率进行初始化。特别是波特率,输入和输出要保持一致。

2.struct termios 结构体及相关函数

termios 函数族提供了一个常规的终端接口,用于控制非同步通信端口。简单来说就是通过这个结构体来对串口进行新的配置。

先来看一下struct termios结构体成员:

struct termios{
   
				unsigned short c_iflag; /* 输入模式标志*/
                unsigned short c_oflag; /* 输出模式标志*/
                unsigned short c_cflag; /* 控制模式标志*/
                unsigned short c_lflag; /*区域模式标志或本地模式标志或局部模式*/
                unsigned char c_line; /*行控制line discipline */
                unsigned char c_cc[NCC]; /* 控制字符特性*/
              };

2.1 c_iflag 输入模式标志

c_iflag:输入模式标志,控制终端输入方式,具体参数如表1所示。

在这里插入图片描述

2.2 c_oflag 输出模式标志

c_oflag:输出模式标志,控制终端输出方式,具体参数如表2所示。

在这里插入图片描述

2.3 c_cflag 控制模式标志

c_cflag:控制模式标志,指定终端硬件控制信息,具体参数如表3所示

在这里插入图片描述

2.4 c_lflag 区域模式标志或本地模式标志或局部模式

c_lflag:本地模式标志,控制终端编辑功能,具体参数如表4所示。

在这里插入图片描述

2.4 c_cc[NCC] 控制字符特性

c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等。c_cc中定义了如表5所示的控制字符。

在这里插入图片描述

2.5 tcsetattr() 与 tcgetattr()函数

2.5.1 tcsetattr()函数

是用于设置终端参数的函数。成功的时候返回0,失败的时候返回-1,并设置errno的值。

函数原型 :int tcsetattr(int fd, int optional_actions, conststruct termios *termios_p);

fd:打开的终端文件描述符;
optional_actions: 控制修改起作用的时间;

optional_actions可以取如下的值:
TCSANOW: 不等数据传输完毕就立即改变属性。
TCSADRAIN: 等待所有数据传输结束才改变属性。
TCSAFLUSH: 等待所有数据传输结束,清空输入输出缓冲区才改变属性。

termios_p: 保存了要修改的参数;

错误信息:

EBADF: 非法的文件描述符。
EINTR: tcsetattr函数调用被信号中断。
EINVAL: 参数optional_actions使用了非法值,或参数termios中使用了非法值。
ENOTTY: 非终端的文件描述符。

2.5.2 tcgetattr()函数

tcgetattr函数用于获取与终端相关的参数。返回的结果保存在termios 结构体中。

函数原型:int tcgetattr(int fd, struct termios *termios_p);
fd:打开的终端文件描述符;
termios *termios_p: 用来保存从终端获取到的相关参数。

2.6 cfsetispeed() 与 cfsetospeed()

cfsetispeed() 与 cfsetospeed()函数分别用于设置输入和输出的波特率

函数原型

int cfsetispeed(struct termios *termios_p, speed_t speed); int
cfsetospeed(struct termios *termios_p, speed_t speed);

参数说明:

struct termios*termptr:指向termios结构的指针;
speed_t speed: 需要设置的输出波特率;

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

二、绘制流程图和设计代码

对于串口模块来说,可以把程序分别封装为下面几个函数:
1、Linux下一切皆文件,所以又开就有关。设计两个函数用于串口的开关,在打开串口时候我们就因该对串口进行初始化所以设计如下两个函数用于串口的开关

1、int serial_open(serial_t *serial, char *devname, long baudrate, char *conf );
2、int serial_close(serial_t *serial);

2、串口间要实现通信,就得有发和接收两个函数。

3、int serial_send(serial_t *serial, char *sbuf, int sbuf_len);
4、int serial_recv(int fd, char *rbuf, int rbuf_len, int timeout);

由于串口是一个模块所以所有的函数应该封装为一个.c和一个.h文件里

serial.h

#ifndef _SERIAL_H
#define _SERIAL_H

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>

#define SERIALNAME_LEN 128

typedef struct  serial_s{
   

        int     fd;             //串口文件描述符
        long     Baudrate;               //波特率
        int     Databits;               //数据位
        char    Parity;         //奇偶校验位
        int     Stopbits;               //停止位
        int     mSend;          //一次发送的最大数据
        char    SerialName[SERIALNAME_LEN];     //端口名字
        struct  termios OldTermios;     //保存原来的端口配置

}serial_t;

int serial_open(serial_t *serial, char *devname, long baudrate, char *conf /*"8N1N"*/);
int serial_close(serial_t *serial);
int serial_send(serial_t *serial, char *sbuf, int sbuf_len);
int serial_recv(int fd, char *rbuf, int rbuf_len, int timeout);


#endif

1.串口的打开和关闭

1.1打开串口

serial_open()函数
int serial_open(serial_t *serial, char *devname, long baudrate, char *conf)
{
   

        int re
  • 19
    点赞
  • 171
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值