uCOS为可剥性型实时操作系统,顾名思义可剥夺型意为:
① 在系统的运行过程中高优先级任务可剥夺低优先级任务的CPU使用权。
② 低优先级任务不可打断高优先级任务。
在uCOS操作系统中,多个任务的优先级不同,而在系统的运行过程中,uCOS总是在任务就绪表里面寻找最高优先级的任务来执行
#define OS_TICKS_PER_SEC 200u /* 在一秒内设置节拍数,每次间隔5ms产生一次节拍中断 */
*************************************************
(正点原子UCOSII例程)
调用该delay_init()函数后,程序每隔5ms会产生一次中断,如下
//systick中断服务函数,使用ucos时用到
void SysTick_Handler(void)
{
if(delay_osrunning==1) //OS开始跑了,才执行正常的调度处理
{
OSIntEnter(); //进入中断
OSTimeTick(); //调用ucos的时钟服务程序
OSIntExit(); //触发任务切换软中断
}
}
OSIntExit(); 这个函数中会发生任务调度,事实上,为了保证系统的实时性,实时操作系统时钟中断里面和任何的中断退出时都会产生调度。(多重中断嵌套,必须是完全退出时)
void delay_us(u32 nus) //这个延时不会被节拍中断打断
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD的值
ticks=nus*fac_us; //需要的节拍数
tcnt=0;
OSSchedLock(); //阻止OS调度,防止打断us延时
told=SysTick->VAL; //刚进入时的计数器值
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{ //这里注意一下SYSTICK是一个递减的计数器就可以了.
if(tnow<told)tcnt+=told-tnow;
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.
}
};
OSSchedUnlock(); //恢复OS调度
}
OSSchedLock(); 只是阻止OS任务调度,并没有关闭系统每5ms产生的中断,所以在while循环中仍然可以进入中断,但不会发生任务调度,确保delay_us延时的准确性,OSSchedLock()和OSSchedUnlock()函数必须成对出现。
阻止OS任务调度实现方法:对 OSLockNesting++(多任务锁嵌套级别)
void OSIntExit (void)
{
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
if (OSRunning == OS_TRUE)
{
OS_ENTER_CRITICAL(); //关闭中断
if (OSIntNesting > 0u)
{
OSIntNesting--;
}
if (OSIntNesting == 0u) /*中断嵌套级别 */
{
if (OSLockNesting == 0u) /*多任务锁嵌套级别 */
{
OS_SchedNew(); //任务调度
......
}
}
OS_EXIT_CRITICAL(); //打开中断
}
}
UCOS在什么时候发生任务调度及任务调度时间点
1.使用UCOS延时函数OSTimedly()或者OSTimeDlyHMSM()。
2.释放信号量或者发送消息。
3.任务等待的事情还没有发生,如等待信号量,消息队列等。
4.任务取消等待。
5.创建任务,删除任务。
6.删除一个内核对象。
7.任务改变自身的优先级或者其他任务的优先级。
8.调用OSTaskSuspend()将自己挂起。
9.任务解除被挂起的任务。
10.退出所有的嵌套中断,中断嵌套级别 OSIntNesting=0。
11.任务锁嵌套OSLockNesting=0。
*************************************************
使用UCOS读取DS18B20时,时序很重要,避免发生任务调度,破坏时序,虽然使用了delay_us(),但是TEMP_DATA_OUT=1; … 等语句仍然可以被节拍中断打断,产生任务调度,可以使用OSMutexPend(mutex,0,&err)提高任务优先级,防止任务调度。
uint8_t DS18_Init()
{
uint8_t flag=0;
OSMutexPend(mutex,0,&err); //提高优先级
TEMP_IO_OUT(); //输出方向
TEMP_DATA_OUT=1;
delay_us(2);
TEMP_DATA_OUT=0;
delay_us(500);
TEMP_DATA_OUT=1;
TEMP_IO_IN(); //输入方向
delay_us(50);
if(TEMP_DATA_IN==0) flag=1; //ds18b20拉低总线,告诉主机本器件已做好准备 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)==0
else flag=0;
delay_us(480);
TEMP_DATA_OUT=1;
OSMutexPost(mutex); //恢复优先级
return flag;
}