(学习日记)2024.03.05:UCOSIII第七节:SysTick+任务时间片

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2024.03.05

  • 十六、UCOSIII:介绍SysTick
    • 1、SysTick简介
    • 2、初始化SysTick
    • 3、SysTick中断服务函数
  • 十七、UCOSIII:任务时间片运行
    • 1、对main()函数修改
    • 2、关闭中断函数CPU_IntDis()
    • 3、仿真测试

十六、UCOSIII:介绍SysTick

1、SysTick简介

RTOS需要一个时基来驱动,系统任务调度的频率等于该时基的频率。
通常该时基由一个定时器来提供,也可以从其他周期性的信号源获得。 刚好Cortex-M内核中有一个系统定时器SysTick,它内嵌在NVIC中,是一个24位的递减的计数器,计数器每计数一次的时间为1/SYSCLK。
当重装载数值寄存器的值递减到0的时候,系统定时器就产生一次中断,以此循环往复。

因为SysTick是嵌套在内核中的, 所以使得OS在Cortex-M器件中编写的定时器代码不必修改,使移植工作一下子变得简单很多。
所以SysTick是最适合给操作系统提供时基, 用于维护系统心跳的定时器。

SysTick寄存器汇总如下:

寄存器名称寄存器描述
CTRLSysTick控制及状态寄存器
LOADSysTick重装载数值寄存器
VALSysTick当前数值寄存器

SysTick控制及状态寄存器如下:

位段名称类型复位值描述
16COUNTFLAGR/W0如果在上次读取本寄存器后, SysTick 已经计到了 0,则该位为 1。
2CLKSOURCER/W0时钟源选择位,0=AHB/8,1=处理器时钟AHB
1TICKINTR/W01=SysTick倒数计数到 0时产生 SysTick异常请求,0=数到 0 时无动作。也可以通过读取COUNTFLAG标志位来确定计数器是否递减到0
0ENABLER/W0SysTick 定时器的启用位

SysTick 重装载数值寄存器如下:

位段名称类型复位值描述
23:0RELOADR/W0当倒数计数至零时,将被重装载的值

SysTick当前数值寄存器如下:

位段名称类型复位值描述
23:0CURRENTR/W0读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG 标志

2、初始化SysTick

使用SysTick非常简单,只需一个初始化函数搞定,OS_CPU_SysTickInit函数在os_cpu_c.c中定义

我使用的是野火的教材,SysTick初始化函数野火没有使用μC/OS-III官方的,野火是自己另外编写了一个。
区别是uC/OS-III官方的OS_CPU_SysTickInit函数里面涉及 SysTick寄存器都是重新在cpu.h中定义,
而野火自己编写的则是使用ARMCM3.h(记得在os_cpu_c.c的开头包含ARMCM3.h这个头文件) 这个固件库文件里面定义的寄存器,仅此区别而已。

#include "ARMCM3.h"


#if 0 /* 不用μC/OS-III自带的 */
void  OS_CPU_SysTickInit (CPU_INT32U  cnts)
{
    CPU_INT32U  prio;

    /* 填写 SysTick 的重载计数值 */
    CPU_REG_NVIC_ST_RELOAD = cnts - 1u;

    /* 设置 SysTick 中断优先级 */
    prio  = CPU_REG_NVIC_SHPRI3;
    prio &= DEF_BIT_FIELD(24, 0);
    prio |= DEF_BIT_MASK(OS_CPU_CFG_SYSTICK_PRIO, 24);

    CPU_REG_NVIC_SHPRI3 = prio;

    /* 启用 SysTick 的时钟源和启动计数器 */
    CPU_REG_NVIC_ST_CTRL |= CPU_REG_NVIC_ST_CTRL_CLKSOURCE |
                            CPU_REG_NVIC_ST_CTRL_ENABLE;
    /* 启用 SysTick 的定时中断 */
    CPU_REG_NVIC_ST_CTRL |= CPU_REG_NVIC_ST_CTRL_TICKINT;
}

#else /* 直接使用头文件ARMCM3.h里面现有的寄存器定义和函数来实现 */
void  OS_CPU_SysTickInit (CPU_INT32U  ms)
{
    /* 设置重装载寄存器的值 */
    SysTick->LOAD  = ms * SystemCoreClock / 1000 - 1;

    /* 配置中断优先级为最低 */
    NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);

    /* 复位当前计数器的值 */
    SysTick->VAL   = 0;

    /* 选择时钟源、启用中断、启用计数器 */
    SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                    SysTick_CTRL_TICKINT_Msk   |
                    SysTick_CTRL_ENABLE_Msk;
}
#endif
  • SysTick->LOAD = ms * SystemCoreClock / 1000 - 1;
    配置重装载寄存器的值,我们配合函数形参ms来配置,如果需要配置为10ms产生一次中断,形参设置为10即可。

  • NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
    配置SysTick的优先级,这里配置为15,即最低。

3、SysTick中断服务函数

SysTick中断服务函数也是在os_cpu_c.c中定义

/* SysTick 中断服务函数 */
void SysTick_Handler(void)
{
    OSTimeTick();
}

SysTick中断服务函数很简单,里面仅调用了函数OSTimeTick()。
OSTimeTick()是与时间相关的函数, 在os_time.c文件中定义。

#include "os.h"

void  OSTimeTick (void)
{
	/* 任务调度 */
	OSSched();
}

OSTimeTick()很简单,里面仅调用了函数OSSched,OSSched函数暂时没有修改,还是手动切换任务
在这里插入图片描述

十七、UCOSIII:任务时间片运行

1、对main()函数修改

main()函数与之前区别不大

  1. 加入了SysTick相关的内容
    在这里插入图片描述
  2. 注释掉任务里的OSSched()函数
    在这里插入图片描述
/*
************************************************************************************************************************
*                                                 包含的头文件
************************************************************************************************************************
*/
#include "os.h"
#include "ARMCM3.h"

/*
************************************************************************************************************************
*                                                   宏定义
************************************************************************************************************************
*/


/*
************************************************************************************************************************
*                                                  全局变量
************************************************************************************************************************
*/

uint32_t flag1;
uint32_t flag2;

/*
************************************************************************************************************************
*                                                  TCB & STACK & 任务声明
************************************************************************************************************************
*/
#define  TASK1_STK_SIZE       20
#define  TASK2_STK_SIZE       20

static   CPU_STK   Task1Stk[TASK1_STK_SIZE];
static   CPU_STK   Task2Stk[TASK2_STK_SIZE];

static   OS_TCB    Task1TCB;
static   OS_TCB    Task2TCB;

void     Task1( void *p_arg );
void     Task2( void *p_arg );

/*
************************************************************************************************************************
*                                                  函数声明
************************************************************************************************************************
*/
void delay(uint32_t count);

/*
************************************************************************************************************************
*                                                    main函数
************************************************************************************************************************
*/
/*
* 注意事项:1、该工程使用软件仿真,debug需选择 Ude Simulator
*           2、在Target选项卡里面把晶振Xtal(Mhz)的值改为25,默认是12,
*              改成25是为了跟system_ARMCM3.c中定义的__SYSTEM_CLOCK相同,确保仿真的时候时钟一致
*/
int main(void)
{	
	OS_ERR err;
	
	/* 关闭中断 */
    CPU_IntDis();

  /* 配置SysTick 10ms 中断一次 */
  OS_CPU_SysTickInit(10);
	
	/* 初始化相关的全局变量 */
	OSInit(&err);
	
	/* 创建任务 */
	OSTaskCreate ((OS_TCB*)      &Task1TCB, 
	              (OS_TASK_PTR ) Task1, 
	              (void *)       0,
	              (CPU_STK*)     &Task1Stk[0],
	              (CPU_STK_SIZE) TASK1_STK_SIZE,
	              (OS_ERR *)     &err);

	OSTaskCreate ((OS_TCB*)      &Task2TCB, 
	              (OS_TASK_PTR ) Task2, 
	              (void *)       0,
	              (CPU_STK*)     &Task2Stk[0],
	              (CPU_STK_SIZE) TASK2_STK_SIZE,
	              (OS_ERR *)     &err);
				  
	/* 将任务加入到就绪列表 */
	OSRdyList[0].HeadPtr = &Task1TCB;
	OSRdyList[1].HeadPtr = &Task2TCB;
	
	/* 启动OS,将不再返回 */				
	OSStart(&err);
}

/*
************************************************************************************************************************
*                                                    函数实现
************************************************************************************************************************
*/
/* 软件延时 */
void delay (volatile uint32_t count)
{
	for(; count!=0; count--);
}



/* 任务1 */
void Task1( void *p_arg )
{
	for( ;; )
	{
		flag1 = 1;
		delay( 100 );		
		flag1 = 0;
		delay( 100 );
		
		/* 任务切换,这里是手动切换 */		
		//OSSched();
	}
}

/* 任务2 */
void Task2( void *p_arg )
{
	for( ;; )
	{
		flag2 = 1;
		delay( 100 );		
		flag2 = 0;
		delay( 100 );
		
		/* 任务切换,这里是手动切换 */
		//OSSched();
	}
}

2、关闭中断函数CPU_IntDis()

在这里插入图片描述
关闭中断。
因为在OS系统初始化之前我们启用了SysTick定时器产生10ms的中断,在中断里面触发任务调度。
如果一开始我们不关闭中断,就会在OS还有启动之前就进入SysTick中断,然后发生任务调度,既然OS都还没启动,那调度是不允许发生的, 所以先关闭中断。
系统启动后,中断由OSStart()函数里面的OSStartHighRdy()重新开启。

CPU_IntDis()在cpu.c中被声明
在这里插入图片描述
一个关闭中断,一个开启中断
代码在cpu_a.asm中被定义
在这里插入图片描述

3、仿真测试

在这里插入图片描述

从图可以看到,两个任务轮流的占有CPU,享有相同的时间片。
其实目前的实验现象与上一章的实验现象还没有本质上的区别, 加入SysTick只是为了后续章节做准备。
上一章两个任务也是轮流的占有CPU,也是享有相同的时间片,该时间片是任务单次运行的时间。
不同的是本章任务的时间片等于SysTick定时器的时基,是很多个任务单次运行时间的综合。即在这个时间片里面任务运行了非常多次, 如果我们把波形放大,就会发现大波形里面包含了很多小波形
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/432248.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java-ssm-jsp-大学社团管理系统

java-ssm-jsp-大学社团管理系统 获取源码——》公主号&#xff1a;计算机专业毕设大全

pyg-创建消息传递网络

创建消息传递网络 — pytorch_geometric 文档 (pytorch-geometric.readthedocs.io) https://arxiv.org/abs/1801.07829 import torch from torch.nn import Sequential as Seq, Linear, ReLU from torch_geometric.nn import MessagePassing class EdgeConv(MessagePassing): …

Cloud-Sleuth分布式链路追踪(服务跟踪)

简介 在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求都会形成一条复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求最后的失败 GitHub - spring-cloud/spring-cloud-sl…

Java基础 - 8 - 算法、正则表达式

一. 算法 什么是算法&#xff1f; 解决某个实际问题的过程和方法 学习算法的技巧&#xff1f; 先搞清楚算法的流程&#xff0c;再直接去推敲如何写算法 1.1 排序算法 1.1.1 冒泡排序 每次从数组中找出最大值放在数组的后面去 public class demo {public static void main(S…

分析开源机器学习框架TensorFlow

TensorFlow是一个开源的机器学习框架&#xff0c;由Google开发和维护。它提供了一个灵活的编程环境&#xff0c;可用于构建和训练各种机器学习模型。TensorFlow的基本概念和使用场景如下&#xff1a; 张量&#xff08;Tensor&#xff09;&#xff1a;在TensorFlow中&#xff0c…

微信小程序开发系列(十六)·事件传参·data-*自定义数据

事件传参&#xff1a;在触发事件时,将一些数据作为参数传递给事件处理函数的过程,就是事件传参。 在微信小程序中,我们经常会在组件上添加一些自定义数据,然后在事件处理函数中获取这些自定义数据,从而完成业务逻辑的开发。 在组件上通过data-"的方式定义需要传递的数据,其…

大屏 超宽屏自适应最优解决方案(transform:scale)

问题引入&#xff1a; 可视化数据大屏需要适配各种大屏尺寸 1080P&#xff1a;1920*1080 2K&#xff1a;2560*1440 左右 4K&#xff1a;3840*2160 左右 8K&#xff1a;7680*4320 左右 ① 大屏使用rem 耗时 而且对浏览器最小字体不支持&#xff0c; ② 使用transform:scale可以…

【unity】shader优化总结-转载

分为三个部分&#xff1a;Unity官方文档&#xff0c;GDC&#xff0c;个人经验。 Unity Manual 1.计算量优化。着色器进行的计算和处理越多&#xff0c;对性能的影响越大。针对不影响最终效果但依然进行计算的无效代码&#xff0c;进行移除操作。计算的频率也会影响游戏的性能…

《操作系统真相还原》读书笔记四:安装nasm

下载链接&#xff1a;https://www.nasm.us/pub/nasm/releasebuilds/2.13.03/ 下载-解压-安装 tar zxvf nasm-2.13.03.tar.gz ./configure --prefix/home/truthos/nasm/toolchain/make && makeinstall执行make install export PATH/home/truthos/nasm/toolchain/bin:…

用自适应K-Means的差分进化算法解决有容量的电动汽车(EV)路由问题(2023)

Solving the Capacitated Electric Vehicle (EV) Routing Problem by The Differential Evolutionary Algorithm with Adaptive K-Means 摘要 本文旨在解决限制电能和工作量的路由问题&#xff0c;称为电容式电动汽车路由问题&#xff08;CEVRP&#xff09;。这个问题的目的是…

《 前端挑战与未来:如何看待“前端已死”》

在技术领域,时常会有一些激进的言论引发热议,比如近年来不少人声称“前端已死”。这样的言论引发了广泛的讨论和反思。本文将从几个方向探讨这个话题:为什么会出现“前端已死”的言论、如何看待这种说法、前端技术的未来发展趋势以及前端人如何应对这场职位突围战。 为什么会…

代码训练LeetCode(1)合并有序数组详解

代码训练(1)LeetCode之合并两个有序数组 Author: Once Day Date: 2024年3月5日 漫漫长路&#xff0c;才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 88. 合并两个有序数组 - 力扣&#xff08;LeetCode&#xff09;力扣 (LeetCode) …

【BUG】Windows状态栏总卡死解决办法

屋漏偏逢连夜雨&#xff0c;正在赶deadline呢&#xff0c;Windows状态老卡死&#xff0c;一时间崩溃。 解决办法&#xff1a; 右键状态栏新闻和咨询关掉 这个烧笔新闻与资讯我真服了

Ubantu 18.04 如何映射IP到公网,外网可以访问

介绍一种简单的方式&#xff0c;就是通过路由侠 inux 系统安装路由侠&#xff0c;可通过两种方式进行&#xff0c;一种是通过直接脚本安装&#xff0c;一种是通过 Docker 安装。 windows下载地址&#xff1a;路由侠-局域网变公网 方式一&#xff1a;通过脚本安装 1、获取安…

赵珊珊Go语言汇编视频课程

本课程由赵珊珊老师倾情打造&#xff0c;旨在深入解析Go语言与汇编语言结合的高级主题。学员将系统学习Go语言底层实现原理&#xff0c;掌握汇编代码优化技巧&#xff0c;为高性能、高并发应用开发奠定坚实基础&#xff0c;助力学员在软件工程领域取得更大成功。 课程大小&…

Ajax+Axios+前后端分离+YApi+Vue-ElementUI组件+Vue路由+nginx【全详解】

目录 一.Ajax技术 二. Axios 三.前后台分离开发介绍 四. YAPI 五.前端工程化 六.vue工程的目录结构 七.Vue项目核心文件 八.Vue组件库ElementUI AboutView.vue最终代码 AboutView.vue最终代码 九.Vue路由 十.案例 十一.nginx介绍 一.Ajax技术 1.Ajax概述 Ajax: 全…

excel 动态列导出

excel动态列&#xff0c;只好用poi来写了&#xff0c;也并不复杂&#xff0c;一样就这个件事情抽像为几步&#xff0c;就是套路了&#xff0c;开发效率就上去了。 1 准备空模板 导出操作与excel模板的导出一样&#xff0c;可以参考excel导出标准化 2 自定义SheetWriteHandler …

Redis面试问题纯享版

基础内容 1、简单介绍以下你了解的Redis 2、对比一下Redis和Memcache的异同&#xff1f; 3、为什么MySQL选用Redis作为缓存&#xff1f; 4、详细聊聊你对Redis各种数据类型的了解&#xff1f; 5、Redis中五种基本数据类型的底层数据结构是什么样的&#xff1f; Redis线程模型…

图书推荐|Word文稿之美

让你的文档从平凡到出众&#xff01; 本书内容 《Word文稿之美》是一本全面介绍Word排版技巧和应用的实用指南。从初步认识数字排版到高效利用模板、图文配置和表格与图表的排版技巧&#xff0c;再到快速修正错误和保护文件&#xff0c;全面系统地讲解数字排版的技术和能力&…

【Linux】编译器gcc | make | Makefile | 模拟进度条 | gitee

目录 1. 编译器 gcc 1.1 背景知识 1.2 gcc如何完成 2.1 Makefile背景 2.2 Makefile原理 2.3 Makefile常用符号 3. 模拟倒计时 4. 模拟进度条 5. 使用 git 命令行 5.1 安装 git 5.2 创建项目下载到本地 5.3 推送本地代码到远端仓库 1. 编译器 gcc 1.1 背景知识 预处…