STM32FreeRtos入门(五)——同步互斥与通信

文章目录


前言

前面包含了任务创建,任务删除,任务状态等

用到实际,如果通过串口发送数据,发到一半的过程中被打断了,过了一段时间再恢复,是不是通讯数据的错乱了,并且接受的串口数据的没法保证完整性。所以,要在部分情况下加个锁,此时就用到了互斥。如果发送是数据还没准备好,是不是发送指令要等待发送数据,这就是同步。


提示:以下是本篇文章正文内容,下面案例可供参考

一、非Freertos的同步通信

简单来说,中间增加

while (g_calc_end == 0);

来等待通信

c 复制代码
static StackType_t g_pucStackOfLightTask[128];
static StaticTask_t g_TCBofLightTask;
static TaskHandle_t xLightTaskHandle;

static StackType_t g_pucStackOfColorTask[128];
static StaticTask_t g_TCBofColorTask;
static TaskHandle_t xColorTaskHandle;

/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
struct TaskPrintInfo {
	uint8_t x;
	uint8_t y;
	char name[16];
};

static struct TaskPrintInfo g_Task1Info = {0, 0, "Task1"};
static struct TaskPrintInfo g_Task2Info = {0, 3, "Task2"};
static struct TaskPrintInfo g_Task3Info = {0, 6, "Task3"};
//static int g_LCDCanUse = 1;
//static volatile int g_Calc_end = 0;
//static uint64_t g_Calc_time = 0;
//static uint32_t g_sum = 0;

static int g_LCDCanUse = 1;
static volatile int g_calc_end = 0;
static uint64_t g_Calc_time = 0;
static uint64_t g_sum = 0;

//void CalcTask(void *params)
//{
//	uint32_t i = 0;
//	LCD_PrintString(0, 0, "Waiting");
//	g_Calc_time=system_get_ns();
//   for (i=0;i<10000000;i++)
//	{
//		g_sum += i;
//	}
//	g_calc_end = 1;
//	g_Calc_time=system_get_ns() - g_Calc_time;
//	vTaskDelete(NULL);
//}


void CalcTask(void *params)
{
	uint32_t i = 0;
	
	LCD_PrintString(0, 0, "Waiting");

	g_Calc_time = system_get_ns();
	for (i = 0; i < 10000000; i++)
	{
		g_sum += i;
	}
	g_calc_end = 1;
	g_Calc_time = system_get_ns() - g_Calc_time;

	vTaskDelete(NULL);
}




void LcdPrintTask(void *params)
{
	int len;
	while (1)
	{
		LCD_PrintString(0, 0, "Waiting");
		
		vTaskDelay(3000);
		
		while (g_calc_end == 0);
		
		/* 打印信息 */
		if (g_LCDCanUse)
		{
//			g_LCDCanUse = 0;
//			LCD_ClearLine(0,0);
//			len = LCD_PrintString(0, 0, "sum:");
//			LCD_PrintHex(len, 0, g_sum,1);
			
			g_LCDCanUse = 0;
			
			LCD_ClearLine(0,0);
			len = LCD_PrintString(0, 0, "Sum: ");
			LCD_PrintHex(len, 0, g_sum, 1);			
			
			LCD_ClearLine(0,2);
			len = LCD_PrintString(0, 2, "time(ns):");
			LCD_PrintSignedVal(len, 2, g_Calc_time);
			
			g_LCDCanUse = 1;
		}
		vTaskDelete(NULL);
	}
}

  xTaskCreate(CalcTask, "task1", 128, NULL, osPriorityNormal, NULL);
  xTaskCreate(LcdPrintTask, "task2", 128, &g_Task2Info, osPriorityNormal, NULL);

二、非Freertos的互斥通信

非 FreeRTOS 环境下的互斥通信,核心是通过软件算法或硬件机制,确保多个执行单元(如任务、中断)安全访问共享资源,避免数据竞争。

常用例子;标志位

举例:

禁止中断(Disable Interrupts)

在访问共享资源前,关闭所有可能抢占当前执行流程的中断。

完成资源操作后,重新使能中断。

适用场景:单 CPU、对实时性要求不高的简单场景,如裸机中任务与中断的资源共享。

测试并置位(Test-and-Set, TAS)

借助 CPU 指令(如XCHG、BTS),原子性地检查并设置一个标志位。

若标志位为 "未占用",则置位并获取资源;若已占用,则循环等待(忙等)。

适用场景:多任务环境,依赖 CPU 的原子指令支持。

三、Freertos的同步与互斥函数以及通信

具体历程下一章写


总结

这些实现不依赖 FreeRTOS 的osMutex等 API,而是基于底层硬件特性或通用编程范式,适用于裸机(Bare-metal)、RT-Thread、μC/OS 等其他系统或无操作系统场景。

在系统中,如果不依靠FreeRTOS的osMutex等 API,互斥会极大的浪费时间,同步有小概率会出现问题,任务被切换等。

相关推荐
戴誉杰1 小时前
idea 2025.2 重置试用30天,无限期使用
java·ide·intellij-idea
q***78782 小时前
Spring学习——新建module模块
java·学习·spring
q***11652 小时前
在Nginx上配置并开启WebDAV服务的完整指南
java·运维·nginx
白起那么早2 小时前
我又开发了一款idea插件-ContiNewGenerator
java·后端
装不满的克莱因瓶2 小时前
【Java架构师体系课 | MySQL篇】③ Explain执行计划详解
java·数据库·mysql·架构·优化·索引·explain
王煜苏2 小时前
最新版idea2025 配置docker 打包spring-boot项目到生产服务器全流程,含期间遇到的坑
java·docker·容器
李玮豪Jimmy2 小时前
Day18:二叉树part8(669.修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树)
java·服务器·算法
后端小张3 小时前
【AI 学习】AI Agent 开发进阶:架构、规划、记忆与工具编排
java·人工智能·ai·架构·系统架构·agent·智能体
Jerry丶Li3 小时前
二十八、STM32的USART (介绍)
stm32·单片机·嵌入式硬件
西岭千秋雪_3 小时前
Kafka客户端整合
java·spring boot·分布式·kafka·linq