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,互斥会极大的浪费时间,同步有小概率会出现问题,任务被切换等。

相关推荐
利刃大大8 分钟前
【SpringBoot】validation参数校验 && JWT鉴权实现 && 加密/加盐
java·spring boot·jwt·加密
小北方城市网14 分钟前
第 3 课:前后端全栈联动核心 —— 接口规范 + AJAX + 跨域解决(打通前后端壁垒)
java·大数据·网络·python
降临-max19 分钟前
JavaWeb企业级开发---MySQL
java·开发语言·数据库·笔记·后端·mysql
C雨后彩虹20 分钟前
二维伞的雨滴效应
java·数据结构·算法·华为·面试
一路往蓝-Anbo22 分钟前
C语言从句柄到对象 (八) —— 当对象会说话:观察者模式与事件链表
c语言·开发语言·数据结构·stm32·单片机·观察者模式·链表
polarislove021423 分钟前
9.5 [定时器]输入捕获-嵌入式铁头山羊STM32笔记
笔记·stm32·嵌入式硬件
oMcLin24 分钟前
Ubuntu 22.04 Docker 容器启动失败:解决 Overlay2 存储驱动冲突
java·ubuntu·docker
Knight_AL39 分钟前
深入理解Java中的函数式接口
java·开发语言·python
Chen不旧40 分钟前
Java实现三个线程顺序打印
java·开发语言
Ahtacca1 小时前
Redis 五大常用数据类型详解及 Java 客户端(RedisTemplate)操作实战
java·数据库·redis·学习·缓存