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

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

### 回答1: 好的,我可以回答这个问题。首先,您需要下载FreeRTOS和freemodbus的源代码,然后根据STM32F103的硬件特性进行适当的修改和配置。最后,将修改后的代码编译并烧录到STM32F103上即可。具体的步骤可以参考相关的开发文档和教程。 ### 回答2: 要将FreeRTOS freemodbus移植到STM32F103上,首先需要了解STM32F103的硬件特性和FreeRTOS、freemodbus的工作原理。然后按照以下步骤进行移植: 1. 首先,将STM32F103的开发环境搭建好,包括安装相关的开发工具和驱动程序。 2. 从FreeRTOS官方网站下载最新版本的FreeRTOS源代码,并解压缩到工程目录下。 3. 从freemodbus官方网站下载最新版本的freemodbus源代码,并解压缩到工程目录下。 4. 打开STM32F103的开发环境,创建一个新的工程。 5. 将FreeRTOS的源代码添加到工程中,包括核心代码、任务调度器、内存管理等。 6. 根据STM32F103的硬件特性,配置相关的寄存器和引脚,确保与FreeRTOS的功能相匹配。 7. 将freemodbus的源代码添加到工程中,包括主站、从站和串口通信等模块。 8. 通过配置文件或修改源代码,设置freemodbus的参数,如波特率、数据位、停止位等。 9. 在工程中创建一个新的任务,用于处理freemodbus的通信逻辑。 10. 编译并下载程序到STM32F103。 11. 运行程序,通过串口或其他方式检测和验证freemodbus的通信功能。 12. 根据实际需求,对移植后的FreeRTOS freemodbus进行优化和调试。 以上是将FreeRTOS freemodbus移植到STM32F103的大致步骤,具体的实施过程需要根据具体的环境和需求进行调整。在移植过程中可能会遇到一些问题和挑战,需要仔细阅读相关文档和参考资料,并进行适当的学习和研究。 ### 回答3: 要将FreeRTOS freemodbus移植到STM32F103上,需要按照以下步骤进行操作: 1. 首先,需要确保你熟悉STM32F103的操作和编程。了解该微控制器的寄存器和外设配置,以及相应的开发工具和环境设置。熟悉使用STM32CubeMX来进行初始化和配置。 2. 下载FreeRTOS和freemodbus库的最新版本。可以从官方网站下载并解压这两个库。 3. 在STM32CubeMX中,创建一个新的项目,并选择适合你的STM32F103型号的芯片。 4. 在配置时,确保使能FreeRTOS和freemodbus库。这些库应该是预编译好的二进制文件,所以不需要进行额外的编译工作。 5. 在配置文件中,设置FreeRTOS的任务和堆栈大小,根据你的需求进行适当的调整。还要根据freemodbus库的要求,配置相应的寄存器和外设。 6. 在生成代码后,你将得到一个基本的FreeRTOS和freemodbus库的项目框架。在这个框架中,你可以添加自定义任务和功能,以满足你的应用需求。例如,你可以添加具体的modbus从站和主站的实现。 7. 通过FreeRTOS的任务和队列机制,你可以实现多任务并发和通信。在这个框架中,你可以创建多个modbus任务,以处理不同的modbus请求。 8. 配置UART或其他串行通信外设来与modbus通信。这取决于你的具体需求和硬件配置。 9. 最后,编译和下载固件到STM32F103上,然后运行你的应用程序。确保程序正常工作并能够实现预期的功能。 总结起来,移植FreeRTOS freemodbus库到STM32F103的过程需要熟悉STM32F103的编程和操作,配置合适的开发环境和工具,同时充分理解和使用FreeRTOS和freemodbus库的功能和特性。通过合理的任务分配和通信机制,你可以实现一个高效可靠的modbus通信应用。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值