树莓派3B串口通信

树莓派3B串口通信

文章目录

  • 树莓派3B串口通信
    • 一、串口的基本认知
      • 1.1 关于电器标准和协议:
        • RS232
        • RS422
        • RS485
      • 1.2 关于串口的电平:
        • UART
        • RS232电平
        • TTL电平
      • 1.3 串口通信引脚接线:
      • 1.4 串口的通信协议:
    • 二、树莓派串口通信开发
      • 2.1 树莓派的串口引脚:
      • 2.2 串口调试工具:
      • 2.3 查看串口驱动文件:
      • 2.4 基于WiringPi的串口通信:
      • 2.5 不使用WiringPi库自己实现串口通信:

一、串口的基本认知

  • 串口通信(Serial Communication)是一种在计算机和外部设备或计算机之间进行的串行数据传输方式。它采用逐位(bit)顺序传输数据,相对于并行通信而言,**串口通信使用的数据线较少,在远距离通信中可以节约通信成本。**串口通信广泛应用于各种设备之间的数据传输,如计算机与外设(如打印机、鼠标、键盘等)、微控制器之间的通信等。

  • 串口通信的基本参数包括波特率(数据传输速率)、数据位(每个数据包的位数)、停止位(用于表示单个数据包的结束)、奇偶校验位(用于错误检测)等。这些参数需要在通信双方之间预先约定,以确保数据的正确传输和解析。

  • 串口通信的主要优点包括使用简单的线路结构、成本较低、适用于远距离通信等。然而,它也有一些缺点,如传输速度相对较慢、传输距离受限等。因此,在选择通信方式时,需要根据具体的应用场景和需求进行权衡。

1.1 关于电器标准和协议:

串行接口按电气标准及协议来分包括RS-232-CRS-422RS485等。RS-232-C、RS-422与RS-485标准只对接口的电气特性做出规定,不涉及接插件、电缆或协议。

RS232

​ 也称标准串口,最常用的一种[串行通讯接口,比如我们的电脑主机的9针串口 ,最高速率为20kb/s,RS-232是为点对点(即只用一对收、发设备)通讯而设计的,其传送距离最大为约15米。所以RS-232适合本地设备之间的通信

在这里插入图片描述

RS422

由于接收器采用高输入阻抗和发送驱动器比RS232更强的驱动能力,故允许在相同传输线上连接多个接收节点,最多可接10个节点。即一个主设备(Master),其余为从设备(Slave),从设备之间不能通信,所以RS-422支持点对多的双向通信。

RS-422的最大传输距离为1219米,最大传输速率为10Mb/s。平衡双绞线的长度与传输速率成反比

RS485

是从RS-422基础上发展而来的,无论四线还是二线连接方式总线上可多接到32个设备。

在这里插入图片描述

1.2 关于串口的电平:

UART

异步串行是指UART(Universal Asynchronous Receiver/Transmitter),通用异步接收/发送。UART包含TTL电平的串口和RS232电平的串口

RS232电平
  • 逻辑1为-3~-15V的电压,逻辑0为 3~15V的电压

笔记本通过RS232电平和单片机通信

在这里插入图片描述

TTL电平
  • TTL是(Transistor-Transistor Logic),即晶体管-晶体管逻辑的简称,它是计算机处理器控制的设备 内部各部分之间通信的标准技术。TTL电平信号应用广泛,是因为其数据表示采用二进制规定, +5V等价于逻辑”1”,0V等价于逻辑”0”。

  • 数字电路中,由TTL电子元器件组成电路的电平是个电压范围,规定: 输出高电平>=2.4V,输出低电平<=0.4V; 输入高电平>=2.0V,输入低电平<=0.8V

  • 笔记本电脑通过TTL电平与单片机进行通信,需要将电脑的USB转成TTL电平,需要用到CH340工具将USB转换成TTL电平实现电脑与MCU之间的通信

在这里插入图片描述

1.3 串口通信引脚接线:

  • RXD:数据接收引脚,
  • TXD:数据发送引脚
  • VCC:电源正极
  • GND:电源负极

在这里插入图片描述

1.4 串口的通信协议:

串口通信协议中的波特率、奇偶检验位和停止位等参数是非常重要的,它们决定了数据的传输方式和数据的完整性检查。以下是一些常见的串口通信参数:

  • 波特率(Baud Rate)

波特率是串口通信中的传输速率,它表示每秒传输的比特数。常见的波特率包括 9600、115200、57600 等。

通信的双方必须使用相同的波特率。波特率过高可能会导致数据传输错误,因此需要根据硬件和通信距离来选择适当的波特率。

  • 数据位(Data Bits)

数据位指定每个数据字节中的位数,通常为 5、6、7 或 8 位。大多数情况下,使用 8 位数据位以支持 8 位的二进制数据。

  • 奇偶检验位(Parity)

奇偶检验位用于检测数据传输中的错误。通常有以下几种选项: 无校验位:不使用奇偶检验位。 奇校验位:确保数据位中有奇数个 “1”。 偶校验位:确保数据位中有偶数个 “1”。 奇偶检验位通常用于检测单比特错误。

  • 停止位(Stop Bits)

停止位表示数据字节的结束。通常有 1 位和 2 位停止位选项,其中 1 位停止位是最常见的选择。 这些参数通常一起组合,以确定数据的帧格式。例如,常见的串口通信设置是:

波特率:9600 数据位:8 无奇偶检验位 1 位停止位 这意味着每个数据帧由 10 位组成:1 位起始位、8 位数据位、无奇偶检验位和 1 位停止位。

正确配置这些参数对于串口通信非常重要,因为通信的双方必须使用相同的参数,否则会导致数据传输错误。通常,串口设备的规格表明了所需的通信参数设置。在编程中,你需要使用相应的库函数来设置这些参数,以确保正确的数据传输和校验。

二、树莓派串口通信开发

2.1 树莓派的串口引脚:

在这里插入图片描述

前面我们在对树莓派刷机的时候,默认串口是接到蓝牙上面的,因为想要看到树莓派的启动过程,所以我们把串口配置到了调试信息上,后来我们树莓派配置完成以后我们又把串口配置成默认的了,所以这里就不需要配置了,如果想要配置我们这样做:

  • 修改 /boot/cmdline.txt:
1. sudo vi /boot/cmdline.txt
2. 将“console=serial,115200”删除

在这里插入图片描述

然后我们保存退出,接着执行下面指令重启树莓派:

sudo reboot

2.2 串口调试工具:

在这里插入图片描述

使用安信可串口调试助手,亲测好用,可以调节波特率,可以设置快捷键等。

2.3 查看串口驱动文件:

Linux系统一切皆文件,每一个硬件设备对应一个文件,进入下面路径查看串口文件:

cd /dev

在这里插入图片描述

2.4 基于WiringPi的串口通信:

#include <stdio.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>int fd;/* 发送线程函数 */
void* Sendhandler(void* arg)
{char *sendBuffer = NULL;                                    //发送缓冲区sendBuffer = (char *)malloc(128 * sizeof(char));             //分配发送缓冲区内存while(1){memset(sendBuffer, '\0', 128);                           //清空发送缓冲区printf("请输入要发送的内容:\n");scanf("%s", sendBuffer);                              //输入要发送的内容getchar();while(*sendBuffer!= '\0'){serialPutchar(fd, *sendBuffer);                         //发送数据sendBuffer++;                                           //指向下一个位置}}pthread_exit(NULL);                                       //退出线程
}/* 接收线程函数 */
void* Recvhandler(void* arg)                                    
{char readBuffer[128];                                       //接收缓冲区while(1){int len = serialDataAvail(fd);                         //检查串口是否有数据if(len > 0){memset(readBuffer, '\0', 128);                      //清空接收缓冲区for(int i=0; i<len; i++){readBuffer[i] = serialGetchar(fd);                //读取串口数据}printf("接收到的收据是: %s\n", readBuffer);}}pthread_exit(NULL);                                       //退出线程
}int main()
{pthread_t idSend;                                   //发送线程IDpthread_t idRecv;                                   //接收线程IDfd = serialOpen("/dev/ttyAMA0", 9600);              //打开串口if(fd < 0){printf("打开串口设备失败!\n");return -1;}pthread_create(&idSend, NULL, Sendhandler, NULL);   //创建发送线程pthread_create(&idRecv, NULL, Recvhandler, NULL);   //创建接收线程if(wiringPiSetup() == -1){                          //初始化wiringPiprintf("初始化wiringPi失败! \n");}pthread_join(idSend, NULL);                         //等待发送线程退出pthread_join(idRecv, NULL);                         //等待接收线程退出serialClose(fd);                                    //关闭串口return 0;
}

在这里插入图片描述

2.5 不使用WiringPi库自己实现串口通信:

#ifndef __MYSERIALTOOL_H__
#define __MYSERIALTOOL_H__/*
* @Author: <NAME> 打开指定的串口设备,并设置波特率
*
* @param device 串口设备名称,如"/dev/ttyUSB0"
* @param baud 波特率,如9600、115200等
* @return 成功返回文件描述符,失败返回-1
*/
int mySerialOpen(const char *device, const int baud);/*
* @Author: 向指定的串口设备发送字符串
*
* @param fd 串口设备文件描述符
* @param str 要发送的字符串 
* @return 无
*/
void mySerialSendString(const int fd, const char *str);/*
* @Author: 从指定的串口设备读取字符串
*
* @param fd 串口设备文件描述符              
* @param buffer 读取到的字符串存放的缓冲区      
* @return 读取到的字符串的长度,失败返回-1
*/
int mySerialReadString(const int fd, char *buffer);#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>/*打开指定的串口设备,并设置波特率*/
int mySerialOpen(const char *device, const int baud)
{struct termios options; // 串口配置参数speed_t myBaud;         // 波特率int status, fd;         // 状态和文件描述符//根据传入的波特率参数设置相应的波特率switch(baud){case 9600:myBaud = B9600;break;case 115200:myBaud = B115200;break;default:printf("不支持的波特率!\n");return -2;}  //打开串口设备if( (fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY)) == -1){printf("无法打开串口设备\n");return -1;}// 设置文件描述符的标志为读写模式fcntl(fd, F_SETFL, O_RDWR);// 获取当前串口配置tcgetattr(fd, &options);// 设置串口为原始模式,无特殊处理cfmakeraw(&options);// 设置输入波特率cfsetispeed(&options, myBaud);// 设置输出波特率cfsetospeed(&options, myBaud);// 清除标志位并设置数据格式options.c_cflag |= (CLOCAL | CREAD);options.c_cflag &= ~PARENB; // 无奇偶校验位options.c_cflag &= ~CSTOPB; // 1个停止位options.c_cflag &= ~CSIZE; // 清除数据位options.c_cflag |= CS8; // 设置为8位数据位options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 非规范模式,不执行输入处理options.c_oflag &= ~OPOST; // 输出处理// 设置读取时的超时和最小接收字符数options.c_cc[VMIN] = 0;options.c_cc[VTIME] = 100; // 10秒超时// 应用串口配置tcsetattr(fd, TCSANOW, &options);// 使用ioctl设置串口的DTR和RTS信号ioctl(fd, TIOCMGET, &status);status |= TIOCM_DTR;status |= TIOCM_RTS;ioctl(fd, TIOCMSET, &status);// 短暂延时usleep(10000); // 10毫秒延时return fd; // 返回文件描述符
}/*向指定的串口设备发送字符串*/
void mySerialSendString(const int fd, const char *str)
{int ret;ret = write(fd, str, strlen(str));            // 发送字符串if(ret == -1){printf("串口发送失败!\n");exit(-1);                                 // 发送失败,退出程序}
}/*从指定的串口设备读取字符串*/
int mySerialReadString(const int fd, char *buffer)
{int n_read;n_read = read(fd, buffer, 32);                // 读取串口数据if(n_read == -1){printf("串口读取失败!\n");exit(-1);                                 // 读取失败,退出程序}
}
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include "mySerialTool.h"int fd;void* readSerial(void* arg)
{char readBuffer[32] = {'\0'};                                               //定义读缓冲区while(1){memset(readBuffer, '\0', sizeof(readBuffer));                           //清空缓冲区int n_read = mySerialReadString(fd, readBuffer);                        //读取串口数据printf("从串口中读取的数据是:%s,读取了%d个字节\n", readBuffer, n_read);}pthread_exit(NULL);                                                         //线程退出
}void* sendSerial(void* arg)
{char sendBuffer[32] = {'\0'};                                               //定义发送缓冲区while(1){memset(sendBuffer, '\0', sizeof(sendBuffer));                           //清空缓冲区printf("请输入要发送的数据:\n");scanf("%s", sendBuffer);                                               //输入要发送的数据mySerialSendString(fd, sendBuffer);                                    //发送数据}pthread_exit(NULL);                                                         //线程退出
}   int main(int argc, char **argv)
{pthread_t readThread;                                   //读线程IDpthread_t sendThread;                                   //发送线程IDchar deviceName[32] = {'\0'};if(argc < 2){                                           //查看命令行参数是否存在printf("Usage: %s /dev/ttyAMA0\n");return -1;}strcpy(deviceName, argv[1]);                            //将命令行参数赋值给deviceNamefd = mySerialOpen(deviceName, 9600);                    //打开串口if(fd < 0){printf("打开串口设备失败\n");return -1;}pthread_create(&readThread, NULL, readSerial, NULL);    //创建读线程pthread_create(&sendThread, NULL, sendSerial, NULL);    //创建发送线程pthread_join(readThread, NULL);                         //等待读线程结束pthread_join(sendThread, NULL);                         //等待发送线程结束while(1){sleep(5);}close(fd);                                              //关闭串口return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/53417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TensorRT-For-YOLO-Series项目:实现yolov10模型的python-tensorrt推理(对比int8与fp16推理差异)

项目地址&#xff1a;https://github.com/Linaom1214/TensorRT-For-YOLO-Series/tree/cuda-python 算法支持状态&#xff1a; 2024.6.16 Support YOLOv9, YOLOv10, changing the TensorRT version to 10.0 2023.8.15 Support cuda-python 2023.5.12 Update 2023.1.7 support YO…

观趋势 谋发展 2024 SSHT上海智能家居展有哪些创新呈现?

引言&#xff1a;大数跨境发布的《2024全球智能家居市场洞察报告》显示&#xff0c;智能家居市场正迎来快速增长&#xff0c;预计从2024年的1215.9亿美元增长至2032年的6332.0亿美元&#xff0c;复合年增长率为22.9%。 近年来&#xff0c;随着物联网、AI等底层技术的飞速进步&…

kubernetes微服务之ingress-nginx

目录 1 ingress-nginx 介绍 2 Ingress-nginx 的工作原理 3 使用 Ingress-nginx 的步骤 4 部署 ingress &#xff1a; 4.1 开启ipvs 模式 4.2 下载部署文件 4.3 上传镜像到harbor 4.4 修改文件中镜像地址,与harbor仓库路径保持一致 4.5 检查是否running 4.6 将ingress的命名…

轻松上手,高效产出:音频剪辑工具年度精选

不知道你有没有拍vlog记录生活的习惯&#xff0c;有时候视频里穿插进自己的声音能让视频更加丰富贴上自己的标签。这次我们一起探讨当下有哪些好用的在线音频剪辑工具。 1.FOXIT音频剪辑 链接直达>>https://www.foxitsoftware.cn/audio-clip/ 这个工具是一款专业的音…

Java 数据类型详解:基本数据类型与引用数据类型

在 Java 编程语言中&#xff0c;数据类型主要分为两大类&#xff1a;基本数据类型和引用数据类型。理解这两种类型的区别、使用场景及其转换方式是学习 Java 的基础。本文将深入探讨这两类数据类型的特点&#xff0c;并展示自动类型转换、强制类型转换以及自动拆箱和封箱的使用…

虚拟现实辅助工程技术助力多学科协同评估

在当今高速发展的经济环境中&#xff0c;制造业面临着多重挑战&#xff0c;包括提高产品性能、压缩设计周期、实现轻量化设计和降低成本。为了有效应对这些挑战&#xff0c;多学科协同评估成为缩短研发周期和提升研制质量的关键手段。 传统的多学科评估面临着数据孤立与融合困难…

《‌黑神话:‌悟空》‌游戏攻略‌

时光荏苒&#xff0c;岁月如梭&#xff0c;不知不觉已经来到了2024年的9月份了。 ‌突然想写一篇关于《‌黑神话&#xff1a;‌悟空》‌的游戏攻略‌。 在《‌黑神话&#xff1a;‌悟空》‌这款以中国古代名著《‌西游记》‌为背景的动作角色扮演游戏中&#xff0c;‌玩家将扮…

LeetCode 热题 100 回顾9

干货分享&#xff0c;感谢您的阅读&#xff01;原文见&#xff1a;LeetCode 热题 100 回顾_力code热题100-CSDN博客 一、哈希部分 1.两数之和 &#xff08;简单&#xff09; 题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标…

【redis】redis的特性和主要应用场景

文章目录 redis 的特性在内存中存储数据可编程的扩展能力持久化集群高可用快 redis 的应用场景实时数据存储缓存消息队列 redis 的特性 redis 的一些特性&#xff08;优点&#xff09;成就了它 在内存中存储数据 In-memory data structures MySQL 主要是通过“表”的方式来…

JavaEE-HTTPHTTPS

目录 HTTP协议 一、概念 二、http协议格式 http请求报文 http响应报文 URL格式 三、认识方法 四、认识报头 HTTP响应中的信息 HTTPS协议 对称加密 非对称加密 中间人攻击 解决中间人攻击 HTTP协议 一、概念 HTTP (全称为 "超⽂本传输协议") 是⼀种应⽤…

Mysql中的锁机制详解

一、概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。 在数据库中&#xff0c;除了传统的计算资源&#xff08;如CPU、RAM、I/O等&#xff09;的争用以外&#xff0c;数据也是一种供需要用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决…

一文讲懂Spring Event事件通知机制

目录 一 什么是spring event 二 怎么实现spring event 一 什么是spring event 我不会按照官方的解释来说什么是spring event&#xff0c;我只是按照自己的理解来解释&#xff0c;可能原理上会和官方有偏差&#xff0c;但是它的作用和功能就是这个&#xff0c;我更加偏向于从他…

详解React setState调用原理和批量更新的过程

1. React setState 调用的原理 setState目录 1. React setState 调用的原理2. React setState 调用之后发生了什么&#xff1f;是同步还是异步&#xff1f;3. React中的setState批量更新的过程是什么&#xff1f; 具体的执行过程如下&#xff08;源码级解析&#xff09;&#x…

安卓13带有系统签名的应用不能正常使用webview 调用webview失败 系统应用app apk

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.彩蛋1.前言 android版本高一些的平台,经常会遇到一些权限安全问题,像客户的应用如果带有系统签名,会导致不能正常使用webview问题。 2.问题分析 我们log信息,可以发现下面的提示: Fo…

网络层ip协议

一.概念 ip协议主要是为了在复杂的网络环境中确定一个合适的路径来传输主机间的数据。简单来说就是用来确定主机的位置。 ip协议中的一些设备如下&#xff1a; 主机: 配有 IP 地址, 但是不进行路由控制的设备;路由器: 即配有 IP 地址, 又能进行路由控制;节点: 主机和路由器的统…

传统CV算法——边缘算子与图像金字塔算法介绍

边缘算子 图像梯度算子 - Sobel Sobel算子是一种用于边缘检测的图像梯度算子&#xff0c;它通过计算图像亮度的空间梯度来突出显示图像中的边缘。Sobel算子主要识别图像中亮度变化快的区域&#xff0c;这些区域通常对应于边缘。它是通过对图像进行水平和垂直方向的差分运算来…

5.2.数据结构-c/c++二叉树详解(下篇)(算法面试题)

本章所有代码请见&#xff1a;5.3.数据结构-c/c二叉树代码-CSDN博客 上篇:5.数据结构-c/c二叉树详解(上篇)&#xff08;遍历方法&#xff0c;完全二叉树&#xff09;-CSDN博客 目录 1 求二叉树 第k层的节点 2 查找一个节点是否在二叉树中 3 求二叉树节点的个数 4 求二叉树…

数据结构(邓俊辉)学习笔记】排序 1——快速排序:算法A

文章目录 1. 分而治之2. 轴点3. 构造轴点4. 单调性 不变性5. 实例 1. 分而治之 主题就是排序。实际上我们对于排序问题并不陌生。你应该记得在最开始的几章&#xff0c;我们就分别介绍过起泡排序、插入排序、选择排序以及归并排序&#xff0c;而在介绍散列技术时&#xff0c;我…

自定义TextView实现结尾加载动画

最近做项目&#xff0c;仿豆包和机器人对话的时候&#xff0c;机器人返回数据是流式返回的&#xff0c;需要在文本结尾添加加载动画&#xff0c;于是自己实现了自定义TextView控件。 源码如下&#xff1a; import android.content.Context import android.graphics.Canvas imp…

基于云原生向量数据库 PieCloudVector 的 RAG 实践

近年来&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;已然成为最热门的话题之一。工业界出现了各种内容生成工具&#xff0c;能够跨多种模态产生多样化的内容。这些主流的模型能够取得卓越表现&#xff0c;归功于创新的算法、模型规模的大幅扩展&#xff0c;以及海…