本文包含原理图、PCB、源代码、封装库、中英文PDF等资源
您需要 登录 才可以下载或查看,没有账号?注册会员
×
摘 要: 介绍了实时操作系统(SAFERTOS)的特点,并将其与μC/OS-II进行比较。以SAFERTOS的队列机制为基础,实现了邮箱和信号量机制。最后介绍了SAFERTOS在新型智能负荷监测仪中的应用。
关键词: SAFERTOS;Cortex-M3;μC/OS-II;负荷检测仪
1 SAFERTOS简介
SAFERTOS是近年来欧美极为流行的实时操作系统,本文设计的新型智能负荷检测仪中已将其内嵌于主控芯片LM3S9B96中免费使用。SAFERTOS是从一款开源实时操作系统FREERTOS演化而来的,并且在安全性方面做了很多优化。最重要的是,SAFERTOS通过了欧洲的一个安全认证,使其能够用于医疗、工业等高安全系数领域。
实时系统的正确性不仅依赖于系统计算的逻辑结果,还依赖于产生这些结果的时间。因此,实时操作系统的调度机制和通信机制对于整个系统来说都是至关重要的[1]。SAFERTOS如大多数实时操作系统一样支持任务调度、中断管理、消息队列等功能,而且内核本身精简安全,是本应用的理想选择。
1.1 任务调度
SAFERTOS任务有运行、阻塞、挂起和就绪4个状态,被划分为11(10~0)个优先级,其中等级10优先级最高。SAFERTOS的状态转换如图1所示。任务被创建后处于就绪状态,一旦调度器被开启,系统就会根据调度算法,找出投入运行的就绪任务,使该任务获得CPU和硬件资源后即开始运行。运行中的任务可能会由于等待某个事件而被阻塞一段时间,或者被一个例程挂起而由另一个例程恢复,此时调度器会重新进行调度[2]。
SAFERTOS采用抢占式和合作式任务调度,即基于优先级的抢占式调度与时间轮转调度相结合的算法。SAFERTOS确保了CPU总是被具有最高优先级的就绪任务所控制,当系统中出现两个或两个以上就绪任务拥有相同的当前最高优先级时,调度器会使用时间片轮转算法,将CPU时间平均分配给这些任务。系统至少应该有一个任务处于就绪状态,因此优先级最低的空闲任务不会被阻塞或挂起。
1.2 任务间通信机制
多任务多个中断处理过程有机地构成了嵌入式实时多任务应用程序,它们之间相互竞争CPU、共享内存和硬件等资源。任务间通信机制协调彼此运行的步调、彼此间传递的数据或信息,保证协同运行的各个任务具有正确的执行次序,协同完成某项工作。SAFERTOS提供的通信机制有临界区和消息队列两种。
SAFERTOS采用传统的实现临界区的方法,即关中断进入临界区,开中断出临界区。SAFERTOS提供了队列,用于任务间、任务与中断服务程序之间安全地传递数据。队列的基本元素为项目(item),每个队列可以包含0个或多个项目,每个项目占内存空间的大小以及队列包含项目的个数在队列创建时可任意配置。基于这种结构,队列使用灵活,以此为基础可以开发出实时操作系统常见的邮箱和信号量。
2 SAFERTOS与μC/OS-II的比较
μC/OS-II(Micro-Control Operation System Version2)是一款源代码开放的实时操作系统内核,由LABROSSE J J开发。μC/OS-II最大的特点是源代码开放,移植性强。μC/OS-II是完全抢占式的内核,它总是运行优先级最高的就绪任务,并且提供了许多系统调用,如邮箱、信号量、动态内存分配、时间管理等[3]。μC/OS-II与SAFERTOS的功能比较如表1所示。
从表1可以看出,SAFERTOS与μC/OS-II的功能差异不大,两者皆支持中断嵌套,有类似的任务间通信机制。受任务位图的影响,μC/OS-II能建立的任务数目不超过56个,而SAFERTOS能够创建的任务数目只受内存大小限制。SAFERTOS支持同等优先级的轮转调度,这比μC/OS-II能更好地支持多任务后台计算。出于安全考虑,SAFERTOS不支持动态内存分配。
3 邮箱与信号量
3.1 邮箱
邮箱用于任务、任务与中断服务程序之间传递结构化数据或事件标志。邮箱实质上是消息的中转站,一个任务或一个中断服务程序通过内核服务可以把一个消息(即一段结构化数据) 放到邮箱里去。每个邮箱有相应的正在等待消息的任务列表,要得到消息的任务会因为邮箱是空的而被挂起,直到收到消息[4]。
虽然SAFERTOS没有直接提供邮箱机制,仅仅提供了一种配置灵活的队列,但从本质上, SAFERTOS的队列是一种未结构化的邮箱。而通过结构化队列项目的内存缓存区,可以实现收发特定数据结构的邮箱机制。创建邮箱函数为mbox_create,其中参数mptr为邮箱内存缓存区首地址,msgcnt为队列项目个数,msgsz为每个项目的大小,mboxptr为邮箱的句柄(邮箱的标志,供收发函数使用),则函数定义如下:
#define MBOX xQueueHandle
void mbox_create(void *mptr, UINT16 msgcnt, UINT16 msgsz,
MBOX *mboxptr)
{
UINT16 mboxbuflen;
portCHAR *mboxbuf = (portCHAR *)mptr;
mboxbuflen = msgcnt*msgsz+portQUEUE_OVERHEAD_
BYTES;
xQueueCreate( mboxbuf, mboxbuflen, msgcnt, msgsz, mboxptr);
}
邮箱接收函数为mbox_get,发送函数为mbox_put。其中:参数mptr为邮箱句柄,msg为收发的结构化数据的地址,接收函数中的waitopt为获取消息失败,任务等待时间。函数定义如下:
UINT16 mbox_put(MBOX mptr, UINT16 *msg)
{
return xQueueSend( mptr,msg, 2);
}
UINT16 mbox_get(MBOX mptr, UINT16 *msg, SINT16 waitopt)
{
if( xQueueReceive(mptr, msg, waitopt )!= pdPASS)
return FAILURE;
return SUCCESS;
}
3.2 信号量
某些软硬件资源(例如Flash、串行总线、数据缓冲区等)会被不同任务同时访问,使用信号量可以实现资源的互斥访问。每种资源用一个信号量描述,当任务访问该资源时,必须先成功获取该信号量。
信号量由计数器和等待队列组成,计数器描述可用信号量的个数,等待队列用来挂起等待获取信号量的任务。释放信号量(V操作)计数器加1;获取信号量(P操作)计数器减1。如果计数器值小于0,则获取失败,请求获取信号量的任务被阻塞固定长时间,等待其他任务释放信号量。从本质上来看,信号量是项目长度为零的队列。定义的信号量数据结构如下:
typedef struct semaphore SEMAPHORE;
struct semaphore{
long ref; //计数值
xQueueHandle mbx; //队列句柄
signed char mbxbuf[portQUEUE_OVERHEAD_BYTES]; };
创建信号量函数为SemaphoreCreate,需要的参数是信号量结构指针和计数器初始值。函数定义如下:
void SemaphoreCreate(SEMAPHORE *smptr, long ini)
{
smptr->ref = ini;
xQueueCreate(smptr->mbxbuf, sizeof(smptr->mbxbuf), 1,
0, &smptr->mbx );
}
获取信号量函数为sem_p,释放信号量函数为sem_v,其中,参数s为信号量指针,waitopt为获取失败等待时间。则函数定义如下:
UINT16 sem_p(SEMAPHORE *s, UINT16 waitopt)
{
taskENTER_CRITICAL();//进入临界区
if(--s->ref < 0){
taskEXIT_CRITICAL(); //退出临界区
if (xQueueReceive( s->mbx, NULL, waitopt ) ==
pdPASS)
return SUCCESS;
taskEXIT_CRITICAL();
return FAILURE;
}
void sem_v(SEMAPHORE *s)
{
taskENTER_CRITICAL();
if(s->ref++ < 0)
{
taskEXIT_CRITICAL();
xQueueSend( s->mbx, NULL, 0 );
}
taskEXIT_CRITICAL();
}
4 SAFERTOS应用
4.1 智能负荷监测仪
负荷检测仪是一种广泛应用于配电变压器运行状态监测、运行管理、电能计量、无功补偿和远程通信的智能监测控制装置[5]。其系统硬件结构图如图2所示。检测仪采用LM3S9B96芯片作为主控芯片,控制整个系统运行;高速高精度电能计量专用芯片ADE7878采集计算电网参数;大容量片外Flash芯片存储突发事件与电网历史数据;GPRS通信模块MC52i用于远程通信;高精度时钟芯片FM33256用于精确计时。
|