c-FreeRTOS中具有互斥功能的两个任务同步



我正试图在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仅工作两次上下文切换。

当我在两次切换后调试时,断点没有击中任务

经过一点尝试,我想我找到了答案:

每个任务都应该有它的延迟时间,所以我们需要添加一个延迟时间来执行它的操作,但我认为我添加了xTakeSemaphorexGiveSemaphore方法之间的延迟时间是互斥延迟时间,它说明了资源应该如何锁定,而不是任务延迟时间。

解决方案是:

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的通常前提是,准备运行的最高优先级任务/线程优先于以较低优先级运行的任务/线程。

LedOffLedOn任务都是以相同的优先级创建的,因此当信号量发出信号时,上下文切换不会立即发生。

当它绕过循环并试图再次使用信号量时,可能会发生上下文切换。现在有两项任务在争夺它

谁获胜本质上是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(会破坏它。创建了一个互斥对象,准备就绪,即处于释放状态。