1、总结二进制信号量和计数型信号量的区别,以及他们的使用场景。
二进制信号量:信号量的数值只能是0和1,用于共享资源的访问
计数型信号量:信号量的值都是大于或者等于2,实现生产者和消费者模型
2、使用技术型信号量完成生产者和消费者模型实验。
void StartDefaultTask(void *argument)
{
for(;;)
{
osSemaphoreRelease(myCountingSem01Handle);
printf("生产1\r\n");
osSemaphoreRelease(myCountingSem01Handle);
printf("生产2\r\n");
osDelay(500);
}
}
void StartTask02(void *argument)
{
for(;;)
{
osSemaphoreAcquire(myCountingSem01Handle,osWaitForever);
printf("消费者1\r\n");
osSemaphoreAcquire(myCountingSem01Handle,osWaitForever);
printf("消费者2\r\n");
osSemaphoreAcquire(myCountingSem01Handle,osWaitForever);
printf("消费者3\r\n");
osDelay(500);
}
}
3、总结FreeRTOS中同步和互斥的五种方法的使用方法
1)队列:用于任务之间的通信,也可以存储数据
//创建队列函数
osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr)
uint32_t msg_count:队列的容量
uint32_t msg_size:队列元素的大小
const osMessageQueueAttr_t *attr:属性
osMessageQueueId_t:创建队列返回的ID,通过这个ID可以找到对应的队列
//队列写函数
osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout)
osMessageQueueId_t mq_id:数据要写入哪个队列
const void *msg_ptr:要写入数据的地址
uint8_t msg_prio:数据的优先级,一般设置为0
uint32_t timeout:超时时间,单位是ms,特殊的值:osWaitForerver:一直等待,让任务去休眠
//队列读函数
osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout)
osMessageQueueId_t mq_id:要从哪个队列中读取数据
void *msg_ptr:数据要保存的地址
uint8_t *msg_prio:数据的优先级,一般设置为NULL
uint32_t timeout:超时时间
osStatus_t:是否读取成功
2)信号量:用于实现任务之间的同步和互斥
//创建信号量的函数:
osSemaphoreId_t osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr)
uint32_t max_count:信号量的最大值,二进制信号量的最大值是1
uint32_t initial_count:信号量的初始值
const osSemaphoreAttr_t *attr:信号量的属性
osSemaphoreId_t:信号量的ID
//获取信号量函数:
osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout)
osSemaphoreId_t semaphore_id:要获取哪一个信号量
uint32_t timeout:超时时间
osStatus_t:是否获取成功
获取成功信号量的值减一
//释放信号量函数:
osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id)
osSemaphoreId_t semaphore_id:要释放哪一个信号量的ID
osStatus_t:是否释放成功
释放成功信号量的值加一
3)互斥量:用于保护共享资源
//创建互斥量函数:
osMutexId_t osMutexNew (const osMutexAttr_t *attr)
const osMutexAttr_t *attr:互斥量的属性
osMutexId_t:互斥量的ID
//获取锁函数:
osStatus_t osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout)
osMutexId_t mutex_id:要获取哪一个互斥量
uint32_t timeout:超时时间
osStatus_t:是否成功获取到互斥量
//释放互斥量函数:
osStatus_t osMutexRelease (osMutexId_t mutex_id)
osMutexId_t mutex_id:要释放的互斥量ID
osStatus_t:是否成功释放
4)事件组:允许任务等待多个事件的状态,并且可以在任何事件被设置时唤醒等待的任务
//创建事件组函数:
osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr)
const osEventFlagsAttr_t *attr:属性
osEventFlagsId_t:事件组的ID
//设置事件组函数:
uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags)
osEventFlagsId_t ef_id:要设置的事件组的ID
uint32_t flags:要设置的事件
//等待事件组函数:
uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout)
osEventFlagsId_t ef_id:要等待一个哪一个事件组
uint32_t flags:要等待什么事件
uint32_t options:等待的选项,osFlagsWaitAll:等待全部事件完成,osFlagsWaitAny:等待任意事件完成
5)任务通知:通知任务,用来实现任务之间的同步和互斥
//任务通知函数:
uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags)
osThreadId_t thread_id:要通知任务的ID
uint32_t flags:要设置哪一个事件
//任务通知等待函数:
uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout)
uint32_t flags:要等待哪些事件
uint32_t options:等待的选项
uint32_t timeout:超时时间
4、总结任务通知和其他任务通信机制的区别
1)任务通知无需创建,可以直接使用,通过任务控制块来实现(TCB),队列、信号量、互斥量、事件组都需要创建后才能使用。
2)任务通知所需的资源比队列、信号量、互斥量、事件组要少。
3)队列、信号量、互斥量、事件组主要用于多对多之间的通信,任务通知是一对一之间的通信。
5、根据文档和录屏学习一下软件定时器,了解软件定时器的作用和软件定时器和硬件定时器的区别
软件定时器的作用:在指定的时间到来时执行指定的函数,或者以某个频率周期性地执行某个函数。被执行的函数叫做软件定时器回调函数。
区别:
1)硬件定时器精度比软件定时器高
2)软件定时器消耗的资源比较多
3)软件定时器的数量理论上没有限制,硬件定时器的数量和硬件相关