第11章_瑞萨MCU零基础入门系列教程之SysTick

news2025/1/16 17:56:01

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写,需要的同学可以在这里获取: https://item.taobao.com/item.htm?id=728461040949

配套资料获取:https://renesas-docs.100ask.net

瑞萨MCU零基础入门系列教程汇总: https://blog.csdn.net/qq_35181236/article/details/132779862


第11章 SysTick

本章目标

  • 了解滴答定时器的概念
  • 学会配置滴答定时器和扩展驱动应用

11.1 认识滴答定时器

SysTick定时器也被称为滴答定时器。在Cortex架构的处理器里,有一个24bit的向下计数定时器,它就是滴答定时器。它不是处理器之外的、跟GPIO等设备同等地位的设备,而是位于处理器内部的定时器。

对于Cortex-M33内核而言,它拥有2个滴答定时器:一个用于非安全系的滴答定时器,另一个用于安全系的滴答定时器。如果开发者不使用Cortex-M33的TrustZone的程序安全功能,那么只能使用一个非安全系的滴答定时器。

滴答定时器有4个寄存器用于控制和获取状态:

a) 控制和状态寄存器:SYST_CSR
b) 重载值寄存器:SYST_RVR
c) 当前计数值寄存器:SYST_CVR
d) 校验值寄存器:SYST_CALIB

使用滴答定时器就是对这几个寄存器进行配置让它按照指定的频率进行计数,本章会实现几个驱动函数为后续章节的外设驱动使用。

11.2 滴答定时器的配置

在配置滴答定时器前,首先应该要熟悉其工作机制,其工作机制有如下几条:

① 当使能了滴答定时器的计数后,滴答定时器将会从重载值向下计数到零,然后在下一个时钟周期从重载值寄存器读取重载值,在紧随的下一个时钟周期又开始向下计数。
② 如果给重载值寄存器RVR写入了一个‘0’,那么本次计数循环(也就是本次向下计数到0)后就会停止计数。
③ 当计数到0使,控制状态寄存器CSR的计数标志COUNTFLAG位会被置1.,当读取CSR寄存器时会将这一位清零。
④ 如果给当前计数值寄存器CVR写入一个值时,会更新CVR的值且会将COUNTFLAG清零;
⑤ 如果程序处于调试状态,当开发者暂停调试时,滴答定时器也会暂停计数;

可以看到,这几个机制中使用到的寄存器只有3个:CSR(Control and Status Register,控制和状态寄存器)、RVR(Reload Value Register,重载值寄存器)和CVR(Current Value Register,当前值寄存器)。接下来就着重认识下这3个寄存器,并且学会如何配置他们。

11.2.1 控制和状态寄存器SYST_CSR

控制状态寄存器各个位的描述如下图:

  • Bit0-ENABLE:计数器使能位;0-不使能计数器;1-使能计数器;
  • Bit1-TICKINT:滴答定时器中断请求位;0-计数到0不产生中断请求;1-产生中断请求;
  • Bit2-CLKSOURCE:滴答定时器的时钟选择位;0-使用外部基准时钟;1-使用处理器时钟;
  • Bit16-COUONTFLAG:滴答定时器技术标志位,当计数到0时置1,如果没有读取CSR的话将会一直为1;

CSR寄存器上电复位默认值是0x00000000,一般情况下,程序是需要滴答定时器产生中断请求来判定滴答定时器计数到0的,所以TICKINT通常被设置为1;而时钟源的选择,惯用的是选择处理器时钟。所以在初始化的时候,一般将CSR的值设置为0x07。

11.2.2 重载值寄存器SYST_RVR

重载值寄存器虽然是一个32bit的寄存器,但是鉴于滴答定时器的设计只有24位的计数值,因而此寄存器只有低24bit有效,高8bit保留,如下图所示:

所谓重载值,就是指滴答定时器计数到0时,又重新从这个值开始向下计数。例如程序中需要滴答定时器从100开始向下计数,那么这里就将RVR的低24bit设置为‘100-1’,也就是十六进制的0x63,二进制的0110 0011,那么RVR寄存器的值就是下图这样:

11.2.3 当前计数值寄存器SYST_CVR

当前计数值寄存器CVR也是低24bit有效,用来表示滴答定时器当前的计数值,如图所示:

无论程序给此寄存器写入什么值,都会将此寄存器清零,并且会将计数标志位COUNTFLAG清零。

11.2.4 滴答定时器的初始化配置

滴答定时器还有一个校准寄存器CALIB,它是只读寄存器,无需操作。从Cortex-M33的调试手册中其对滴答定时器的各个寄存器总结如下图:

那么开发者配置滴答定时器时,步骤如下:

① 选择抵达定时器的时钟源;
② 使能滴答定时器的中断请求;
③ 设置重载值;
④ 清零当前计数值;
⑤ 使能滴答定时器计数;

  1. 初始化滴答定时器

在Cortex内核源文件的core_cmXX.h,比如core_cm33.h定义滴答定时器的初始化函数,代码如下:

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);                       /* Reload value impossible */
  }
  SysTick->LOAD  = (uint32_t)(ticks - 1UL);              /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;          /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
  return (0UL);                  /* Function successful */
}

开发者只需要在自己的代码中调用此函数,传入一个指定的重载值即可,例如下面这个代码:

fsp_err_t SystickInit(void)
{
	/* 获取处理器时钟uwSysclk */
    uint32_t uwSysclk= R_BSP_SourceClockHzGet(FSP_PRIV_CLOCK_PLL);
    /* 技术周期为uwSysclk/1000 */
    if(SysTick_Config(uwSysclk/1000) != 0)
    {
        return FSP_ERR_ASSERTION;
    }
    /* Return function status */
    return FSP_SUCCESS;
}

如上初始化滴答定时器后,它的计数时钟频率就是处理器的系统主频

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在此频率下向下计数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

个数后触发中断,也就是每秒钟触发1000次中断,换算公式如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

假如

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

那么传入给SysTick_Config函数的值就是200K,滴答定时器就会以200MHz的频率从200K往0开始递减,递减为0时触发一次中断,中断触发频率就是

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 实现滴答定时器的中断服务函数

当滴答定时器计数到0时,会触发中断,中断服务函数SysTick_Handler被调用,这个函数需要开发者实现,比如给一个全局变量递增1,参考如下代码:

volatile  uint32_t dwTick = 0;
void SysTick_Handler(void)
{
    dwTick += 1;
}

11.3 基于SysTick的扩展应用

本实验会用到板载LED外设和printf功能,请读者参考本书《第5章 GPIO输入输出》和《第7章 UART》来配置LED的GPIO和UART模块,并且移植drv_uart.c和drv_config.h到本节实验的工程“1101_systick_delay”中。

在上一小节已经初始化了滴答定时器、实现了中断服务函数。本节在此基础上实现一个ms级别的延时函数(因为初始化设置的滴答定时器是1KHz的中断触发频率)。参考如下代码:

#define HAL_MAX_DELAY      0xFFFFFFU
void HAL_Delay(uint32_t dwTime)
{
    uint32_t dwStart = dwTick;
    uint32_t dwWait = dwTime;

    /* Add a freq to guarantee minimum wait */
    if (dwWait < HAL_MAX_DELAY)
    {
        dwWait += (uint32_t)(1);
    }

    while((dwTick - dwStart) < dwWait)
    {
    }
}
  • 第10行:在延时值基础上加1;
  • 第13行:滴答定时器中断服务函数中的递增变量dwTick减去此延时函数调用时刻的dwStart,即滴答定时器触发“dwTick- dwStart”次后大于等于延时时长后才退出函数;

为什么dwWait要先加1?这是因为执行HAL_Delay函数时必定是在2次滴答定时器中断之间,距离下一次中断的时间必定小于1ms。比如传入的dwTime等于2时,实际延时的时间是大于1ms、小于2ms。第10行里让dwWait值加1,目的是使得延时能满足下限:“至少延时dwWait毫秒”。

还可以读取dwTick获取系统运行时间/时刻,例如以下代码:

uint32_t HAL_GetTick(void)
{
	return dwTick;
}

11.4 测试程序

本书测试滴答定时器的方法是:使用基于滴答定时器的延时函数来闪烁LED,并且打印延时前后的tick值。代码如下:

void SystickAppTest(void)
{
    uint8_t ucCount = 5;
    uint32_t dwLastTick = 0, dwCurtick = 0;
    bsp_io_level_t nLevel = false;
    
    while(ucCount--)
    {
        dwLastTick = HAL_GetTick();
        HAL_Delay(1000);
        dwCurtick = HAL_GetTick();

11.5 上机实验

本实验将滴答定时器的驱动在hal_systick.c中实现,在hal_systick.h中声明;测试函数在app_systick.c中实现,在app.h中声明;最后在hal_entry.c中调用初始化函数和测试函数,代码如下:

#include "app.h"
#include "hal_systick.h"
#include "drv_uart.h"
#include "hal_data.h"

void hal_entry(void)
{
    /* TODO: add your own code here */
    SystickInit();
    UARTDrvInit();
    
    SystickAppTest();
}

将程序编译出来的二进制可执行文件烧录到处理器中运行可以得到如下图的结果:

开发板上LED间隔1s改变状态。


本章完

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QTabWidget当tab位置在左右时,设置文字方向朝上

QTabWidget当tab位置在左右时&#xff0c;设置文字方向朝上解决方案 方案一&#xff1a;调用setTabButton()方法方案二&#xff1a;重写QTabBar方案三&#xff1a;重写QProxyStyle 当用QTabWidget控件时&#xff0c;默认是下方显示&#xff1a; 如果想左侧或右侧显示tab页&…

upload-labs文件上传漏洞通关

一、环境搭建 upload-labs是一个使用php语言编写的&#xff0c;专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。 下载地址&#xff1a;https://github.com/c0ny1/upload-labs/releases 在 win 环境下 直接解压到phpstudy下即可 二、通关 &#xff08;一&#xff09;16关…

【leetcode 力扣刷题】删除字符串中的子串or字符以满足要求

删除字符串中的子串或者字符以满足题意要求 1234. 替换子串得到平衡字符串680. 验证回文串917. 仅仅反转字母 1234. 替换子串得到平衡字符串 题目链接&#xff1a;1234. 替换子串得到平衡字符串 题目内容&#xff1a; 题目中给出了平衡字符串的定义——只有’Q’&#xff0c;…

【C++】详解std::thread

2023年9月10日&#xff0c;周日下午开始 2023年9月10日&#xff0c;周日晚上23:35完成 虽然这篇博客我今天花了很多时间去写&#xff0c;但是我对std::thread有了一个完整的认识 不过有些内容还没完善&#xff0c;以后有空再更新.... 目录 头文件类的成员类型方法(construc…

GDB用法(三)

预备 测试代码参照GDB用法(二) 命令历史 可以将命令历史保存到文件中 (show history) 展示当前gdb中history的设置信息 设置expansion (set history expansion) 打开历史扩展 能使用历史处理命令对历史数据进行处理, 暂不细究 (show history expansion) 展示历史扩展配置…

《JDK17新特性和代码案例演示》

《JDK17新特性和代码案例演示》 &#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全…

sqli --【1--10】

Less-1&#xff08;联合查询&#xff09; 1.查看是否有回显 2.查看是否有报错 3.使用联合查询&#xff08;字符注入&#xff09; 3.1判断其列数 3.2 判断显示位置 3.3敏感信息查询 Less-2&#xff08;联合查询&#xff09; 1.查看是否有回显 2.查看是否有报错 3.使用…

[学习笔记]词向量模型-Word2vec

参考资料&#xff1a; 【word2vec词向量模型】原理详解代码实现 NLP自然语言处理的经典模型Word2vec 论文背景知识 词的表示方法 One-hot Representation&#xff1a;独热表示 简单&#xff0c;但词越多&#xff0c;向量越长。且无法表示词与词之间的关系。 论文储备知识-pr…

Ae 效果:CC Scatterize

模拟/CC Scatterize Simulation/CC Scatterize CC Scatterize&#xff08;CC 散射&#xff09;主要用于模拟将对象散射为颗粒状的效果。 CC Scatterize 的工作原理是&#xff1a;对源图像的 Alpha 通道先进行融解 Dissolve&#xff0c;从而产生随机颗粒&#xff0c;因此改变了源…

安卓系列机型 另类体验第三方系统 DSU操作步骤解析 不影响主系统开启第二系统

dsu loader即 动态系统更新&#xff0c;可以在使用动态分区的安卓设备上&#xff0c;不影响原来系统的同时安装一个副系统&#xff0c;用于体验最新的原生安卓系统。可以不影响主系统的基础上体验其他gsi第三方。DSU 依赖于 Android 动态分区功能&#xff0c;并要求 GSI 作为可…

博客系统(升级(Spring))(二)获取当前用户信息、对密码进行加密、设置统一数据格式、设置未登录拦截、线程池

博客系统&#xff08;二&#xff09; 博客系统获取当前用户的信息对密码进行加密和解密的操作设置统一的数据返回格式设置未登录拦截设置线程池 博客系统 博客系统是干什么的&#xff1f; CSDN就是一个典型的博客系统。而我在这里就是通过模拟实现一个博客系统&#xff0c;这是…

精品基于SpringCloud实现的高校招生信息管理系统-微服务-分布式

《[含文档PPT源码等]精品基于SpringCloud实现的高校招生信息管理系统-微服务-分布式》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;Java 框架&#xff1a;springcloud JDK版本&#x…

【环境配置】基于Docker配置Chisel-Bootcamp环境

文章目录 Chisel是什么Chisel-Bootcamp是什么基于Docker配置Chisel-Bootcamp官网下载Docker安装包Docker换源启动Bootcamp镜像常用docker命令 可能产生的问题 Chisel是什么 Chisel是Scala语言的一个库&#xff0c;可以由Scala语言通过import引入。 Chisel编程可以生成Verilog代…

C高级day3(shell指令)

一、Xmind整理&#xff1a; 二、上课笔记整理&#xff1a; 1.定义一个变量&#xff0c;把第11个外部参数的值&#xff0c;赋值给该变量并输出&#xff0c;再输出外部参数的个数 var3${11} echo $var3 echo $# 2.定义一个变量num&#xff0c;使用num获取root用户&#xff0c;…

腾讯事务处理技术验证系统3TS-Coo模板安装文档说明文档(小白向,简单轻松就能上手)

本篇文章将详细说明3TS-Coo模板的安装和使用&#xff0c;帮助您快速上手项目 第一部分是简单的基础Docker相关概念&#xff0c;精炼的几句小白话快速理解即可&#xff1b; 第二部分是快速安装项目环境的安装文档&#xff0c;简单几行命令搞定&#xff0c;小白也能轻松上手&…

12. Xaml Calendar控价 时间控件-->像挂历

1.运行图片 2.运行源码 a.xaml 源码 <Grid Name="Grid1"><!--DisplayMode="Month" 按照什么模式显示DisplayDateStart="2023-2-10" 显示时间的起始时间DisplayDateEnd="2023-8-30" 显示时间的结束时间IsTodayH

MyBatis-Plus-入门操作(1)

MyBatis-Plus-入门操作 2.1常见注解 约定大于配置 mp扫描实体类基于反射的方式作为数据库表的信息。 默认的约定 类名驼峰转下划线名字为id的是主键属性名进行驼峰转换成下划线 要是不遵循约定的话就需要对应的注解进行修改。 表的名字和 实际的表的名字是不一致的 Table…

Scrum看板工具-敏捷看板?

​ 敏捷看板 看板是一个团队共享的工作区&#xff0c;在看板上团队可以进行实时的工作任务协同&#xff0c;团队的工作以卡片的形式体现。通过泳道和任务列表组织管理。需求、任务、问题、缺陷 都作为卡片放在看板上&#xff0c;通过看板实现可视化和透明化的 管理&#xff0…

PHP8中获取并删除数组中第一个元素-PHP8知识详解

我在上一节关于数组的教程&#xff0c;讲的是在php8中获取并删除数组中最后一个元素&#xff0c;今天分享的是相反的&#xff1a;PHP8中获取并删除数组中第一个元素。 回顾一下昨天的知识&#xff0c;array_pop()函数将返回数组的最后一个元素&#xff0c;今天学习的是使用arr…

数据结构 每日一练:选择 + 编程

目录 选择 选择题总结 特殊矩阵的压缩存储 1.对阵矩阵 2.三角矩阵 3.三对角矩阵&#xff08;带状矩阵&#xff09; 编程 选择 1. 设有一个 10 阶的下三角矩阵 A &#xff08;包括对角线&#xff09;&#xff0c;按照行优先的顺序存储到连续的 55 个存储单元中&#xff0c…