1.前言
本文参考自网上各大神的代码,在此基础上做修改,写了一份更适合本人开发的裸机操作系统代码。
在此特别感谢“无际单片机”,他的代码框架讲解真的很不错。
后面还有很多地方需要完善,读者如有想法可以一起探讨。
有纰漏请指出,转载请说明。
学习交流请发邮件 1280253714@qq.com
2.原理讲解
我理解的操作系统(OS),就是在系统资源有限的情况下,通过OS进行调度处理,例如对进程、设备、文件、存储资源进行管理。
为什么我想写这个简单操作系统呢?因为个人裸机开发不需要用到FreeRTOS、RT-Thread等来开发,一来是简单任务简单处理,二是当遇到bug时不至于无从下手。
这里的操作系统,其实是放在定时器里(周期1毫秒),每个任务的计数值大于任务周期时,任务将被调度,然后在主循环里进行任务的执行。
外部的命令/数据进入单片机,还是用中断/DMA来处理,可以保证一定能接收。同时,为了保证命令/数据一定能被执行,需要写一个消息队列(后面有空再写一下,给自己挖坑),当系统空闲时对命令/数据进行处理。
这里的话,只要其他函数不进行阻塞(像Delay函数),基本上能保持任务的实时进行。
任务初始化时处于睡眠状态,任务创建时处于就绪状态,当定时时间一到,任务处于运行态,然后在主函数进行轮询处理。
系统可以随时让任务暂停(睡眠)、启动(就绪)。
在下面的演示中,我创建了两个任务,一是LED灯闪烁,二是串口不断发心跳包。
在testPro里,随时可以让任务启停。
3.os.h
#ifndef _OS_H
#define _OS_H
#include "includes.h"
typedef enum {
Task1,
Task2,
TaskNum,
}OS_Task_S;
typedef enum {
OS_Sleep,
OS_Ready,
OS_Run,
}OS_Task_State_S;
typedef struct {
void (* task)(void); //任务函数指针
OS_Task_State_S state; //任务运行状态
u32 u32Period; //任务周期
u32 u32Tick; //任务计时器,计时时间超过任务周期时,任务将被执行
u32 u32ExeTimes; //任务被执行次数
} OS_S;
void OS_TaskInit(void);
void OS_TaskCreat(u8 ID, void (* pFunCallBack)(void), u32 period);
void OS_TaskInterruptHandler(void);
void OS_TaskRun(void);
void OS_TaskSleep(u8 ID);
void OS_TaskReady(u8 ID);
void OS_TaskDestroy(u8 ID);
#endif
4.os.h
#include "includes.h"
__IO OS_S OS_Task[TaskNum];
/********************************************
* @函数名 OS_TaskInit
* @描述 系统任务初始化
* @参数 无
* @返回值 无
* @注意 该函数放在main函数里while(1)前
********************************************/
void OS_TaskInit(void)
{
for (u8 i=0; i<TaskNum; i++)
{
OS_Task[i].task = 0;
OS_Task[i].state = OS_Sleep;
OS_Task[i].u32Period = 0;
OS_Task[i].u32Tick = 0;
OS_Task[i].u32ExeTimes = 0;
}
}
/********************************************
* @函数名 OS_TaskCreat
* @描述 创建一个任务
* @参数
ID 任务ID
(* pFunCallBack)(void) 任务的回调函数
period 任务周期
* @返回值 无
* @注意 无
********************************************/
void OS_TaskCreat(u8 ID, void (* pFunCallBack)(void), u32 period)
{
if (!OS_Task[ID].task) //任务为空
{
OS_Task[ID].task = pFunCallBack;
OS_Task[ID].u32Period = period;
OS_Task[ID].state = OS_Ready;
}
}
/********************************************
* @函数名 OS_TaskInit
* @描述 系统任务调度函数
* @参数 无
* @返回值 无
* @注意 为了保证任务的实时性,
该中断处理函数必须放在定时器或者系统时钟中断里
********************************************/
void OS_TaskInterruptHandler(void)
{
for (u8 i=0; i<TaskNum; i++)
{
if (OS_Task[i].task)
{
if(OS_Task[i].state != OS_Sleep)
{
OS_Task[i].u32Tick++;
if (OS_Task[i].u32Tick>=OS_Task[i].u32Period)
{
OS_Task[i].u32Tick = 0;
OS_Task[i].state = OS_Run;
}
}
}
}
}
/********************************************
* @函数名 OS_TaskRun
* @描述 当任务时间到,任务状态在定时中断处被置为运行态时,执行任务
* @参数 无
* @返回值 无
* @注意 该函数放置于主函数while(1)里面
********************************************/
void OS_TaskRun(void)
{
for (u8 i=0; i<TaskNum; i++)
{
if (OS_Task[i].state == OS_Run)
{
OS_Task[i].state = OS_Ready;
OS_Task[i].u32Tick = 0;
(* OS_Task[i].task)();
OS_Task[i].u32ExeTimes++;
}
}
}
/********************************************
* @函数名 OS_TaskSleep
* @描述 让任务处于休眠态
* @参数 ID 任务的ID号
* @返回值 无
* @注意 无
********************************************/
void OS_TaskSleep(u8 ID)
{
if (OS_Task[ID].task)
{
OS_Task[ID].state = OS_Sleep;
OS_Task[ID].u32Tick = 0;
}
}
/********************************************
* @函数名 OS_TaskReady
* @描述 让任务处于就绪态
* @参数 ID 任务的ID号
* @返回值 无
* @注意 无
********************************************/
void OS_TaskReady(u8 ID)
{
if (OS_Task[ID].task)
{
OS_Task[ID].state = OS_Ready;
OS_Task[ID].u32Tick = 0;
}
}
/********************************************
* @函数名 OS_TaskDestroy
* @描述 销毁任务
* @参数 ID 任务的ID号
* @返回值 无
* @注意 需再次创建任务才能让任务执行
********************************************/
void OS_TaskDestroy(u8 ID)
{
if (OS_Task[ID].task)
{
OS_Task[ID].task = 0;
}
}
/********************************************
* @函数名 TIM4_IRQHandler
* @描述 定时器每隔1ms进一次中断
* @参数 无
* @返回值 无
* @注意 无
********************************************/
void TIM4_IRQHandler(void)
{
if ( TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET )
{
OS_TaskInterruptHandler();
TIM_ClearITPendingBit(TIM4 , TIM_FLAG_Update);
}
}
5.main.c
#include "includes.h"
u8 TestTemp = 0;
static void testPro(void);
int main(void)
{
TimerOsInit();
LED_Init();
UartInit();
OS_TaskInit();
OS_TaskCreat(Task1, LED1_Toggle, 200);
OS_TaskCreat(Task2, UartSendHeartBeat, 500);
while (1){
UartLoopTask();
testPro();
ledLoopTask();
OS_TaskRun();
}
}
static void testPro(void)
{
if(!TestTemp){return;}
switch(TestTemp){
case 1:
UaetSendHeartBeat();
break;
case 2:
LED1_Toggle();
break;
case 3:
OS_TaskSleep(Task1);
break;
case 4:
OS_TaskReady(Task1);
break;
}
TestTemp = 0;
}
6.演示视频
简单的操作系统演示