树莓派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等底层技术的飞速进步&…

C++学习笔记(11)

四、学习要领 1&#xff09;如果容器有成员函数&#xff0c;则使用成员函数&#xff0c;如果没有才考虑用 STL 的算法函数。 2&#xff09;把全部的 STL 算法函数过一遍&#xff0c;知道大概有些什么东西。 3&#xff09;如果打算采用某算法函数&#xff0c;一定要搞清楚它的原…

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;请你在该数组中找出 和为目标…

前端页面加载由模糊到清晰的实现方案

要实现图片加载时由模糊逐渐变得清晰的效果,可以使用 CSS 和 JavaScript 的结合。这里的思路是:先让图片在加载时模糊显示,等图片完全加载完后,再去掉模糊效果。 1. 使用 CSS 实现模糊效果 我们可以使用 filter: blur() 来为图片添加模糊效果,结合 transition 属性在加载…

MongoDB Limit 与 Skip 方法

MongoDB Limit 与 Skip 方法 MongoDB 是一个流行的 NoSQL 数据库&#xff0c;它提供了灵活的数据存储和强大的查询功能。在处理大量数据时&#xff0c;我们常常需要限制返回的结果数量或者跳过一部分结果&#xff0c;这时就可以使用 MongoDB 的 limit 和 skip 方法。 Limit 方…

Python中差分进化differential_evolution的调用及参数说明

在场景应用中&#xff0c;要求我们的函数计算结果尽可能的逼近实际测量结果&#xff0c;可转化计算结果与测量结果的残差&#xff0c;通过最小化残差&#xff0c;便可求出最优的结果。但使用最小二乘等方法来计算时&#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 (全称为 "超⽂本传输协议") 是⼀种应⽤…

WEB项目解决CORS 跨域问题

为了安全&#xff0c;web默认是不允许跨域访问的。不过实际项目中&#xff0c;会遇到不同模块之间来回跳转的情况。所以&#xff0c;项目内部一般会修改配置或者代码来解决CORS跨域问题。 我的后端使用的是 Jetty 服务器&#xff0c;所以下面就拿jetty来举例。Jetty 提供了一个…

14.2 k8s中我们都需要监控哪些组件

本节重点介绍 : k8s中关注四大块指标总结 容器基础资源指标k8s资源指标k8s服务组件指标部署在pod中业务埋点指标 k8s关注指标分析 k8s中组件复杂&#xff0c;我们主要专注的无外乎四大块指标&#xff1a; 容器基础资源指标 为何关注这些指标 我们的应用从独享一台机器上…

springboot组件使用-mybatis组件使用

文章目录 springboot使用mybatis组件1. 添加依赖2. 配置数据源3. 创建实体类4. 创建Mapper接口5. 创建Mapper XML文件6. 使用Mapper7. 启动类配置 mybtis 动态SQL1. Mapper 注解2. Select 注解3. Insert 注解4. Update 注解5. Delete 注解6. Results 注解7. Param 注解8. Cache…

Mysql中的锁机制详解

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

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

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

Rust:Restful API 服务程序开发详述

0. 关于异步程序设计 0.1 对异步机制的理解 运行效率对于后端程序来讲很重要。我曾经以为&#xff0c;多线程机制是后端设计的终极方法&#xff0c;后来才发现&#xff0c;异步机制才是榨干 CPU 运行效率资源的关键所在。 我最初对于异步程序设计有误解&#xff0c;以为多线…