我正试图在IAR Workbench IDE中的STM32 F401RE MCU上使用FreeRTOS打开和关闭led。
led属于STM32核板。有两个任务,一个打开Led,另一个关闭相同的Led。
这是代码:
主要代码:
SemaphoreHandle_t xMutex;
int main()
{
if ( xMutex == NULL )
{
xMutex = xSemaphoreCreateMutex();
if ( ( xMutex ) != NULL )
xSemaphoreGive( ( xMutex ) );
}
xTaskCreate(LedOn, "Led On", 100, NULL, 1, NULL);
xTaskCreate(LedOff, "Led Off", 100, NULL, 1, NULL);
vTaskStartScheduler();
while(1){}
}
任务:
void LedOn(void *argument)
{
for(;;)
{
xSemaphoreTake( xMutex, ( TickType_t )5000 ) ;
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
vTaskDelay(5000);
xSemaphoreGive(xMutex);
}
}
void LedOff(void *argument)
{
for(;;)
{
xSemaphoreTake( xMutex, ( TickType_t )5000 ) ;
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
vTaskDelay(5000);
xSemaphoreGive(xMutex);
}
}
我的意图是:
Led on任务负责开启Led进行5s
Led off任务负责关闭Led进行5s
因此,这种情况将持续到断电
我的问题是:
在最初的情况下,在Led保持5秒关闭后,Led保持5秒钟打开。在两次切换后,Led仅工作两次上下文切换。
当我在两次切换后调试时,断点没有击中任务
经过一点尝试,我想我找到了答案:
每个任务都应该有它的延迟时间,所以我们需要添加一个延迟时间来执行它的操作,但我认为我添加了xTakeSemaphore
和xGiveSemaphore
方法之间的延迟时间是互斥延迟时间,它说明了资源应该如何锁定,而不是任务延迟时间。
解决方案是:
void LedOn(void *argument)
{
for(;;)
{
if(xSemaphoreTake(xMutex, portMAX_DELAY)== pdTRUE)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
vTaskDelay(pdMS_TO_TICKS(5000));
xSemaphoreGive(xMutex);
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
}
void LedOff(void *argument)
{
for(;;)
{
if( xSemaphoreTake( xMutex, portMAX_DELAY)== pdTRUE)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
vTaskDelay(pdMS_TO_TICKS(5000));
xSemaphoreGive(xMutex);
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
}
考虑"任务A"是LedOn
,"任务B"是LedOff
。或者,相反,因为这对问题无关紧要。
假设任务B已经获取了互斥。
您的问题是任务A的xSemaphoreTake
可能超时了,而没有获取互斥。
您应该检查返回代码。
原因是它的超时值为5000个刻度。但是,任务B执行vTaskDelay(5000)
。而且,当它这样做的时候,它已经锁定了互斥
因此,在任务B释放互斥之前,任务A的xSemaphoreTake
很可能会超时。
然后,翻转LED值,并进行延迟。但是,您在一个互斥体上执行xSemaphoreGive
,而任务a并没有锁定该互斥体。
换句话说,你有种族条件。
在take调用中设置无限超时,或者至少设置一个比您给延迟函数的值大的值。
尝试取(例如(10000
永远等待互斥
xSemaphoreTake( xMutex, portMAX_DELAY);
在两项任务中。
优先级调度RTOS的通常前提是,准备运行的最高优先级任务/线程优先于以较低优先级运行的任务/线程。
LedOff
和LedOn
任务都是以相同的优先级创建的,因此当信号量发出信号时,上下文切换不会立即发生。
当它绕过循环并试图再次使用信号量时,可能会发生上下文切换。现在有两项任务在争夺它
谁获胜本质上是FreeRTOS的一个实现细节,尤其是信号量对信号量的操作是否以严格的FIFO顺序进行——VxWorks(FreeRTOS似乎是以其为主要模型(可以选择这样做的ISTR。
POSIX线程(FreeRTOS也支持(的另一种方法是唤醒等待的线程,并首先调度该线程要使用的信号量——这肯定是已经在运行的信号量。
作为一个更普遍的观点,你已经极大地过度复杂了一个有两个状态的有限状态机。实现这一目标的一种高度可靠的方法是:
void LedFlasher(void *argument)
{
for(;;)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
vTaskDelay(5000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
vTaskDelay(5000);
}
}
有点晚了..;(但我认为你的程序中有个错误。互斥体的初始释放(主中的xSemaphoreGive(会破坏它。创建了一个互斥对象,准备就绪,即处于释放状态。