前后台系统,RTOS与定时器任务管理系统
前后台系统
在裸机上写程序,通常把程序分为两部分:前台系统和后台系统。
简单的小系统通常是前后台系统,这样的程序包括一个死循环和若干个中断服务程序:应用程序是一个无限循环,循环中调用API函数完成所需的操作,这个大循环就叫做后台系统。中断服务程序用于处理系统的异步事件,也就是前台系统。前台是中断级,后台是任务级。
RTOS
RTOS全称为:Real Time OS,就是实时操作系统,强调的是:实时性。实时操作系统又分为硬实时和软实时。硬实时要求在规定的时间内必须完成操作 ,硬实时系统不允许超时,在软实时里面处理过程超时的后果就没有那么严格。在实时操作系统中,我们可以把要实现的功能划分为多个任务,每个任务负责实现其中的一部分,每个任务都是一个很简单的程序,通常是一个死循环。
RTOS操作系统:UCOS,FreeRTOS,RTX,RT-Thread,DJYOS等。
RTOS操作系统的核心内容在于:实时内核。RTOS的内核负责管理所有的任务,内核决定了运行哪个任务,何时停止当前任务切换到其他任务,这个是内核的多任务管理能力。多任务管理给人的感觉就好像芯片有多个CPU,多任务管理实现了CPU资源的最大化利用,多任务管理有助于实现程序的模块化开发,能够实现复杂的实时应用。
可剥夺内核顾名思义就是可以剥夺其他任务的CPU使用权,它总是运行就绪任务中的优先级最高的那个任务。
定时器管理系统
对于以上两种系统,前后台系统整个程序运行严格遵守先后顺序,对于有实时性要求的任务无法做到周期性运行。RTOS可以完美得做到,但是开发要求有一定知识基础,对RTOS有一定了解。因此第三种发难应运而生:定时器任务管理系统。
定时器任务管理系统由定时器中断提供时钟基础,对每个任务进行定时处理。在大多数情况下,可以做到对单个任务周期性运行处理。对一些有实时性要求但是要求不苛刻的场景还是很方便的。
定时器任务管理系统原理
定时器任务管理系统,通过定时器定时提供一个时间基准。例如定时器1ms中断一次,在中断处理函数中将时间变量累加,就可以得到整个系统运行时间,当时间变量累加到n,就将对应的标志位置1,认为n ms到了,系统检测到标志位为1就执行对应的任务。
时间变量结构体
typedef struct
{
u8 uCount10ms;
u8 uCount50ms;
u8 uCount100ms;
u8 uCount1000ms;
u8 uFlag5ms;
u8 uFlag10ms;
u8 uFlag50ms;
u8 uFlag100ms;
u8 uFlag1000ms;
} TimerDef;
定时器时间基准
定时器初始化函数:
//定时器初始化
//0.5ms进入中断一次
void TimerInit()
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
//enable Time2 gloabal Interrupt
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 6;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_DeInit(TIM2);
TIM_TimeBaseInitStruct.TIM_Period = 719; //100KHz //定时器计数频率=系统时钟/分频系数
TIM_TimeBaseInitStruct.TIM_Prescaler = 49; //定时器自动重装载值 //2K // //0.5ms
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
}
定时器中断处理:
void TIM2_IRQHandler(void) //0.5ms
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//判断中断
{
TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);//清除中断标志位
Timer.uCount ++; //时间累积变量 0.5ms累加一次
if(Update_tim > 0)Update_tim--;//定时器延时,0.5ms减少1,为零时定时到达
}
}
时间管理
void updateTimerTask(TimerDef *Timer)
{
if (Timer->uCount >= 10) //0.5*10=5 ms到达
{
Timer->uCount = 0;
Timer->uFlag5ms = 1; //5 ms标志位置1
Timer->uCount10ms ++;
Timer->uCount50ms ++;
Timer->uCount100ms ++;
Timer->uCount1000ms ++;
}
if (Timer->uCount10ms >= 2)//10ms到达
{
Timer->uCount10ms = 0;
Timer->uFlag10ms = 1;
}
if (Timer->uCount50ms >= 10)//50ms到达
{
Timer->uCount50ms = 0;
Timer->uFlag50ms = 1;
}
if (Timer->uCount100ms >= 20)//100ms到达
{
Timer->uCount100ms = 0;
Timer->uFlag100ms = 1;
}
if (Timer->uCount1000ms >= 200)//1000ms到达
{
Timer->uCount1000ms = 0;
Timer->uFlag1000ms = 1;
}
}
时间任务管理
//大循环任务
void EverWhile_tasks()
{
}
//5ms 任务
void Per_5ms_tasks()
{
if(Timer.uFlag5ms != 1)//5ms未到达
return;//退出函数
task1();//用户函数
Timer.uFlag5ms = 0;//清空5ms标志位
}
//10ms 任务
void Per_10ms_tasks()
{
if(Timer.uFlag10ms != 1)
return;
task2();//用户函数
DIU.Timer.uFlag10ms = 0;
}
//50ms 任务
void Per_50ms_tasks()
{
if(Timer.uFlag50ms != 1)
return;
task3();//用户函数
Timer.uFlag50ms = 0;
}
//100ms 任务
void Per_100ms_tasks()
{
if(DIU.Timer.uFlag100ms != 1)
return;
task4();//用户函数
DIU.Timer.uFlag100ms = 0;// //
}
//1s 任务
void Per_1s_tasks()
{
if(DIU.Timer.uFlag1000ms != 1)
return;
task5();//用户函数
DIU.Timer.uFlag1000ms = 0;
}
上一篇:STM32学习记录之看门狗
下一篇:STM32串口接收数据卡死问题解决办法
设计资源 培训 开发板 精华推荐
- AS1115-QF_DK_ST B,AS1115 64-LED 演示板,带按键扫描的 I2C 接口 LED 驱动器
- 使用 MaxLinear, Inc 的 SP6656 的参考设计
- 使用 Analog Devices 的 LT124XMJ8 的参考设计
- LTC3265MPDHC 低噪声 +7V/-2V 电源的典型应用电路来自一个单端 5V 输入电源(频率 = 200kHz)
- arduino uno二轴激光打印拓展板
- BP5221A慢启动降压DC/DC转换器典型应用电路
- 使用 Analog Devices 的 AD9981KSTZ 的参考设计
- HEGduino:测量实时脑血氧水平(全开源)
- 3W, 一个 LED 手电筒通用 LED 驱动器
- LTM8031EV 演示板、超低 EMI 36V、1A 模块稳压器