读者*石 三*问:博主可以介绍下在RTOS下多个任务访问同一硬件的方法吗?比如说,多个任务都要用到串口打印信息。
我的回答是:使用互斥量、队列两种方式都能解决访问冲突的问题。
多线程访问同一串行硬件在许多系统中经常使用,如多个线程都使用UART收发数据、多个线程使用读写SPI_FLASH、I2C_E2PROM,CAN总线收发数据等······
如果每个线程都同时抢占同一串口去读写操作,那么很容易出现问题。为了解决其中的冲突问题,就需要使用一定的办法。下面以UART为例,基于FreeRTOS讲述一下基本的互斥量和队列方式的解决方法。
Ⅰ
互斥访问方法
互斥量:是一个可以处于两态之一的变量:解锁和加锁。
原理:创建一个互斥量,线程A在需要占用资源(使用UART发送数据),把资源(UART)占用。此时,线程B及其他线程就不能占用该资源。当线程A使用完资源(UART发送完数据),释放资源,其他线程就可以抢占该资源。
创建互斥量
线程A占用资源
使用资源(发送数据)
线程A释放资源
优先级高的线程B占用资源
使用资源
线程B释放资源
依次,优先级线程占用资源
·
·
·
代码:
//创建互斥量资源
SemaphoreHandle_t xSemaphore = NULL;
xSemaphore = xSemaphoreCreateMutex();
void TaskA(void *pvParameters)
{
for(;;)
{
//占用资源
if(xSemaphoreTake(xSemaphore, 10 ) == pdTRUE)
{
//使用资源(发送数据)
USART_SendNByte();
//释放资源
xSemaphoreGive(xSemaphore);
}
}
}
信号量与互斥量区别:
信号量:多线程同步使用的;一个线程完成某个动作后通过信号告诉别的线程,别的线程才可以执行某些动作;
互斥量:多线程互斥使用的;一个线程占用某个资源,那么别的线程就无法访问,直到该线程离开,其他线程才可以访问该资源;
Ⅱ
队列操作方法
队列操作方法就是FIFO,先入先出的原理。比如:线程A要使用UART发送一串数据,将其加入队列; 接着线程B也要使用UART发送一串数据。
那么,线程A将这串数据加入队列,接着线程B又将要发送的一串数据加入队列。
在另外一个UART发送的线程中,从队列中按照FIFO方式读取队列里面的数据,依次发送出去即可。
创建一个队列(发送数据队列)
创建一个任务(UART发送数据线程)
线程A加入队列
线程B加入队列
·
·
·
另外一边的线程,依次读取队列数据,使用UART发送出去。
代码:
QueueHandle_t xQueue;
xQueue = xQueueCreate(QUEUE_LENGTH, QUEUE_ITEM_SIZE);
xTaskCreate(UART_Send_Task, "UART_Send", STACK_SIZE, NULL, TASK_PRIORITY, NULL);
void TaskA(void *pvParameters)
{
for(;;)
{
//线程相关操作
//加入队列
xQueueSend(xQueue, &TaskA_Buf, 10)
}
}
void TaskB(void *pvParameters)
{
for(;;)
{
//线程相关操作
//加入队列
xQueueSend(xQueue, &TaskB_Buf, 10)
}
}
void UART_Send_Task(void *pvParameters)
{
for(;;)
{
//循环读取队列BUF
if(xQueueReceive(xQueue, &Buf, 10) == pdTRUE)
{
USART_SendNByte(&Buf);
}
}
}
以上两种方法是常用的,希望大家都掌握一下。 上述仅让大家掌握原理,代码不宜直接复制粘贴使用。
推荐阅读:
Ⅲ
最后
置顶公众号,不怕找不到我;
记得给我点赞哦!
微信搜索“strongerHuang” 或者扫描下面二维码、关注,在我的底部菜单查看更多精彩内容!
长按识别二维码 关注