STM32复习笔记(三):串口

news2024/11/20 20:39:12

目录

Preface:

(一)CUBEMX配置串口

(二)轮询方式

(三)中断 + DMA


Preface:

串口通信协议简单,因此被广泛应用;串口有UART(Universal Asynchronous Receiver Transmitter,通用异步收发传输器),USART(Universal Synchronous Asynchronous Receiver Transmitter,通用同步异步收发传输器),在物理层,常用的有TTL(晶体管-晶体管逻辑,0V表示逻辑0,5V表示逻辑1),RS232(+3V~+15V表示逻辑0,-15V~-3V表示逻辑1),RS485(差分线);而这三者在数据链路层使用的是相同的协议,也就是常说的串口协议,基本参数有:数据位、停止位、奇偶校验位、波特率、过采样参数等等;


(一)CUBEMX配置串口

首先,根据串口原理图可知,外部的TX和RX分别接到了PA10(MCU的RX)和PA9(MCU的TX)也就是你发我收我发你收:

接下来进入cubemx,设置好调试,时钟之后,打开Connectivity,选择USART1-串口1,一般都用异步通信,因为同步通信需要连时钟线比较麻烦;选择异步通信后,默认选好了PA9和PA10,当然如果PA9或PA10被占用的话也可以自己选择重映射引脚;然后看到参数设置选项(左上角的!可以显示当前参数的description),首先看到波特率,可以发现范围为1.283K~5.25MBit/s,也就是可以写1283~5250000;字长可以是8bit或9bit(包含奇偶校验位),奇偶校验可选奇校验、偶校验或无校验;停止位有1bit或2bit;数据传输方向可选仅接收、仅发送或双向;过采样可选8次采样和16次采样,用于确定有效的起始位,8次采样速度更快(单位时间采8次,次数少速度快),但容错性差,16次采样速度慢,但容错性好,默认使用16次采样;其实参数选择是根据通信双方来定的,当然没定的话大家都保持默认即可,也不需要改参数;设置好之后直接生成代码即可:


(二)轮询方式

轮询就是cpu一直死循环检测串口,等待数据到来,极其浪费cpu资源,一般来说都不会用这种方式;下面实现了一个轮询检测串口,收到数据后再通过串口发回去:

my_uart.h:

#ifndef UART_MY_UART_H
#define UART_MY_UART_H

#ifdef __cplusplus
extern "C" {
#endif

#include "main.h"


HAL_StatusTypeDef UART_SendData(UART_HandleTypeDef* uart, char* str, uint16_t size);
HAL_StatusTypeDef UART_ReceiveData(UART_HandleTypeDef* uart, uint8_t* pdata, uint16_t size);


#ifdef __cplusplus
}
#endif

#endif //UART_MY_UART_H

my_uart.cpp(实际上,对于接收数据函数就是把收到的数据传给发送函数,然后让发送函数通过串口发送回去;而对于发送函数,首先new一片内存,用来存放接收数据函数传过来的数据,然后用sprintf函数copy过来;why?为什么要copy?这不是多此一举吗?其实不然,这里仅仅发送字符串看不出sprintf的作用;事实上,如果还要通过串口发送数字之类的变量,就可以在发送之前全部用sprintf打包进一个字符数组中,一次性发完,个人感觉方便很多;;;最后不要忘记delete掉申请的内存,并将指针置空,以防野指针错误):

#include "my_uart.h"
#include "cstdio"

//串口发送数据函数
HAL_StatusTypeDef UART_SendData(UART_HandleTypeDef* uart, char* str, uint16_t size) {
    HAL_StatusTypeDef status = HAL_OK;
    char *temp = new char[size];    //申请内存

    std::sprintf(temp, "%s", str);  //copy数据
    status = HAL_UART_Transmit(uart, (uint8_t*)temp, size, 0xffff);//阻塞直到发送完成

    delete[] temp;
    temp = nullptr; //释放内存并置空指针

    return status;
}

//串口接收数据函数
HAL_StatusTypeDef UART_ReceiveData(UART_HandleTypeDef* uart, uint8_t* pdata, uint16_t size) {
    HAL_StatusTypeDef status = HAL_OK;

    status = HAL_UART_Receive(uart, pdata, size, 0xffff);//阻塞直到接收完成

    return status;
}

主函数主要部分:

结果:

还有分析代码执行过程;首先打一个断点在接收函数中,并进入调试,如下图:

然后点击执行下一句,会发现系统进入阻塞状态,等待串口输入数据;当然如果过了太久没输入,就会超时,也会结束接收:

 接下来,在串口助手中输入想输入的字符串(当然只能读取15个,因为前面指定了读15个;并且要在超时时间内输入):

我这里输入了“0123456789abc”(共13个,加上回车&换行一共15个)可以观察到数据已经被成功接收了,并且状态为HAL_OK,表示接收成功;也可以根据地址去内存看数据,如下:

接下来,进入发送函数,如下图(箭头指向的是待执行语句),可以发现字符串已经被正确地传过去了:

然后执行分配内存new语句(可以发现刚分配好内存时,其中的值是随机的),再执行字符串copy语句sprintf,并去内存中查看是否成功;如下图:

然后就是将数据发送出去了,最后别忘了释放内存(继续查看内存会发现,释放了内存而内存中该地址的值却没有变,只有前面的两个字节变了,我猜测这两个字节应该是表示后面这段内存是否已被分配),不然就会产生内存泄漏:

以上就是串口轮询的分析过程~~~

工程链接:https://pan.baidu.com/s/1XDGoVidEDXZgnw1muTyaWQ 
提取码:0xFF


(三)中断 + DMA

事实上,串口有许多个中断,不太可能全部列出来,我认为最常用的就是RXNE(接收缓冲非空中断)、IDLE(空闲中断)、TC(发送完成中断)了;然后就是DMA,可以直接从外设把数据传送到内存(或者反过来)而不需要cpu干预,只需要在数据开始发送的时候指定参数,当数据传输完毕就会产生一个DMA传输完成的中断给cpu,让cpu来进行接下来的处理;那为啥要把中断和DMA放一起?主要是一般来说,数据接收者预先都不知道会收到多少数据,用轮询是不太能做得到的;而如果用中断一个字符一个字符地中断接收的话又导致cpu被频繁中断,拉低了性能;那能不能说收完数据再产生一次中断了,这样明显更合理,而这就是串口空闲中断+DMA;用DMA接收数据,当接收完数据之后,等到了总线空闲状态,串口就会产生一个IDLE空闲中断;那什么是空闲状态呢?空闲就是总线上在一个字节的时间内没有再接收到数据。空闲中断是从检测到有数据被接收开始,总线上在一个字节的时间内没有再接收到数据的时候发生的。一般就只有一个数据帧发送完成的时候,总线在会在一个字节时间内没有接收到数据,所以串口的空闲中断也叫帧中断。

我之前有写过一个串口空闲中断+DMA来接收不定长数据的,在这里;但其实,还是有一点bug的;比如说:

1、连着接收两帧数据,但是这两帧数据间隔很近,不够一个字节的空闲时间,这就导致只产生一次空闲中断,出现错误;

2、正常的一问一答数据交流是没有问题,只要保证每次接收不同帧的数据间隔大于一个字节的空闲时间即可,也就是保证一帧数据对应一个空闲中断;但是如果是MCU要接收很大的数据量,并且是连着接收,实时性又高(相当于bug 1中的升级版吧),就会导致:在所有数据传输完之前,一次空闲中断都不会发生,cpu不知道DMA已经收了多少数据,势必会导致出错。

暂时没有想到很好的解决办法......

完~


以上均为个人学习心得,如有错误,请不吝赐教~

THE END

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

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

相关文章

谷歌注册手机号码无法验证

1. 打开设置,在语言中点击添加语言搜索English并添加 2. 点击添加后把首选语言换成英语 3. 然后重启浏览器,这时候浏览器就是英文了,最后打开注册页面就能接收短信了

微服务技术栈-认识微服务和第一个微服务Demo

文章目录 前言一、认识微服务二、微服务技术栈三、Eureka注册中心四、微服务DEMO1、搭建eureka-server2、服务注册和服务发现 总结 前言 随着业务的不断复杂,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。 本章就从微服…

vuejs中缓存组件状态-keepAlive

前言 在 vuejs中,我们经常需要缓存一些组件的状态,比如用户登录后,切换到其他页面,再切换回来,需要保留之前的登录状态,而不是重新登录。 或者在切换不同组件的时候,需要保留之前的组件状态&…

[Linux]线程同步

[Linux]线程同步 文章目录 [Linux]线程同步线程同步线程饥饿问题概念 线程同步控制--条件变量pthread_cond_init函数pthread_cond_destroy函数pthread_cond_wait函数pthread_cond_signal函数pthread_cond_broadcast函数条件变量相关函数的使用示例生产者消费者模型基于Blocking…

基于SpringBoot的体育馆场地赛事预约管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

【生命周期】

生命周期 1 引出生命周期2 分析生命周期3 总结生命周期 1 引出生命周期 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta …

互联网Java工程师面试题·MyBatis 篇·第二弹

目录 16、Xml 映射文件中&#xff0c;除了常见的 select|insert|updae|delete标签之外&#xff0c;还有哪些标签&#xff1f; 17、Mybatis 的 Xml 映射文件中&#xff0c;不同的 Xml 映射文件&#xff0c;id 是否可以重复&#xff1f; 18、为什么说 Mybatis 是半自动 ORM 映射…

证书显示未受信任,生成的证书过期

此时若是导入证书后&#xff0c;证书显示未受信任&#xff0c;则说明我们缺失最新的AppleWWDRCA证书 解决方案&#xff1a; 重新下载AppleWWDRCA并安装。即下载最新的AppleWWDRCA证书&#xff0c;双击安装到“登录”项的钥匙串下&#xff1b;然后再安装你的开发证书或者发布证书…

云原生微服务 第六章 Spring Cloud Netflix Eureka集成远程调用、负载均衡组件OpenFeign

系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 第五章 Spring Cloud Netflix 之 Ribbon 第六章 Spring Cloud 之 OpenFeign 文章目录 系列文章目录前言1、OpenFeign的实现…

嵌入式Linux应用开发-驱动大全-第一章同步与互斥②

嵌入式Linux应用开发-驱动大全-第一章同步与互斥② 第一章 同步与互斥②1.3 原子操作的实现原理与使用1.3.1 原子变量的内核操作函数1.3.2 原子变量的内核实现1.3.2.1 ATOMIC_OP在 UP系统中的实现1.3.2.2 ATOMIC_OP在 SMP系统中的实现 1.3.3 原子变量使用案例1.3.4 原子位介绍1…

js正则的前瞻释义

/^(?a)aa$/可以匹配aa,但不能匹配aaa,因为前瞻不消耗字符串 检验密码强度的正则 /^(?.*[a-z])(?.*[A-Z])(?.*\d)(?.*[$,_.])[a-zA-Z\d$,_.]{6,12}$/var reg/^(?.*[a-z])(?.*[A-Z])(?.*\d)(?.*[$,_.])[a-zA-Z\d$,_.]{6,12}$/var res reg.test(abcdefg.A6)console.log(…

SpringBoot中使用Servlet和Filter

为什么要把Servlet和Filter写在一起,因为使用方式很相似 两种方式 第一种,使用Servlet和Filter 使用Servlet 继承HttpServlet 注册Servlet 使用Filter 1.自定义过滤器 2.注册过滤器 这里注意一点 使用/**无效 至少我这2.4.5版本是这样 过滤所有请求用/* 那么其实还有…

CodeCraft-21 and Codeforces Round 711 (Div. 2)A-F

1.Problem - A - Codeforces &#xff08;1&#xff09;题意 求一个大于等于n的整数x&#xff0c;满足gcd(x,sum(dig(x)) > 1&#xff0c;dig表示x的各个数位。 &#xff08;2&#xff09;思路 考虑最差是满足gcd(x,sum(dig(x)) 2,因此不会枚举很多&#xff0c;直接暴力枚…

【Diffusion】DDPM - (2)公式推导 之 前向扩散

1、加噪过程 1、将 图像 x 0 x_0 x0​ 像素值映射到 [-1, 1] 之间 x 255 2 − 1 , w h e r e    x 为图像中的像素值 \quad \frac{x}{255} \times 2-1, \quad where \; x 为图像中的像素值 255x​2−1,wherex为图像中的像素值 \quad 2、生成一张尺寸相同的噪声图片,像…

【Kafka专题】Kafka收发消息核心参数详解

目录 前置知识课程内容一、从基础的客户端说起&#xff08;Java代码集成使用&#xff09;1.1 消息发送者源码示例1.2 消息消费者源码示例1.3 客户端使用小总结 *二、从客户端属性来梳理客户端工作机制*2.1 消费者分组消费机制2.2 生产者拦截器机制2.3 消息序列化机制2.4 消息分…

二叉搜索树 , Set 和 Map (JAVA)

二叉搜索树 二叉搜索树又称二叉排序树&#xff0c;它具有以下性质的二叉树或空树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值它的每颗子树也分别为二叉搜索树 二叉搜索树的…

北京开发APP需要多少钱

北京开发一个移动应用&#xff08;APP&#xff09;的费用因多种因素而异&#xff0c;包括项目的规模、复杂性、所需功能、设计要求、技术选择、开发团队的经验和地理位置等。一般来说&#xff0c;北京的APP开发费用通常较高&#xff0c;因为这是中国的主要技术和创新中心之一&a…

【云备份项目】:环境搭建(g++、json库、bundle库、httplib库)

文章目录 1. g 升级到 7.3 版本2. 安装 jsoncpp 库3. 下载 bundle 数据压缩库4. 下载 httplib 库从 Win 传输文件到 Linux解压缩 1. g 升级到 7.3 版本 &#x1f517;链接跳转 2. 安装 jsoncpp 库 &#x1f517;链接跳转 3. 下载 bundle 数据压缩库 安装 git 工具 sudo yum…

嵌入式Linux应用开发-驱动大全-第一章同步与互斥①

嵌入式Linux应用开发-驱动大全-第一章同步与互斥① 第一章 同步与互斥①1.1 内联汇编1.1.1 C语言实现加法1.1.2 使用汇编函数实现加法1.1.3 内联汇编语法1.1.4 编写内联汇编实现加法1.1.5 earlyclobber的例子 1.2 同步与互斥的失败例子1.2.1 失败例子11.2.2 失败例子21.2.3 失败…

IDEA中的神仙插件——Smart Input (自动切换输入法)

推荐专栏&#xff1a;开发环境配置攻略 致力于记录学习过程中各种软件的安装及环境配置操作&#xff0c;并提供详细的步骤说明和丰富的配图。涵盖了 Java、Python、IntelliJ IDEA、Tomcat、MySQL 等常见开发工具和服务器组件的配置&#xff0c;为初学者提供一个实用、全面的配置…