【踩坑日记】STM32 USART 串口与 FreeRTOS 冲突

文章目录

  • 问题描述
  • 问题出现的环境
  • 问题解决过程
    • 第一步
    • 第二步
    • 第三步
    • 第四步
    • 第五步
    • 第六步
    • 第七步
    • 第八步
  • 后续验证
  • 一些思考
  • 类似的问题
  • 后记

问题描述

笔者使用 FreeRTOS 创建了两个任务,使两颗 LED 以不同频率闪烁,但是在加入串口 USART 部分代码后, LED 不能正常工作了。

问题出现的环境

  • 硬件:STM32F103C8T6、ST-Link
  • 软件:KEIL5
  • 代码来源:野火 FreeRTOS 例程
    说明,野火的教程并不适用于 F103C8,笔者对其进行了移植,一定程度上是因为移植出现了冲突的问题。
    关于如何移植野火的 FreeRTOS 源码,请看笔者的这篇文章【学习日记】【FreeRTOS】FreeRTOS 移植到 STM32F103C8

问题解决过程

这个部分记录了笔者解决问题的思路,或许对你有一些启发,如果觉得太长可以直接按右边的目录跳到问题的解决方法
在这里插入图片描述

第一步

首先尝试屏蔽了重定向的 printf,但是未注释掉 USART 的初始化函数,问题没有解决;

第二步

尝试屏蔽 USART 的初始化函数,问题解决,此时可以确定问题出在 USART 的初始化函数中;

第三步

查看 USART 的初始化函数代码,如下:

 /*** @brief  USART GPIO 配置,工作参数配置* @param  无* @retval 无*/
void USART_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;// 打开串口GPIO的时钟DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);// 打开串口外设的时钟DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);// 将USART Tx的GPIO配置为推挽复用模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);// 将USART Rx的GPIO配置为浮空输入模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);// 配置串口的工作参数// 配置波特率USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;// 配置 针数据字长USART_InitStructure.USART_WordLength = USART_WordLength_8b;// 配置停止位USART_InitStructure.USART_StopBits = USART_StopBits_1;// 配置校验位USART_InitStructure.USART_Parity = USART_Parity_No ;// 配置硬件流控制USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 配置工作模式,收发一起USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 完成串口的初始化配置USART_Init(DEBUG_USARTx, &USART_InitStructure);// 串口中断优先级配置NVIC_Configuration();// 使能串口接收中断USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);	// 使能串口USART_Cmd(DEBUG_USARTx, ENABLE);	    
}

可以将函数复制到 ChatGPT 中,让 AI 帮助分析函数的结构,这里分享一个我自制的 Prompt:

你是一个优秀的编程工程师,你的工作是分析我发送给你的函数,把函数执行的功能用较简洁的语言归纳为几步。需要进行分析的函数我将放置于中括号中,你只需要输出归纳出的函数功能,不需要输出其他提示语。为了防止我们的对话过长你忘记了你的职责,当你忘记时我将在发送的消息前加上 “/keep” 来提醒你。

这个函数的结构大致是:

  • 打开串口使用的 GPIO 端口的时钟和外设的时钟。
  • 配置 USART Tx 引脚为推挽复用模式,配置 USART Rx 引脚为浮空输入模式。
  • 配置串口的工作参数,包括波特率、数据字长、停止位、校验位和硬件流控制等。
  • 完成串口的初始化配置,将工作参数应用到 USART 外设上。
  • 配置串口的中断优先级。
  • 使能串口接收中断。
  • 使能串口。

由于我们不确定问题出在这个函数的哪个地方,所以笔者采用了逐层解屏蔽的方式进行排查,也就是先将这个函数中所有代码都注释掉,然后从上往下逐层去掉屏蔽,直到问题出现,就可以确定有问题的代码。

如果函数较长,可以采用类似二分法的方式进行排查,也就是每次都解除一半的注释,如果问题出现,那么有问题的代码就在刚刚接触注释的那一半代码中;如果问题没有出现,有问题的代码就在另一半代码中。

不过在我们对这个函数进行逐层解屏蔽的排查操作时,我们要注意从函数的结构可以看出,串口的生效操作在最后一行,如果这行被注释了意味着前面所有的操作实际上都没有生效,所以这行从始至终都不能被注释。

经过笔者的排查,发现问题就出在 “使能串口接收中断” 这部分代码中,只要这部分代码被屏蔽了,问题就解决了。
在这里插入图片描述
虽然注释掉串口接收中断就可以解决问题,但是这意味着我们只能接收的 STM32 发送给电脑的信息,而不能给 STM32 发送信息。笔者自然是对这个解决方式不满意的,接着往下看。

第四步

值得一提的是,我发现了野火的代码中另一个 bug:野火在板载硬件初始化和串口初始化函数中都对中断优先级分组进行了配置,而且配置的方式是冲突的:

  • 板载硬件初始化函数:
    在这里插入图片描述
  • 串口初始化函数中中断配置函数:
    在这里插入图片描述
    我们选择对串口初始化函数中中断配置函数进行修改以解决这个 bug:
 /*** @brief  配置嵌套向量中断控制器NVIC* @param  无* @retval 无*/
static void NVIC_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;//  /* 嵌套向量中断控制器组选择 */
//  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);/* 配置USART为中断源 */NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;/* 抢断优先级*/NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;/* 子优先级 */NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;/* 使能中断 */NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;/* 初始化配置NVIC */NVIC_Init(&NVIC_InitStructure);
}

第五步

  • 由于发现了注释掉串口接收中断就可以解决问题,笔者自然推断是不是进入了中断跳不出来导致任务得不到执行,所以决定修改串口中断的优先级,改为抢断优先级最低的 15。
  • 虽然说思路正确,但这实际上是不可行的。在 FreeRTOS 中,PendSV 的中断优先级配置为最低的 15,PendSV 进行任务切换。
  • 如果真的是由于卡在串口的中断中导致任务得不到执行,那么即使设置串口中断为最低优先级,由于和 PendSV 的中断优先级一样,那么也无法跳出串口中断。

第六步

  • 此时笔者决定先使用串口模块(实际上是 USB 转 TTL 模块)将 STM32 和计算机连接起来,看看能否正常接收 STM32 发送的消息。奇迹发生了,当接上串口模块后,即使是能了串口接收中断,模块也是正常工作的!真有点玄学的味道!
    USB 转 TTL 模块
  • 但是很快我就想到,变量就是我刚刚接入的串口模块。尝试插拔了几次模块,果然如此。
  • 于是笔者开始进行排除,这个模块需要接 3 根线,分别是 GND、TX 和 RX,笔者将其分别单独与 STM32 连接,最终确定问题出在串口模块的 TX 引脚上:当串口模块已经接入计算机,这时只要将串口模块的 TX 连接到 STM32 的 RX 引脚上(这里使用的是 USART1,RX 为 PA10),那么即使使能了串口接收中断, STM32 也能正常工作

第七步

  • 于是笔者测量了串口模块的 TX 电平,发现有 3.5V。推测出是不是当 STM32 的 RX 引脚需要一个类似于 3.5V 的高电平来确保其不会无故触发接收中断导致任务无法执行。所以笔者直接将 RX 引脚接入 STM32 板子自带的 3.3V 引脚,发现工作正常,猜想正确!

  • 笔者又想到,可能不一定需要一个确定的高电平,确定的电平即可。于是将 STM32 的 RX 引脚接地,工作也正常!

第八步

  • 笔者返回查看串口的引脚初始化代码,发现 RX 引脚确实配置为浮空输入,猜想是否因为浮空输入导致了电平的不稳定而无故触发中断卡死
    在这里插入图片描述
  • 这里配置的浮空输入是否有 bug 呢?于是查看数据手册,发现浮空输入或者上拉输入都是可以的:
    在这里插入图片描述
  • 于是改为上拉输入,问题解决
  // 将USART Rx的GPIO配置为上拉输入模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);

解决方法!!!

  • 最简单的解决方式就是将 STM32 USART 的 RX 引脚从浮空输入改为上拉输入
  // 将USART Rx的GPIO配置为上拉输入模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  • 还有一种解决方式是即使暂时不使用 USART,但是只要在程序中初始化了串口(使能了接收中断),就要给串口的 RX 引脚一个确定的电平输入,可以是接地也可以是给 3.3V 的高电平

后续验证

  • 定义了串口中断函数后,使用 ST-Link 进入调试模式,发现的确卡在了串口中断函数中导致任务不能得到执行

  • 推测可能是串口的电平不稳定导致的

一些思考

  • 在一开始我们提到,一定程度上是因为移植野火的 FreeRTOS 例程才出现了冲突的问题。怎么理解呢?

  • 实际上,为了降低学习成本,笔者使用的是 STM32F103C8 的最小系统板,所以才需要外接 USB 转 TTL 电平模块与计算机通信。

  • 而野火的官方例程是适配其开发板的,肯定是经过了测试正常才发布的。那么为什么在野火的开发板上就不会出现类似的 bug 呢?因为野火的开发板已经集成了 USB 转 TTL 电平模块,一上电就能为 STM32 USART 的 RX 引脚提供一个确定的电平,规避了产生这个 bug 的条件。

类似的问题

笔者刚发现这个 bug 的时候,并不清楚是引脚的电平配置导致的问题,在网络上寻求解决方式的时候多半都是往 FreeRTOS 与 USART 冲突这个方向去搜索,导致并未找到正确的解决方法。

而在笔者写这篇文章的时候,就搜到了几篇类似的文章:
stm32 串口接收引脚配置为浮空输入问题
STM32F1频繁进入串口中断-串口直接连接到了接插件引脚上
USART3------------RXD----------PB11 悬空会导致程序频繁进入串口接收中断!!!

后记

如果您觉得本文写得不错,可以点个赞激励一下作者!
如果您发现本文的问题,欢迎在评论区或者私信共同探讨!
共勉!

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

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

相关文章

java八股文面试[多线程]——指令重排序

关于a的操作,由原来的6个指令,变成了4个指令。 1. 指令重排序的介绍 1)指令重排序的类型 在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序。 重排序分三种类型:编译器优化的重排序 编译器在不改变单线…

YOLO V5 和 YOLO V8 对比学习

参考文章: 1、YOLOv5 深度剖析 2、如何看待YOLOv8,YOLOv5作者开源新作,它来了!? 3、anchor的简单理解 完整网络结构 YOLO v5和YOLO v8的Head部分 YOLO v8的Head 部分相比 YOLOv5 改动较大,换成了目前主流的解耦头结构…

【springboot】Spring Cache缓存:

文章目录 一、导入Maven依赖&#xff1a;二、实现思路&#xff1a;三、代码开发&#xff1a; 一、导入Maven依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId><…

WordPress主题Zing V2.2.1/模块化WordPress响应式通用企业商城主题

WordPress主题Zing V2.2.1&#xff0c;模块化WordPress响应式通用企业商城主题。 功能介绍 百度熊掌号文章实时推送、原创保护 多设备支持自适应布局&#xff0c;支持电脑、Pad、手机以及各种浏览器 SEO优化首页、文章、页面、分类均支持自定义标题、关键字和描述 速度优化…

Django(7)-项目实战-发布会管理

登录功能 模板页面 sign/templates/index.html <!DOCTYPE html> <html> <head><title>Login Page</title> </head> <body><h1>发布会管理</h1><form action"/login/" method"post"><la…

idea 常用插件和常用快捷键 - 记录

idea 常用插件 记得下载插件完成后&#xff0c;点击 Apply 和 OK Alibaba Java Coding Guidelines 作用&#xff1a;使用该插件可以&#xff0c;自动提示相关的语法格式问题&#xff0c;格式参考 阿里巴巴代码规范 详情链接&#xff1a; 代码规范之Alibaba Java Coding G…

EXCEL中点击单元格,所在行和列都改变颜色

在日常工作中&#xff0c;尤其是办公室工作人群&#xff0c;尝尝需要处理大量的数据&#xff0c;在对数据进行修改时&#xff0c;时长发生看错行的事情&#xff0c;导致数据越改越乱&#xff0c;因此&#xff0c;我常用的一种方法就是选中单元格时&#xff0c;所在行、列标记为…

【AI】数学基础——高数(函数微分部分)

参考&#xff1a;https://www.bilibili.com/video/BV1mM411r7ko?p1&vd_source260d5bbbf395fd4a9b3e978c7abde437 唐宇迪&#xff1a;机器学习数学基础 文章目录 1.1 函数1.1.1 函数分类1.1.2 常见函数指/对数函数分段函数原函数&反函数sigmod函数Relu函数(非负函数)复…

keil5 快捷下载STM32系列芯片器件包的方法

以STM32H7系列的器件包为例,官网的下载网址为 https://sadevicepacksprodus.blob.core.windows.net/pack/Keil.STM32H7xx_DFP.3.1.1.pack 其中STM32H7xx为芯片系列编号,3.1.1为器件包的版本 如需下载其他系列和版本的器件包,只需把网址中的编号和版本换成对应的即可(前提是输入…

K8S:K8S自动化运维容器Docker集群

文章目录 一.k8s概述1.k8s是什么2.为什么要用K8S3.作用及功能4.k8s容器集群管理系统 二.K8S的特性1.弹性伸缩2.自我修复3.服务发现和复制均衡4.自动发布和回滚5.集中化配置管理和秘钥管理6.存储编排7.任务批量处理运行 三.K8S的集群架构四.K8S的核心组件1.Master组件&#xff0…

ATA-1222A宽带放大器的电子实验案例(案例合集)

ATA-1222A宽带放大器是安泰电子打造的高带宽功放产品&#xff0c;其采用ClassAB的工作模式&#xff0c;带宽高达22MHz&#xff0c;饱和输出功率40W&#xff0c;能兼容全球不同地区的电源标准要求。凭借其优异的指标参数受到不少电子工程师的喜欢&#xff0c;其在电子实验中的应…

香港服务器快还是台湾服务器快?

​  基于机房位置不同&#xff0c;香港服务器相对于台湾服务器在访问速度方面有一定的优势。香港服务器拥有CN2线路&#xff0c;因此访问速度较快。在网络服务商方面&#xff0c;中华电信等台湾服务商提供的带宽也具有很高的性价比。 香港服务器对大陆用户的影响 对于大陆用户…

WordPress导航主题/酷啦鱼导航主题模板

酷啦鱼导航主题模板&#xff0c;是一款基于WordPress的导航主题&#xff0c;酷啦鱼导航主题是个人基于wordpresscodestar work框架设计的简洁导航主题。 下载地址&#xff1a;https://bbs.csdn.net/topics/616084697

无涯教程-Android Mock Test函数

本节介绍了与 Android 相关的各种模拟测试。您可以在本地计算机上下载这些样本模拟测试,并在方便时离线解决。每个模拟测试均随附一个模拟测试键,可让您验证最终分数并为自己评分。 Mock Test I Mock Test II Mock Test III Mock Test IV Q 1 -什么是Android&#xff1f; A -A…

Python Opencv实践 - Sobel边缘检测

import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/pomeranian.png", cv.IMREAD_GRAYSCALE) print(img.shape)#Sobel边缘检测 #cv.sobel( src, ddepth, dx, dy[,ksize[, scale[, delta[, borderType]]]] ) #src:…

Flink+Paimon多流拼接性能优化实战

目录 &#xff08;零&#xff09;本文简介 &#xff08;一&#xff09;背景 &#xff08;二&#xff09;探索梳理过程 &#xff08;三&#xff09;源码改造 &#xff08;四&#xff09;修改效果 1、JOB状态 2、Level5的dataFile总大小 3、数据延迟 &#xff08;五&…

Java“牵手”京东商品详情数据,京东API接口申请指南

京东平台商品详情接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取京东商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息 。 获取商品详情接口API是一种用于获取电商平台上商品详情数据的接口&#xff0c;通过…

一种借助MYSQL递归CTE生成所有的组合情况的实现方法

需求说明 有如下表和数据&#xff1a; Nname1户口2查询机构数过多3危险驾驶4多头用信 需要输出name里的所有组合情况&#xff0c;即单个值&#xff0c;两两组合&#xff0c;三个组合、四个组合。结果为2的n次方-1中情况&#xff0c;这里是15。 预期结果为&#xff1a; Com…

Spring 如何解决循环依赖问题 - 三级缓存

1. 什么是循环依赖问题 ? 循环依赖问题是指对象与对象之间存在相互依赖关系&#xff0c;而且形成了一个闭环&#xff0c;导致两个或多个对象都无法准确的完成对象的创建和初始化。 两个对象间的循环依赖&#xff1a; 多个对象间的循环依赖 &#xff1a; 解决 Spring 中的循环…

uniapp 微信小程序仿抖音评论区功能,支持展开收起

最近需要写一个评论区功能&#xff0c;所以打算仿照抖音做一个评论功能&#xff0c;支持展开和收起&#xff0c; 首先我们需要对功能做一个拆解&#xff0c;评论区功能&#xff0c;两个模块&#xff0c;一个是发表评论模块&#xff0c;一个是评论展示区。接下来对这两个模块进行…