使用 FreeRTOS 二进制信号量的硬件中断
Hardware interrupt with FreeRTOS binary semaphore
我基本上是想在按下按钮后让 LED 灯亮起。以下是应该处理此问题的代码片段:
void task_player1(void *pvParameters)
{
while (1)
{
if (xSemaphoreTake(player1_signal, portMAX_DELAY))
{
printf(">>>Semaphore taken\n<<<");
ioport_set_pin_level(L1, HIGH);
xSemaphoreGive(player1_signal);
}
else
{
ioport_set_pin_level(L1, LOW);
}
}
}
void task_ctrl(void *pvParameters)
{
bool button1 = 0;
while (1)
{
button1 = ioport_get_pin_level(B1);
if (button1)
{
xSemaphoreGive(player1_signal);
printf("Semaphore given\n");
}
}
}
我设想的方式是 task_ctrl
在按下按钮时给出信号量。 Task_player1
在获取信号量之前一直处于阻塞状态,之后它应该打开 LED。
问题是它似乎从不接收信号量。我正在 运行 宁 printf
语句来告诉我程序到达了多远,它永远不会进入 LED 亮起的部分。但是当我 运行 xSemaphoreGive
没有按下 task_ctrl
中的按钮时,信号量被占用。
奇怪的是 "Semaphore given\n"
语句在单击按钮时打印出来,这应该意味着信号量也已给出但从未被占用。
这些任务是独立完成的,我什至在没有按下按钮的 if 语句的情况下给出了信号量,就像我上面所说的那样。
我猜它与按钮按下代码有关,它在任务之外也可以独立运行。那我做错了什么?我没有正确使用 FreeRTOS 吗?
编辑:包括任务创建代码
#define TASK_STACK_SIZE (2048/ sizeof(portSTACK_TYPE))
xTaskCreate(task_ctrl, (const signed char * const) "Control", TASK_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(task_player1, (const signed char * const) "Player1", TASK_STACK_SIZE, NULL, 1, NULL);
编辑 2:可能我应该提到的是我使用的是 FreeRTOS 7.3,因为 Atmel Studio 没有任何更新的版本。因此,据我所知,没有可用的 yield 函数。
task_ctrl
从不阻塞 - 这将阻止任何具有相同或较低优先级的任务 ever 运行ning。因此,如果 task_player
具有相同或更低的优先级,则即使给出信号量,也永远不会安排任务。
它似乎在没有按钮轮询的情况下工作更难解释,但你没有显示该代码所以我无法评论。
你应该做两件事:
- 确保
task_ctrl
的优先级至少低于 task_player1
(如果不阻塞,则低于任何任务 - 在这种情况下,空闲任务永远不会 运行)。
- 确保
task_ctrl
阻塞 - 即使这只是一个 轮询延迟 ,这样它就不会耗尽所有可用的 CPU 周期。
while (1)
{
button1 = ioport_get_pin_level(B1);
if (button1)
{
xSemaphoreGive(player1_signal);
printf("Semaphore given\n");
vtaskDelay( 1 ) ; // at least 1 tick
}
}
task_ctrl
的一个可能问题是,它会在按住按钮时连续不断地重复发出信号量。某种状态变化检测和开关反跳而不是电平轮询可能更可取。
轮询任务的另一种解决方案是对按钮使用硬件中断,并让轮询任务阻止来自 ISR 的事件,或者让 ISR 直接提供信号量 - 无论哪种情况,您都将拥有处理去抖动。
我基本上是想在按下按钮后让 LED 灯亮起。以下是应该处理此问题的代码片段:
void task_player1(void *pvParameters)
{
while (1)
{
if (xSemaphoreTake(player1_signal, portMAX_DELAY))
{
printf(">>>Semaphore taken\n<<<");
ioport_set_pin_level(L1, HIGH);
xSemaphoreGive(player1_signal);
}
else
{
ioport_set_pin_level(L1, LOW);
}
}
}
void task_ctrl(void *pvParameters)
{
bool button1 = 0;
while (1)
{
button1 = ioport_get_pin_level(B1);
if (button1)
{
xSemaphoreGive(player1_signal);
printf("Semaphore given\n");
}
}
}
我设想的方式是 task_ctrl
在按下按钮时给出信号量。 Task_player1
在获取信号量之前一直处于阻塞状态,之后它应该打开 LED。
问题是它似乎从不接收信号量。我正在 运行 宁 printf
语句来告诉我程序到达了多远,它永远不会进入 LED 亮起的部分。但是当我 运行 xSemaphoreGive
没有按下 task_ctrl
中的按钮时,信号量被占用。
奇怪的是 "Semaphore given\n"
语句在单击按钮时打印出来,这应该意味着信号量也已给出但从未被占用。
这些任务是独立完成的,我什至在没有按下按钮的 if 语句的情况下给出了信号量,就像我上面所说的那样。
我猜它与按钮按下代码有关,它在任务之外也可以独立运行。那我做错了什么?我没有正确使用 FreeRTOS 吗?
编辑:包括任务创建代码
#define TASK_STACK_SIZE (2048/ sizeof(portSTACK_TYPE))
xTaskCreate(task_ctrl, (const signed char * const) "Control", TASK_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(task_player1, (const signed char * const) "Player1", TASK_STACK_SIZE, NULL, 1, NULL);
编辑 2:可能我应该提到的是我使用的是 FreeRTOS 7.3,因为 Atmel Studio 没有任何更新的版本。因此,据我所知,没有可用的 yield 函数。
task_ctrl
从不阻塞 - 这将阻止任何具有相同或较低优先级的任务 ever 运行ning。因此,如果 task_player
具有相同或更低的优先级,则即使给出信号量,也永远不会安排任务。
它似乎在没有按钮轮询的情况下工作更难解释,但你没有显示该代码所以我无法评论。
你应该做两件事:
- 确保
task_ctrl
的优先级至少低于task_player1
(如果不阻塞,则低于任何任务 - 在这种情况下,空闲任务永远不会 运行)。 - 确保
task_ctrl
阻塞 - 即使这只是一个 轮询延迟 ,这样它就不会耗尽所有可用的 CPU 周期。
while (1)
{
button1 = ioport_get_pin_level(B1);
if (button1)
{
xSemaphoreGive(player1_signal);
printf("Semaphore given\n");
vtaskDelay( 1 ) ; // at least 1 tick
}
}
task_ctrl
的一个可能问题是,它会在按住按钮时连续不断地重复发出信号量。某种状态变化检测和开关反跳而不是电平轮询可能更可取。
轮询任务的另一种解决方案是对按钮使用硬件中断,并让轮询任务阻止来自 ISR 的事件,或者让 ISR 直接提供信号量 - 无论哪种情况,您都将拥有处理去抖动。