文章目录
前言
前面包含了任务创建,任务删除,任务状态等
用到实际,如果通过串口发送数据,发到一半的过程中被打断了,过了一段时间再恢复,是不是通讯数据的错乱了,并且接受的串口数据的没法保证完整性。所以,要在部分情况下加个锁,此时就用到了互斥。如果发送是数据还没准备好,是不是发送指令要等待发送数据,这就是同步。
提示:以下是本篇文章正文内容,下面案例可供参考
一、非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,互斥会极大的浪费时间,同步有小概率会出现问题,任务被切换等。