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;

void LcdPrintTask(void *params)
{
	struct TaskPrintInfo *pInfo = params;
	uint32_t cnt = 0;
	int len;
	
	while (1)
	{
		/* ´òÓ¡ÐÅÏ¢ */
		if (g_LCDCanUse)
		{
			g_LCDCanUse = 0;
			len = LCD_PrintString(pInfo->x, pInfo->y, pInfo->name);
			len += LCD_PrintString(len, pInfo->y, ":");
			LCD_PrintSignedVal(len, pInfo->y, cnt++);
			g_LCDCanUse = 1;
		}
		mdelay(500);
	}
}


  xTaskCreate(LcdPrintTask, "task1", 128, &g_Task1Info, osPriorityNormal, NULL);
  xTaskCreate(LcdPrintTask, "task2", 128, &g_Task2Info, osPriorityNormal, NULL);
  xTaskCreate(LcdPrintTask, "task3", 128, &g_Task3Info, osPriorityNormal, NULL);


pInfo:这是一个指向 struct TaskPrintInfo 类型的指针变量。
• params:函数参数,是一个 void * 类型的指针。这行代码将 params 赋值给 pInfo,实际上是将传入的通用指针转换为指向 struct TaskPrintInfo 类型的指针。
 

g_Task1Info、g_Task2Info 和 g_Task3Info 分别包含了不同的打印信息(如打印位置和任务名称)。通过将这些不同的信息作为参数传递给 LcdPrintTask 函数,使得同一个函数可以在不同的任务中使用

xTaskCreate 传参:是在创建任务时,将不同的任务数据传递给任务函数,用于区分不同任务的特性和需求,是任务级别的参数传递。
• 函数内部传参:是在任务函数内部,将已经从 xTaskCreate 传递进来的参数进一步传递给其他函数,用于完成具体的功能,是函数调用级别的参数传递。
流程
先定义一个结构体TaskPrintInfo,

写出函数主体

void LcdPrintTask(void *params)
{
	uint32_t cnt = 0;
	int len;
  struct printifinfo *info=params;

	
	while(1)
	{
		if(g_lcdcanuse)
		{
			g_lcdcanuse=0;
		 len =LCD_PrintString(info->x, info->y, info->word);
		 len +=LCD_PrintString(len, info->y, ":");
		 LCD_PrintSignedVal(len, info->y, cnt++);
			g_lcdcanuse=1;
		}
	   mdelay(500);
	}
		

	
	
}

其中g_lcdcanuse(全局变量)为了防止iic传输过程被切换,mdelay(500);为了防止任务一直在一个任务里切换不出去。

然后定义三个类型为TaskPrintInfo的任务的不同参数的结构体用于给不同的任务传参(位置不同和打印信息不同)。

static struct printifinfo task1={0,0,"task1"};
 static struct printifinfo task2={0,3,"task2"};
 static struct printifinfo task3={0,6,"task3"};

最后用同一个函数设置三个任务

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

别忘了在freertos——init前初始化lcd和清屏

提问:

1.使用全局变量使不同任务互斥访问同一个函数有什么缺陷

全局变量的读写操作通常不是原子的(尤其是在多核或中断场景下)。例如,一个任务可能在检查全局变量后(认为资源可用)被调度器切换,此时另一个任务也可能检查同一变量并进入临界区,导致两者同时访问共享资源。
原子操作(Atomic Operation) 是指一个操作在执行过程中不可被中断,要么完全执行,要么完全不执行,中间不会被打断(例如被任务切换、中断或其他核心的访问)。这种特性确保了在多任务、多核或中断场景下,对共享资源的操作不会因并发访问导致数据不一致或逻辑错误。
例如系统提供的同步原语(如互斥量)或硬件支持的原子指令。

2.为什么最后创建的task3最先运行

创建任务时,xcuurentTCB指针会跟着新创建的任务,从当前任务开始找最高优先级任务,当优先级都相同时,就从当前任务开始运行

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐