FreeRTOS 线程安全的printf输出(使用STM32F103)

2023-05-16

https://blog.csdn.net/baidu_23187363/article/details/53811144

环境

STM32F103开发板
HAL库(标准库也没事换个串口输出函数就行)
MDK5.28
STM32CubeMX

前言

原本直接使用串口输出来debug调试的,但是添加FreeRTOS之后出现乱码的现象。所以决定做个线程安全的printf函数来打印输出方便调试。

原因

假设一个115200的波特率发送一个8位的数据、1个停止位、1个起始位、无奇偶校验位,需要大约87us,当发送大量数据的时候很容易被中断或者其他高优先级的任务打断,从而出现乱码。

串口的重映射

参考开发板的教程printf重映射函数是这么写的

int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}

这样使用printf函数就可以实现串口1输出的,由于没有任何保护。所以有概率会出现乱码。

printf函数实现

#include "stdio.h"
#include <stdarg.h>
void print_usart1(char *format, ...)
{
    char buf[64];
	va_list ap;                //声明字符指针 ap
	va_start(ap, format);      //初始化 ap 变量
	vsprintf(buf, format, ap); //使用参数列表发送格式化输出到字符串
	HAL_UART_Transmit(&huart1, (uint8_t *)buf, strlen(buf), 100);//100ms内发送
	va_end(ap);
}

C标准库<stdarg.h>

va_start()

void va_start(va_list ap, last_arg) 

参数:

  • ap – 这是一个 va_list 类型的对象,它用来存储通过 va_arg 获取额外参数时所必需的信息。
  • last_arg – 最后一个传递给函数的已知的固定参数。“…”之前的参数

vsprintf

int vsprintf(char *str, const char *format, va_list arg)

参数:

  • str – 这是指向一个字符数组的指针,该数组存储了 C 字符串。
  • format – 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。
  • arg – 一个表示可变参数列表的对象。这应被 中定义的 va_start 宏初始化。

返回值:
如果成功,则返回写入的字符总数,否则返回一个负数。

va_end

void va_end(va_list ap)

参数:

  • ap – 这是之前由同一函数中的 va_start 初始化的 va_list 对象。

线程安全函数构建

方案一:
我们不希望在打印到一半的时候进入别的任务线程中,我们可以使用函数挂起所有线程,打印结束再回复任务调度。
那么可以使用进入临界区的方式来保证线程安全。

void vTaskSuspendAll( void )
BaseType_t xTaskResumeAll( void )
#include "stdio.h"
#include <stdarg.h>
void print_usart1(char *format, ...)
{
    char buf[64];
	va_list ap;                //声明字符指针 ap
    vTaskSuspendAll();		   //挂起任务
	va_start(ap, format);      //初始化 ap 变量
	vsprintf(buf, format, ap); //使用参数列表发送格式化输出到字符串
	HAL_UART_Transmit(&huart1, (uint8_t *)buf, strlen(buf), 100);//100ms内发送
	va_end(ap);
	xTaskResumeAll();		   //恢复任务调度
}

改良方案一:
但是这种方式只是挂起了任务和恢复任务,没法保证中断安全,若出现中断嵌套还是会出现线程不安全。
所以可以使用临界区和关闭中断来保证printf线程和中断安全。当然前提我们需要构造一个函数判断是否在中断中。


#include "stdio.h"
#include <stdarg.h>
static int inHandlerMode (void) //若在中断中__get_IPSR()返回1,否则返回0
{
   return __get_IPSR();  
}
void print_usart1(char *format, ...)
{
    char buf[64];
 
    if(inHandlerMode() != 0)
	{
        taskDISABLE_INTERRUPTS();//若在中断中调用则关闭中断,防止中断嵌套造成线程不安全
	}
    else
    {
		taskENTER_CRITICAL();    //若不在中断中则进入临界区关闭中断且禁止任务调度
	}
	va_list ap;
	va_start(ap, format);
	vsprintf(buf, format, ap);
	HAL_UART_Transmit(&huart1, (uint8_t *)buf, strlen(buf), 100);
	va_end(ap);
	if(inHandlerMode() != 0)
	{
		taskENABLE_INTERRUPTS();//打开中断
	}else{
		taskEXIT_CRITICAL();//退出临界区
	}
}

再次改良
上述方法虽然能解决线程安全和中断安全,但是需要挂起所有任务消耗资源。所以继续改进使用任务切换的方式,若串口忙时需要打印参数,则只挂起当前任务。

 void print_usart1(char *format, ...)
{
    char buf[64];
    if(inHandlerMode() != 0)
	{
        taskDISABLE_INTERRUPTS();
	}
    else
    {
		while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX)//若串口忙则挂起此任务
		taskYIELD();
	}
	va_list ap;
	va_start(ap, format);
	vsprintf(buf, format, ap);
	HAL_UART_Transmit(&huart1, (uint8_t *)buf, strlen(buf), 100);
	va_end(ap);
	if(inHandlerMode() != 0)
	taskENABLE_INTERRUPTS();

}

#参考文章
Stone_Biny

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS 线程安全的printf输出(使用STM32F103) 的相关文章

随机推荐

  • 关于FreeRTOS的vTaskDelayUntil()延时函数的理解

    关于任务操作的相关函数走读 函数vTaskDelayUntil if INCLUDE vTaskDelayUntil 61 61 1 参数pxPreviousWakeTime xff1a 上一次任务唤醒时间点 xff0c 任务中第一次调用该
  • 关于FreeRTOS的系统时钟节拍

    不管是什么系统 xff0c 运行都需要有个系统时钟节拍 xTickCount就是FreeRTOS的系统时钟节拍器 在每个滴答定时器中断中xTickCount 43 1 xff0c 比如stm32中 xff0c 具体是在delay c中的vo
  • python基础:for循环和while循环区别和相同点,range函数介绍

    循环语句可以让计算机重复和自动的执行代码 xff0c 减少人的工作量 文章目录 for循环while循环两种循环对比 for循环 格式 for in 循环语句 xff0c 简称for循环 xff1b 先看下它的格式吧 span class
  • 不忘初心•砥砺前行——江苏叁拾柒号仓智能科技有限公司2019年中总结会

    2019年7月20日上午 xff0c 江苏叁拾柒号仓智能科技有限公司 下称37号仓 2019年中总结会在集团1楼多媒体厅隆重举行 xff0c 37号仓执行董事魏标 xff0c 总经理卞石磊 xff0c 子雨集团党支部书记 工会主席徐伟 xf
  • python基础:布尔运算和四个语句

    布尔运算 计算机的逻辑判断 xff0c 只有True 判断为真 和alse 判断为假 两种结果 xff0c 计算真假的过程就叫做布尔运算 xff0c True和False就是布尔值 while和if中的布尔运算 相同点 xff1a 在whi
  • 解读编码和文件读写

    解读编码和文件读写 编码的本质就是让只认识0和1的计算机 xff0c 能够理解我们人类使用的语言符号 xff0c 并且将数据转换为二进制进行存储和传输 这种从人类语言到计算机语言转换的形式 xff0c 就叫做编码表 xff0c 它让人类语言
  • BeautifulSoup库的简单使用

    BeautifulSoup是什么 网页解析库BeautifulSoup xff0c 用来解析和提取网页中的数据 安装BeautifulSoup库 BeautifulSoup库目前已经进阶到第4版 xff08 Beautiful Soup 4
  • 运行地面站详细步骤

    第一步 xff1a 打开bin目录 xff0c 保留Backup DLL文件夹 xff0c 删除除Backup DLL文件夹之外的所有文件 xff1b 第二步 xff1a 打开Backup DLL文件夹 xff0c 复制里面所有的dll 粘
  • 关于qt和js的html一些修改

    1 调试打印js文件 maptype tms html 文件 xff0c 没有qdebug 和printf 可以用 xff0c 但可以用alert 来代替 xff0c 用alert 地图上会出现对应窗口显示 xff0c 来判断程序 逻辑 2
  • qt+directshow usb摄像头及音频设备录制视频

    最近来了个项目 xff0c 有一块功能是usb摄像头录制视频并且录音的实现 xff0c 网上的东西七七八八什么技术都有 xff0c 先用opencv打了半天环境不能录音频 xff0c 后来用ffmpeg xff0c 原谅我太菜 xff0c
  • VSCode中Git解决冲突的步骤

    VSCode中Git解决冲突的步骤 1 gt gt 合并分支后 如果存在冲突 右下角会出现一个提示框 提示 存在合并冲突 请在提交之前解决这些冲突 2 gt gt 左边导航第三个图标中 xff0c 找到产生冲突的文件 3 gt gt 打开文
  • VsCode一定要安装的几个插件

    1 Vetur VUE语法高亮 智能感知 Emmet等 xff0c 包含格式化功能 xff0c Alt 43 Shift 43 F xff08 格式化全文 xff09 xff0c Ctrl 43 K Ctrl 43 F xff08 格式化选
  • ccm-slam环境配置

    ccm slam 配置过程记录 介绍 xff1a 一种协同视觉slam方法 传统的slam是一个机器人完成定位与建图的任务 xff0c 但对于大范围的环境 xff0c 多机器人协同建图往往能提高效率 xff0c ccm slam就是基于这个
  • 从大到小排序,Comparator类型

    import java util Arrays import java util Comparator public class Main public static void main String args 注意 xff0c 要想改变默
  • 11种服务器编程语言对比(附游戏服务器框架) 2020.06

    各语言对比 语言版本TIOBE排名垃圾回收类型系统性能Web后端非Web后端特性Java142是中Python3 83是动态低C 43 43 174高不适合Node js147 是动态低PHP7 48是动态低不适合Go1 1412是中Rub
  • 【stm32定时器配置步骤和相关概念解析——LL库】

    系列文章目录 文章目录 系列文章目录前言一 cubeMX定时器介绍二 通用寄存器三 PWM模式四 LL库 PWM模式 xff08 定时器14为例 xff09 1 结构体说明2 LL库代码 前言 一 cubeMX定时器介绍 Slave Mod
  • 华为MateBook&暗影精灵游戏本恢复出厂设置

    总目录 文章目录 总目录前言一 华为MateBook恢复出厂设置1 接上电源2 重启 开机按F10 二 暗影精灵游戏本恢复出厂设置1 接上电源2 重启 开机按F11 前言 记一次个人华为笔记本和暗影精灵游戏本的恢复操作 xff0c 说不准下
  • C/C++类库大全(附github连接)

    C 43 43 资源大全中文版 浏览中发现一篇总结的很全的c c 43 43 类库 xff0c 在此做记录 xff0c 以备不时之需 github地址 xff08 内有各个库的源码连接 xff09 https github com jobb
  • VScode 中 Clangd 使用

    1 VScode 中 Clangd 使用 VScode 中 Clangd 优缺点 优点 占用系统资源确实比 C C 43 43 少了很多 xff0c 无论是 CPU 还是 内存的使用 xff08 最重要 xff09 缺点 操作相较于 C C
  • FreeRTOS 线程安全的printf输出(使用STM32F103)

    https blog csdn net baidu 23187363 article details 53811144 环境 STM32F103开发板 HAL库 xff08 标准库也没事换个串口输出函数就行 xff09 MDK5 28 ST