前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >嵌入式实时操作系统UCOSII[通俗易懂]

嵌入式实时操作系统UCOSII[通俗易懂]

作者头像
全栈程序员站长
发布2022-08-19 19:46:18
3.6K0
发布2022-08-19 19:46:18
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

何谓操作系统

1.什么是操作系统? 操作系统是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。介于APP和硬件之间。

2. 为什么要用操作系统? 1)相比裸机,可以实现更加复杂的功能。 2)屏蔽硬件。使得上层应用APP的移植性更好。

常见操作系统

  1. 常见操作系统 安卓、IOS、Windows、Linux、塞班、Vxworks、wince、RTT、UCOS、FreeRTOS等。
  2. 常见操作系统分类
  3. 实时操作系统(RTOS) 每一个任务的执行时间是不固定的,任务与任务之间的切换时以优先级为调度原则,优先级高的任务可以抢占优先级低的任务的CPU使用使用权,所以也叫抢占式内核。响应速度快。 RTT、UCOS、FreeRTOS
  4. 分时操作系统 系统分配若干个时间片给每个任务,当前任务执行完自己的时间后会自动交出CPU使用权给下一个任务。 时间片:每个时间片都是一样的,系统会分配若干个时间片给每个任务 举例:1S平均分成1000份,每一份就是一个时间片–1ms。 给任务A分配100份,给任务B分配200份,给任务C分配300份… Windows95/98/2000、LINUX2.6内核之前
  5. 半分时半实时操作系统 有一些任务是实时的,有些任务是分时的。 Windows7/8/10、LINUX2.6内核之后
UCOS操作系统概述
UCOS操作系统的调度原则

实时操作系统:以任务优先级作为调度原则 分时操作系统:以时间片作为调度原则

UCOSII是实时操作系统,所以它是以任务优先级作为调度原则。

UCOS操作系统的程序结构

裸机:有且只能有一个主函数,并且在主函数必须要有死循环(while(1)),把要实现的功能在主函数里实现。

上了UCOSII操作系统后:有且只能有一个主函数,在主函数中可以不需要死循环(while(1)),在工程中有多个任务,每个任务都必须有个死循环,把要实现的功能写进各个任务中。

任务结构:任务控制块、任务函数地址、任务栈、任务优先级、任务状态

任务控制块:当成功创建了一个任务之后,系统就会自动分配一段内存空间,这段内存空间就是所谓任务控制块,存放这该任务的相关信息,包括任务函数地址、任务栈、任务优先级、任务状态。

任务函数:可以看成是一个功能函数,把要该任务实现的功能写进该函数中,系统通过该任务函数名(地址)访问该任务函数。 任务栈:当任务与任务之间发生切换时,保存当前任务环境(寄存器配置,变量等)和恢复任务环境。 任务优先级:每个任务都有唯一的优先级,是系统调度和任务切换的依据。 任务状态:休眠/停止、等待/挂起、就绪、运行、中断

UCOS操作系统的系统调度和任务切换

系统调度:当发生系统调度的时候,系统就会查询当前所有处于就绪状态中的任务的优先级,把CPU的使用权给到优先级最高的那个任务(就绪)。 处理就绪状态中任务的优先级问题。 任务切换:CPU从一个任务切换到另一个任务。

什么时候发生系统调度? 满足两个条件中的一个即可发生。

  1. 时基的时间到了。时基又叫Tick,Tick一般情况下都是由系统滴答定时器提供,这个Tick时间长短可以由开发人员自己设定。
  2. 执行到某些API函数( Osched() )

发生系统调度一定会产生任务切换吗? 发生系统调度不一定会产生任务切换

举例: 任务A优先级为10–挂起 任务B优先级为13–运行 任务C优先级为18–就绪 任务D优先级为20–就绪 当前任务B正在运行,突然Tick到了,就会发生一次系统调度,当前任务B从运行态转为就绪态,然后目前一定有任务B,任务C和任务D处于就绪态,并且任务B优先级最高,那么CPU的使用权仍然会给到任务B。 所以,这种情况虽然发生了系统调度,但是并没有产生任务切换。

任务间的切换过程是怎样的?

A—>B—>A

  1. 任务A入栈
  2. 任务B把内容从栈中弹出(出栈)
  3. CPU切换到任务B
  4. 任务B入栈
  5. 任务A出栈
  6. CPU切换到任务A
UCOS操作系统的任务中断

上了操作系统后,中断的写法跟以前裸机基本没有变化。 同样需要设置中断分组,中断优先级,使用中断等(配置NVIC)–没有变化 中断服务函数名也没有没变化 编写中断服务函数的内容需要增加两个UCOSII的API函数。—变化

在中断服务函数里的第一个行,必须加入“OSIntEnter()”,表示当前操作系统进入了中断服务函数 在中断服务函数里的最后一行,必须加入“OSIntExit()”,表示当前操作系统要退出中断服务函数

裸机:当发生了中断事件,会在当前运行的地方设定一个断点,执行完中断服务函数后,CPU会回到断点中继续执行。

上了UCOSII系统后:当发生了中断事件,同样会在当前运行的地方设定一个断点,执行完中断服务函数后,不一定会回到断点处。因为出中断前会执行“OSIntExit()”,执行这个API函数会产生一次系统调度,一旦发生了任务切换,CPU就不会回到断点处。

UCOS操作系统的任务状态

任务状态:休眠/停止、等待/挂起、就绪、运行、中断

创建UCOS版本工程

当前用到的是UCOSII版本。 UCOSII源码链接:www.micrium.com/downloadcenter/

选择对应的处理器

UCOSII文件说明

核心文件:

创建工程

1)新建一个空白文件夹 2)在上面创建的文件夹里再新建名为“CMSIS”、“USER”和“TASK”两个文件夹 3)在“USER”里再新建名为“inc”和“src”两个文件夹 4)在“TASK”里再新建名为“inc”和“src”两个文件夹 5)把芯片相关支持文件复制到“CMSIS” 6)把“UCOSII”整个文件夹复制到与“CMSIS”同目录下 7)打开KEIL软件创建新工程 8)创建虚拟工程树(在原来基础上增加“UCOSII_CONFIG”、“UCOSII_CORE”、“UCOSII_PORT”) 9)配置工程属性 10)设定头文件路径(在原来基础上增加“./TASK/inc”、“./UCOSII/CONFIG”、“./UCOSII/CORE”、 “./UCOSII/PORT”) 11)新建文件并添加到工程中

系统滴答定时器初始化
代码语言:javascript
复制
//函数功能:系统滴答中断
//参数说明:待延时的毫秒
//返回值:无
//注意事项:
//时间:2019.6

void Systick_Interrupt(u32 nms)
{
	SysTick->CTRL &=~(0x01<<2);//	选择时钟源(21M)
	SysTick->LOAD =21*nms*1000;//	设置重载值(LOAD)
  SysTick->VAL=0;//	写VAL(清除VAL,重装载,清标志)
	//使能中断(设置NVIC优先级,模块级中断使能)
	//设置优先级分组
	NVIC_SetPriority(SysTick_IRQn,NVIC_EncodePriority (7-2, 2,2));
	//NVIC中断使能---系统滴答中断NVIC是必须响应,不需要再使能
	//NVIC_EnableIRQ(SysTick_IRQn);
	SysTick->CTRL |=0x01<<1;
	
	SysTick->CTRL |=0x01<<0;//	开启(使能)定时器
}
void SysTick_Handler(void)
{
	OSIntEnter();//告诉操作系统当前进入了中断服务函数
	OSTimeTick();
	OSIntExit();//告诉操作系统已经处理完了中断服务函数
}
主函数的编写
代码语言:javascript
复制
nt main(void)
{
	//各种模块的初始化
  LED_Init( );//LED初始化
	Key_Init( );
	Uart1_Init(84,115200);
	Systick_Interrupt(1000/OS_TICKS_PER_SEC);//TICK=5ms
	
	
	
	OSInit();//初始化 UCOS-II 内核
	
	//至少要创建一个任务
	
	
	GPIO_ResetBits(GPIOF, GPIO_Pin_6);
	
	OSStart();//开启操作系统
						//一旦开启了操作系统,下面的代码就不会再执行了
	
	GPIO_SetBits(GPIOF, GPIO_Pin_6);
	GPIO_ResetBits(GPIOF, GPIO_Pin_9);
	
	while(1)
	{
			
	}
	
}
创建任务

调用 OSTaskCreate 创建一个任务,ucos会给这个任务分配一个任务控制块,任务控制块中记录了任务的任务函数地址,任务栈地址,任务的优先级,任务的状态。 如果成功创建一个任务,这个任务就处于了就绪状态。 不能在中断中创建任务,每个任务的优先级唯一,如果先后创建的两个任务的优先级一样,后一个任务创建会失败。任务的优先级不能低于最低优先级。 函数原型: INT8U OSTaskCreate ( void (* task) (void *pd), void *pdata, OS_STK *ptos, INT8U prio )

参数说明: 1)task:函数指针,是“指向一个返回值类型为void,有一个形参为 void* 指针的函数的”指针。—–其实是就指向任务函数。 2)pdata:void* 指针,任务函数被调用需要传递实参,所传入参数就是这个参数,如果任务函数不需要使用这个参数,可以传递 0、NULL 或 (void*)0 。 3)ptos:任务栈(用户定义一个数组)顶部分,对于栈是递减方式,就是传递数组的最后一个元素地址,如果是递增,就是第0个元素地址。(ARM的CPU一般默认是递减的栈,所以看到的都是传入 最后一个 元素地址; 51单片的栈是递增的,所以51上使用ucOS传入的是第0个元素地址)。(一般不会在51上运行) OS_STK 类型:实际上 unsigned int (对于32位平台),平台不同,长度不同,所以使用时候一般是使用 OS_STK 定义数组。 ptos空间最小不能小于17*4,如果任务函数局部变量比较多,还要更大;如果任务函数用到了浮点运算,一定要把栈设置成8字节对齐,否则出栈异常! 4)prio:任务的优先级。 ucOS2 范围是0~63,实际上是由 os_cfg.h 中宏 OS_LOWEST_PRIO 配置最大值(只能改小,不能改大)。 其中可用的优先级最低2个是内建任务使用,用户不能使用 最低优先级(等于 OS_LOWEST_PRIO):空闲任务 — 当所有用户任务都不运行的时候,CPU在执行空闲任务,通俗说:所有人都不要它时候,给空闲任务收留它。 次低优先级(等于 OS_LOWEST_PRIO -1):统计任务 — 统计CPU利用率。(该任务是可选择的,可裁剪的)。 ucOS 任务优先级不能相同,每个任务优先级都是惟一的。 (经验:建议最高前几个等级不要用,任务间优先级不要连续,考虑程序拓展性)

返回值说明: 1)成功:0,一般不直接使用数字,而使用ucOS提供宏判断执行结果。 OS_ERR_NONE //创建任务成功。

代码语言:javascript
复制
Returns    : OS_ERR_NONE             if the function was successful.
OS_ERR_PRIO_EXIST            if the task priority already exist
*                                      (each task MUST have a unique priority).
*          OS_ERR_PRIO_INVALID     if the priority you specify is higher that the maximum allowed
*                                      (i.e. >= OS_LOWEST_PRIO)
*          OS_ERR_TASK_CREATE_ISR  if you tried to create a task from an ISR.

具体代码请看示例

任务一个任务都必须有主动放弃CPU的动作,否则,比它优先级低的任务用于都得不到CPU。

任务函数: void Start_Task(void *pdata);

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/136141.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月4,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 何谓操作系统
  • 常见操作系统
    • UCOS操作系统概述
      • UCOS操作系统的调度原则
      • UCOS操作系统的程序结构
    • UCOS操作系统的系统调度和任务切换
      • 任务间的切换过程是怎样的?
        • UCOS操作系统的任务中断
          • UCOS操作系统的任务状态
            • 创建UCOS版本工程
          • UCOSII文件说明
            • 创建工程
              • 系统滴答定时器初始化
                • 主函数的编写
              • 创建任务
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档