1.单片机delay函数和FReeRTOS中delay函数的区别
单片机默认的delay函数则一直是cnt++,在计数过程中不会进行其他时间,故会占用很大的资源,影响其然任务的进行。
FReeRTOS中的vTaskDelay函数是由定时器tick进行计数的,当前任务调用delay函数可以理解为将其任务调转到阻塞态,让当前任务放弃调度,定时由FReeRTOS内部的tick计数器完成,它是不会影响其他任务的进行,
2.两个FreeRTOS的delay函数
vTaskDelay可以理解为绝对时间,它就是延迟你所给的时间,而vTaskDelayUntil可以理解为相对时间,好比你规定了一个15ms的总时间,它会根据你任务执行时间的大小动态的调整延时时间,使其总时间达到15ms。因此需要xTaskGetTickCount();来获得当前计数器所计数的时间,也就是传入的第一个参数,第二个参数即为延时的总时间。
3.同步和互斥
在团队活动里,同事A先写完报表,经理B才能拿去向领导汇报。经理B必须等同事A完成报表,AB之间有依赖,B必须放慢脚步,被称为同步。在团队活动中,同事A已经使用会议室了,经理B也想使用,即使经理B是领导,他也得等着,这就叫互斥。经理B跟同事A说:你用完会议室就提醒我。这就是使用"同步"来实现"互斥"。
在裸机程序里,可以使用一个全局变量或静态变量(注意volatile关键字的使用)实现互斥操作,但是在 RTOS 里,使用上述代码实现互斥操作时,会有很小概率出现错误,导致双方任务不能实现互斥。
4.任务之间如何传递信息
1.定义全局变量:但有一定概率达不到互斥的情况,若使用关中断和开中断的办法,假设任务A一直运行,但任务B也在同样运行,一直在判断自己能否使用临界资源,占用了大量的CPU资源。
2.使用环形缓冲区:本质就是一个环形队列,当写的值差读的值1个单位时,此时认为已经满了。适用于两个任务之间,且任务之间不能使用同一个全局变量,以防止出现错误。保证了没有一个变量被同时访问,间接的实现了互斥操作。
3.队列:数据的读写本质就是环形缓冲区,在这个基础上增加了互斥措施、阻塞-唤醒机制。如果这个队列不传输数据,只调整"数据个数的值",它就是信号量(semaphore)。如果信号量中,限定“数据个数”的最大值为1,它就是互斥量(mutex)。
信号量和互斥量的本质都是队列,而队列的本质就是加了保护措施的环形缓冲区。
5.读队列和写队列
读队列和写队列都有三种情况。
读队列:1.队列不为空,直接读出数据;2.队列为空,进入阻塞态,从就绪队列被放入接收队列和delay队列里,在设定的超时时间内有其他任务写入队列,则会被重新移入到就绪队列内,等待任务调度器进行调度,调度完成后读到数据;3.若在超时范围内没有接收到数据,同样会移动到就绪队列内,不过函数会有个错误的返回值,等待处理。
写队列同样的道理。同时,队列内还会存放两个链表,分别指向读和写队列任务的句柄,这样在队列不空或者不满的情况下,可以通知到他们。
任务读写队列时,简单地说:如果读写不成功,则阻塞;可以指定超时时间。口语化地说,就是可以定个闹钟:如果能读写了就马上进入就绪态,否则就阻塞直到超时。
某个任务读队列时,如果队列没有数据,则该任务可以进入阻塞状态:还可以指定阻塞的时间。如果队列有数据了,则该阻塞的任务会变为就绪态。如果一直都没有数据,则时间到之后它也会进入就绪态。
有多个任务在等待同一个队列的数据。当队列中有数据时,哪个任务会进入就绪态:1.优先级最高的任务;2.如果大家的优先级相同,那等待时间最久的任务会进入就绪态
6.队列的基本函数
1、创建队列:
动态分配:
静态分配:
2、复位队列:
3、删除队列:
4、写队列:
队列默认都是写尾部,也就是SendToBack,若想写在头部,则是xQueueSendToFront。ISR指的是中断服务程序,意思是在中断中操作队列。
5、读队列:
7.队列集
假设我有一个设备,可以使用多种方式来控制这个设备,但每种控制的方法是不一样的,好比方法一是串口接收、方法二是按键接收、方法三是陀螺仪控制,因此我们每一个方法的处理逻辑是不一样的,为了防止过度耦合,我们就可以创建三个队列,然后设定一个队列集,并将这三个队列加入到队列集内,队列集本质记录的是各个队列的句柄的先后顺序,当写入队列时,它也同样会被记入到队列集内。这样我们就可以读队列集,得到有数据的队列句柄,然后根据不同队列名称,处理不同的方法。最后在将处理好的数据写入到最终需要控制设备的队列。
8.队列集函数
创建队列:
把队列加入队列集:
读取队列集:
9.信号量
消息队列用于传输多个数据,但是有时候我们只需要传递状态,就采用了信号量。可以表示cpu的资源,好比我可以执行四个任务,若开始一个任务,信号量--。释放一个任务,信号量++。
信号:起通知作用;量:还可以用来表示资源的数量
当"量"没有限制时,它就是"计数型信号量"(Counting Semaphores)
当"量"只有0、1两个取值时,它就是"二进制信号量"(Binary Semaphores)
支持的动作:"give"给出资源,计数值加1;"take"获得资源,计数值减1。
作用:简单性和效率:二值信号的机制简单,只需要一个计数器就可以表示资源是否可用,信号量的获取和释放不需要像队列一样创建、拷贝、存储和删除等操作,效率更高。资源的管理:非常适合用于表示有限资源的数量,如资源池中有多少资源可用。而对于那些不需要传递任何数据,只是单纯想同步任务执行顺序的情况,信号量是一个很好的选择。实现同步
二进制信号量跟计数型的唯一差别,就是计数值的最大值被限定为1。
10.信号量函数
创建二进制信号量:
创建计数型信号量:
删除信号量:
Give和Take:
Give(+1):
Take(-1):
11.信号量和队列的区别
信号量本质就是一种队列,它相比队列而言不具备读写功能,只具备了计数功能,可以看做是一个票数,可实现计数的加或减,同时它会提供了等待链表,就我想要获取信号量,但信号量已经不够的情况下,我可以等待,等待它“发票”,但提供票数的人不需要等待,只需要发或者不发。