欢迎光临
我们一直在努力

FreeRTOS点灯(2)——创建两个LED点灯任务

接上一节,我们已经学习了FreeRTOS任务创建函数xTaskCreate()各个参数的含义。这一节通过创建两个LED点灯任务,进一步理解FreeRTOS任务的创建和运行过程。


一、确定LED的点亮电平

编写程序之前,首先需要确定自己开发板上的LED是高电平点亮还是低电平点亮。

我使用的开发板LED采用低电平点亮:

GPIO_ResetBits(GPIOE, GPIO_Pin_3);

GPIO输出低电平,LED点亮。

GPIO_SetBits(GPIOE, GPIO_Pin_3);

GPIO输出高电平,LED熄灭。

如果使用的开发板是高电平点亮,则需要将上述两个操作互换。

二、编写LED任务函数

这里分别控制单片机上的两个LED灯,并给两个LED设置不同的闪烁周期。

为了避免两个LED的控制代码耦合在一起,我分别创建两个独立任务。

任务1

void task1(void *pvParameters)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(300));

GPIO_ResetBits(GPIOE, GPIO_Pin_3);

vTaskDelay(pdMS_TO_TICKS(300));

GPIO_SetBits(GPIOE, GPIO_Pin_3);
}
}

任务1控制PE3引脚连接的LED。

任务运行后,先延时300ms,然后输出低电平点亮LED;再次延时300ms,输出高电平熄灭LED。之后程序返回循环开头,不断重复执行。

任务2

void task2(void *pvParameters)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(1000));

GPIO_ResetBits(GPIOE, GPIO_Pin_4);

vTaskDelay(pdMS_TO_TICKS(1000));

GPIO_SetBits(GPIOE, GPIO_Pin_4);
}
}

任务2控制PE4引脚连接的LED。

任务2的延时时间为1000ms,因此它的闪烁速度比任务1更慢。

三、vTaskDelay()函数

vTaskDelay()用于让当前任务进入阻塞状态。

例如:

vTaskDelay(pdMS_TO_TICKS(300));

表示当前任务阻塞300ms。

任务进入阻塞状态后不会继续占用CPU。在任务1延时期间,FreeRTOS可以调度任务2或者其他已经进入就绪状态的任务运行。

vTaskDelay()原本接收的参数单位是系统节拍Tick,而不是固定的毫秒数。

例如:

vTaskDelay(300);

表示延时300个系统节拍。只有在系统节拍频率为1000Hz时,300个Tick才等于300ms。

因此,程序中推荐使用:

pdMS_TO_TICKS(300)

将毫秒转换为系统节拍,这样即使以后修改FreeRTOS系统节拍频率,延时时间仍然可以保持正确。

四、创建两个LED任务

任务函数编写完成后,在main()函数中使用xTaskCreate()创建两个任务。

int main(void)
{
BaseType_t task1_result;
BaseType_t task2_result;

/* LED初始化 */
LED_Init();

/* 创建任务1 */
task1_result = xTaskCreate(
task1, //任务函数
"task1", //任务名称
128, //任务栈大小
NULL, //任务参数
1, //任务优先级
NULL //任务句柄
);

/* 创建任务2 */
task2_result = xTaskCreate(
task2,
"task2",
128,
NULL,
1,
NULL
);

/* 判断两个任务是否创建成功 */
if((task1_result == pdPASS) &&
(task2_result == pdPASS))
{
/* 启动任务调度器 */
vTaskStartScheduler();
}

while(1)
{
}
}

这里使用两个BaseType_t类型的变量,分别保存两个任务的创建结果。

task1_result = xTaskCreate(…);
task2_result = xTaskCreate(…);

如果任务创建成功,xTaskCreate()会返回pdPASS。

如果创建失败,通常说明FreeRTOS堆空间不足,无法为任务分配任务控制块和任务栈空间。

两个任务创建完成后,通过下面的代码判断两个任务是否都创建成功:

if((task1_result == pdPASS) &&
(task2_result == pdPASS))

只有两个任务都创建成功,才调用:

vTaskStartScheduler();

启动FreeRTOS任务调度器。

五、任务开始运行

执行vTaskStartScheduler()后,FreeRTOS开始进行任务调度。

任务1和任务2的优先级都设置为1:

uxPriority = 1;

两个任务的优先级相同,但是它们在执行vTaskDelay()后都会进入阻塞状态。

例如,任务1进入延时后,CPU不会停在任务1中等待,而是可以继续执行任务2。任务2进入延时后,CPU又可以运行其他处于就绪状态的任务。

因此,两个LED任务虽然写在不同的函数中,却可以同时按照各自的延时时间运行。

程序下载到单片机后,可以看到:

PE3连接的LED以300ms为间隔改变亮灭状态;

PE4连接的LED以1000ms为间隔改变亮灭状态。

两个LED由两个独立的任务控制,彼此之间不会直接影响。

六、总结

这一节创建了两个简单的LED点灯任务。

整个程序的基本流程为:

编写任务函数;

使用xTaskCreate()创建任务;

判断任务是否创建成功;

调用vTaskStartScheduler()启动任务调度器;

FreeRTOS根据任务状态调度两个LED任务运行。

通过这个实验可以直观地看到,FreeRTOS并不是让一个任务执行结束后再执行另一个任务,而是在任务阻塞、就绪和运行等状态之间进行切换,从而实现多个任务的并发运行。

赞(0)
未经允许不得转载:171主机测评 » FreeRTOS点灯(2)——创建两个LED点灯任务
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址