2.17 STM32 SysTick—系统定时器

news2025/1/15 17:37:01

文章目录

  • 1、简介
  • 2、寄存器
    • 2.1 SysTick控制和状态寄存器(STK_CTRL)
    • 2.2 重载值寄存器(STK_LOAD)
    • 2.3 SysTick当前值寄存器 (STK_VAL)
    • 2.4 校准寄存器(STK_CALIB)
  • 3、SysTick 定时实验
    • 3.1 在标准库中
    • 3.2 在HAL库中的初始化
  • 4、SysTick 定时再RTX系统中延时的使用

1、简介

SysTick—系统定时器是属于 CM4 内核中的一个外设,内嵌在 NVIC 中。系统定时器是一个 24bit 的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK 等于 180M。当重装载数值寄存器的值递减到 0 的时候,系统定时器就产生一次中断,以此循环往复。

因为 SysTick 是属于 CM4 内核的外设,所以所有基于 CM4 内核的单片机都具有这个系统定时器,使得软件在 CM4 单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。

2、寄存器

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

2.1 SysTick控制和状态寄存器(STK_CTRL)

偏移地址:0x00
复位值: 0x0000 0000
在这里插入图片描述
COUNTFLAG:如果在上次读取本寄存器后, SysTick 已经计到了 0,则该位为 1。
CLKSOURCE:时钟源选择位,0=AHB/8,1=处理器时钟 AHB
TICKINT:1=SysTick 倒数计数到 0 时产生 SysTick 异常请求,0=数到 0 时无动作。也可以通过读取COUNTFLAG 标志位来确定计数器是否递减到0
ENABLE:SysTick 定时器的使能位

2.2 重载值寄存器(STK_LOAD)

偏移地址:0x04
复位值: 0x0000 0000
在这里插入图片描述
当计算器使能且计数值到0时,LOAD寄存器的值重加载到STK_VAL寄存器。

2.3 SysTick当前值寄存器 (STK_VAL)

偏移地址:0x08
复位值: 0x0000 0000
在这里插入图片描述
VAL寄存器包含SysTick计数器的当前值

2.4 校准寄存器(STK_CALIB)

偏移地址:0x0C
复位值: 0x0000 0000
在这里插入图片描述

3、SysTick 定时实验

3.1 在标准库中

利用 SysTick 产生 1s 的时基,LED 以 1s 的频率闪烁。

int main(void)
{
	/* LED 端口初始化 */
	LED_GPIO_Config();	 
 
  /* 配置SysTick 为10us中断一次,时间到后触发定时中断,
	*进入stm32fxx_it.c文件的SysTick_Handler处理,通过数中断次数计时
	*/
	SysTick_Init();
  
	while(1)
	{

		LED_RED; 
	  Delay_us(100000);    	// 10000 * 10us = 1000ms
		//Delay_ms(1000);
	  
		LED_GREEN;
	  Delay_us(100000);		// 10000 * 10us = 1000ms
		//Delay_ms(1000);
	
		LED_BLUE;
	  Delay_us(100000);		// 10000 * 10us = 1000ms
		//Delay_ms(1000);


	}   
}

/**
  * @brief  启动系统滴答定时器 SysTick
  * @param  无
  * @retval 无
  */
void SysTick_Init(void)
{
	/* SystemFrequency / 1000    1ms中断一次
	 * SystemFrequency / 100000	 10us中断一次
	 * SystemFrequency / 1000000 1us中断一次
	 */
	 //uint32_t SystemCoreClock = 180000000;
	if (SysTick_Config(SystemCoreClock / 100000))
	{ 
		/* Capture error */ 
		while (1);
	}
}
/** \brief  System Tick Configuration

    The function initializes the System Timer and its interrupt, and starts the System Tick Timer.
    Counter is in free running mode to generate periodic interrupts.

    \param [in]  ticks  Number of ticks between two interrupts.

    \return          0  Function succeeded.
    \return          1  Function failed.

    \note     When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
    function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
    must contain a vendor-specific implementation of this function.

 */
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);      /* Reload value impossible */
// 设置重装载寄存器
  SysTick->LOAD  = ticks - 1;                                  /* set reload register */
  // 设置中断优先级
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
 // 设置系统定时器的时钟源为 AHBCLK=180M
 // 使能系统定时器中断
 // 使能定时器
  SysTick->CTRL
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
  return (0);                                                  /* Function successful */
}

用固件库编程的时候我们只需要调用库函数 SysTick_Config()即可,形参 ticks 用来设置重装载寄存器的值,最大不能超过重装载寄存器的值 224,当重装载寄存器的值递减到 0的时候产生中断,然后重装载寄存器的值又重新装载往下递减计数,以此循环往复。紧随其后设置好中断优先级,最后配置系统定时器的时钟为 180M,使能定时器和定时器中断,这样系统定时器就配置好了,一个库函数搞定。

3.2 在HAL库中的初始化

/**
  * @brief This function configures the source of the time base:
  *        The time source is configured to have 1ms time base with a dedicated
  *        Tick interrupt priority.
  * @note This function is called  automatically at the beginning of program after
  *       reset by HAL_Init() or at any time when clock is reconfigured  by HAL_RCC_ClockConfig().
  * @note In the default implementation, SysTick timer is the source of time base.
  *       It is used to generate interrupts at regular time intervals.
  *       Care must be taken if HAL_Delay() is called from a peripheral ISR process,
  *       The SysTick interrupt must have higher priority (numerically lower)
  *       than the peripheral interrupt. Otherwise the caller ISR process will be blocked.
  *       The function is declared as __weak  to be overwritten  in case of other
  *       implementation  in user file.
  * @param TickPriority: Tick interrupt priority.
  * @retval HAL status
  */
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  HAL_StatusTypeDef  status = HAL_OK;

  if (uwTickFreq != 0U)
  {
    /* Configure the SysTick to have interrupt in 1ms time basis*/
    //SystemCoreClock  = 16000000UL,uwTickFreq=1
    if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) == 0U)
    {
      /* Configure the SysTick IRQ priority */
      if (TickPriority < (1UL << __NVIC_PRIO_BITS))
      {
        HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
        uwTickPrio = TickPriority;
      }
      else
      {
        status = HAL_ERROR;
      }
    }
    else
    {
      status = HAL_ERROR;
    }
  }
  else
  {
    status = HAL_ERROR;
  }

  /* Return function status */
  return status;
}

4、SysTick 定时再RTX系统中延时的使用

#define delay_us(us)			Delay_Us(us)
#define delay_ms(us)			Delay_Us(us*1000)

#include "delay.h"
#include "os_tick.h"
void Delay_Us(uint32_t u32Us)
{
	uint32_t u32Last = SysTick->VAL;//SysTick当前值寄存器 
	uint32_t u32Cnt = 0;
	uint32_t u32Period = OS_Tick_GetInterval();//SysTick->LOAD + 1U,重载值寄存器的值。如果在跑系统,设置的是计时1ms LOAD的值,即SystemCoreClock / (1000U);
	u32Us *= (SystemCoreClock / 1000000);//计时u32Us uS的计数值
	while(1)
	{
		uint32_t u32Now = SysTick->VAL;//SysTick当前值寄存器(递减)
		if(u32Now != u32Last)
		{
			if(u32Now < u32Last)
				u32Cnt += (u32Last - u32Now);//SYSTICK是递减的计数器就可以.
			else
				u32Cnt += (u32Period - u32Now + u32Last);
			if(u32Cnt >= u32Us)
				break; //时间超过/等于要延迟的时间,则退出.
			u32Last = u32Now;
		}
	}
}
/*
OS Tick API
OS_Tick_Setup : 建立 OS Tick 。
OS_Tick_Enable : 启用 OS Tick 。
OS_Tick_Disable : 禁用 OS Tick 。
OS_Tick_AcknowledgeIRQ : 确认 OS Tick IRQ 。
OS_Tick_GetIRQn : 获取 OS Tick IRQ 编号。
OS_Tick_GetClock : 获取 OS Tick 时钟。
OS_Tick_GetInterval : 获取 OS Tick 间隔。
OS_Tick_GetCount : 获取 OS Tick 计数值。
OS_Tick_GetOverflow : 获取 OS Tick 溢出状态。
*/

以下是RTX里,os_systick.c里的代码

/**************************************************************************//**
 * @file     os_systick.c
 * @brief    CMSIS OS Tick SysTick implementation
 * @version  V1.0.3
 * @date     19. March 2021
 ******************************************************************************/
/*
 * Copyright (c) 2017-2021 ARM Limited. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "os_tick.h"

//lint -emacro((923,9078),SCB,SysTick) "cast from unsigned long to pointer"
#include "RTE_Components.h"
#include CMSIS_device_header

#ifdef  SysTick

#ifndef SYSTICK_IRQ_PRIORITY
#define SYSTICK_IRQ_PRIORITY    0xFFU
#endif

static uint8_t PendST __attribute__((section(".bss.os")));

// Setup OS Tick.
__WEAK int32_t OS_Tick_Setup (uint32_t freq, IRQHandler_t handler) {
  uint32_t load;
  (void)handler;

  if (freq == 0U) {
    //lint -e{904} "Return statement before end of function"
    return (-1);
  }

  load = (SystemCoreClock / freq) - 1U;
  if (load > 0x00FFFFFFU) {
    //lint -e{904} "Return statement before end of function"
    return (-1);
  }

  // Set SysTick Interrupt Priority
#if   ((defined(__ARM_ARCH_8M_MAIN__)   && (__ARM_ARCH_8M_MAIN__   != 0)) || \
       (defined(__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ != 0)) || \
       (defined(__CORTEX_M)             && (__CORTEX_M             == 7U)))
  SCB->SHPR[11] = SYSTICK_IRQ_PRIORITY;
#elif  (defined(__ARM_ARCH_8M_BASE__)   && (__ARM_ARCH_8M_BASE__   != 0))
  SCB->SHPR[1] |= ((uint32_t)SYSTICK_IRQ_PRIORITY << 24);
#elif ((defined(__ARM_ARCH_7M__)        && (__ARM_ARCH_7M__        != 0)) || \
       (defined(__ARM_ARCH_7EM__)       && (__ARM_ARCH_7EM__       != 0)))
  SCB->SHP[11]  = SYSTICK_IRQ_PRIORITY;
#elif  (defined(__ARM_ARCH_6M__)        && (__ARM_ARCH_6M__        != 0))
  SCB->SHP[1]  |= ((uint32_t)SYSTICK_IRQ_PRIORITY << 24);
#else
#error "Unknown ARM Core!"
#endif

  SysTick->CTRL =  SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk;
  SysTick->LOAD =  load;
  SysTick->VAL  =  0U;

  PendST = 0U;

  return (0);
}

/// Enable OS Tick.
__WEAK void OS_Tick_Enable (void) {

  if (PendST != 0U) {
    PendST = 0U;
    SCB->ICSR = SCB_ICSR_PENDSTSET_Msk;
  }

  SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk;
}

/// Disable OS Tick.
__WEAK void OS_Tick_Disable (void) {

  SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;

  if ((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) != 0U) {
    SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
    PendST = 1U;
  }
}

// Acknowledge OS Tick IRQ.
__WEAK void OS_Tick_AcknowledgeIRQ (void) {
  (void)SysTick->CTRL;
}

// Get OS Tick IRQ number.
__WEAK int32_t  OS_Tick_GetIRQn (void) {
  return ((int32_t)SysTick_IRQn);
}

// Get OS Tick clock.
__WEAK uint32_t OS_Tick_GetClock (void) {
  return (SystemCoreClock);
}

// Get OS Tick interval.
__WEAK uint32_t OS_Tick_GetInterval (void) {
  return (SysTick->LOAD + 1U);
}

// Get OS Tick count value.
__WEAK uint32_t OS_Tick_GetCount (void) {
  uint32_t load = SysTick->LOAD;
  return  (load - SysTick->VAL);
}

// Get OS Tick overflow status.
__WEAK uint32_t OS_Tick_GetOverflow (void) {
  return ((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) >> SCB_ICSR_PENDSTSET_Pos);
}

#endif  // SysTick

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

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

相关文章

driftingblues7靶机(eyes of network漏洞)

环境准备 靶机链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;49by 虚拟机网络链接模式&#xff1a;桥接模式 攻击机系统&#xff1a;kali linux 2021.1 信息收集 1.arp-scan -l 2.探测靶机开放端口和服务情况 nmap -p- -A -T4 192.168.1.108 漏洞利用 1.访…

为什么开发者这么看重SQL?看完这些应用场景你就明白了

看到一个有趣的比喻&#xff0c;用来说明SQL与Excel的差别是什么。 如果把SQL比作火车&#xff0c;把Excel更比作卡车。 卡车灵活自由&#xff0c;高速或乡村小道想去哪就去哪&#xff0c;但即便每天不停歇卡车的运载量也不大&#xff0c;而且容易出交通事故。 火车运载量大…

P2P中的NAT穿越(打洞)方案详解

1、内容概述 P2P即点对点通信&#xff0c;或称为对等联网&#xff0c;与传统的服务器客户端模式&#xff08;如下图“P2P结构模型”所示&#xff09;有着明显的区别&#xff0c;在即时通讯方案中应用广泛&#xff08;比如IM应用中的实时音视频通信、实时文件传输甚至文字聊天等…

【Python基础】篇四之while、for循环及其嵌套、continue、break

while循环基本格式&#xff1a;while 条件&#xff1a;条件满足时做的事1条件满足时做的事2条件满足时做的事省略注&#xff1a;只要条件满足就会一直执行while的条件需得到布尔类型&#xff0c;True表示循环继续&#xff0c;False表示循环结束需要设置循环终止条件&#xff0c…

map 源码思考

go 语言中 map 比较的说&#xff0c;和 slice 有什么区别&#xff1f;如果 map 是从 int 到 int 类型的话&#xff0c;差别还真不大。map 的 key 退化为 slice 的下标&#xff0c;而 value 退化为 slice 的值。 但这样也存在很大的弊端&#xff1a;空间浪费严重。假设 map 中只…

虹科分享 | 网络流量监控 | 构建大型捕获文件(Ⅱ)——Pcap分析仪:Allegro网络万用表的Pcap过滤器

上一期我们讨论的是如何使用Wireshark工具进行结构化搜索的技术&#xff0c;这一期我们将为大家进行介绍&#xff0c;我们该如何使用 Allegro 网络万用表来加快 pcap 分析器的工作。 前期回顾&#xff1a;构建大型捕获文件&#xff08;Ⅰ&#xff09;——Wireshark过滤器和其他…

VIVO应用商店APP侵权投诉流程

目录一、官方指引二、侵权投诉提交流程一、官方指引 https://dev.vivo.com.cn/documentCenter/doc/34 二、侵权投诉提交流程 登录 vivo 开放平台&#xff1a;https://dev.vivo.com.cn/&#xff0c;点击右下角“工单系统”&#xff1a; 业务类型选 “投诉举报类”&#xff0…

Redis-设置过期时间及淘汰策略

文章目录1. TTL2. 设置过期时间3. 删除过期key4. 淘汰策略Redis-设置过期时间及淘汰策略项目组使用的 Redis 服务器发出了内存不足报警&#xff0c;查了一些资料&#xff0c;记录下。 1. TTL 查看 Redis key 是否过期是 TTL 命令&#xff0c;或者登陆 Redis 客户端&#xff0…

重点算法排序之堆排序(下篇)

文章目录 一、堆排序的概念 1、1 堆的基本概念 1、2 堆的特性 二、堆排序的思路及代码实现 2、1 建堆 2、2 向下调整算法详解 2、3 建完堆后进行堆排序 2、3、1 排升序建大堆 2、3、2 建大堆后进行堆排序 三、堆排序的例题 2、1 例题1&#xff1a;堆排序 2、2 例题2&#x…

HTTP.sys远程代码执行漏洞修复

1.漏洞描述 Http.sys是Microsoft Windows处理HTTP请求的内核驱动程序。HTTP.sys会错误解析某些特殊构造的HTTP请求&#xff0c;导致远程代码执行漏洞。成功利用此漏洞后&#xff0c;攻击者可在System帐户上下文中执行任意代码。由于此漏洞存在于内核驱动程序中&#xff0c;攻击…

VMware下的虚拟机网络设置(NAT、桥接、仅主机)

在入门使用VMware搭建Linux的环境时&#xff0c;对于网络的设置时不可避免的&#xff0c;因为linux搭建完成后&#xff0c;或多或少的回去访问外部资源或者被外部资源访问。这时候设置的虚拟机网络连接方式就显得尤为重要&#xff0c;所以在这里整理了一下虚拟机的三种连接方式…

说说压缩文件“打开密码”的两种模式

我们知道&#xff0c;如果对压缩文件有保密需求&#xff0c;可以给压缩文件设置“打开密码”&#xff0c;通过密码才能查看压缩文件里的内容。那通过WinRAR设置的“打开密码”有两种模式&#xff0c;你知道吗&#xff1f;下面来具体说说。 模式一&#xff1a;可以看到压缩包的…

springboot集成mybatis

springboot集成mybatis 文章目录springboot集成mybatis前言一、初始化项目1.创建项目2.引入依赖3.创建实体类4.修改配置文件二、使用Mybatis1.纯注解方式2.使用xml文件方式三、使用pagehelper分页前言 MyBatis 是一个开源、轻量级的数据持久化框架&#xff0c;是 JDBC 和 Hibe…

赤池信息量准则(AIC)和贝叶斯信息准则(BIC)

一 AIC 赤池信息量准则&#xff08;Akaike information criterion&#xff0c;AIC&#xff09;是评估统计模型的复杂度和衡量统计模型“拟合”资料之优良性(Goodness of fit)的一种标准&#xff0c;是由日本统计学家赤池弘次创立和发展的。赤池信息量准则建立在信息熵的概念基…

LeetCode题目笔记——面试题 02.07. 链表相交

文章目录题目描述题目难度——简单方法一&#xff1a;数数&#xff0c;然后遍历代码/C方法二&#xff1a;双指针代码/C代码/Python总结题目描述 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c…

假期无聊,不如一起刷《剑指offer》(第六天)

剑指 Offer 41. 数据流中的中位数 剑指 Offer 41. 数据流中的中位数 这道题是求数据流的中位数&#xff0c;一般情况我们可以采用排序的方式很轻松的找出中位数。如果我们采用插入排序的话&#xff0c;每次插入数字的时间复杂度大概是O(N)&#xff0c;怎么能让这个时间更短呢&a…

shell原理及Linux权限

shell及Linux权限 目录shell及Linux权限一、指令1.tar指令&#xff08;重要&#xff09;2.热键3.bc命令4.uname –r指令&#xff1a;5.关机6.以下命令作为扩展:二.shell命令以及运行原理三.权限1.权限的概念&#xff1a;2.Linux下有两种用户&#xff1a;超级用户&#xff08;ro…

一图读懂mybatis 查询接口的源码流程

图比较大&#xff1a;如果看着比较糊的话&#xff0c;可以下载高清图&#xff1a;https://download.csdn.net/download/langwuzhe/87376216 第一步&#xff1a;创建 StatementHandler、ParameterHandler、ResultSetHandler-----------(三剑客的新生) 创建 StatementHandler 对…

WPS怎么转换PDF?保证你一学就会

相信大家在处理文件的时候肯定会使用到WPS文件&#xff0c;WPS文件包括Word、Excel、PPT文件&#xff0c;是我们经常使用的几种文件&#xff0c;有这几种文件我们可以更好的完成工作&#xff0c;但是在有些情况下&#xff0c;我们需要将WPS转换成PDF文件&#xff0c;这样就会更…

AS弹性伸缩简单介绍

AS 介绍 弹性伸缩(AutoScaling)是一种服务&#xff0c;可以自动调整弹性计算资源&#xff08;ECS)&#xff0c;以满足业务需求的变化。 弹性伸缩仅支持ECS实例或ECI实例数量的增加和减少&#xff0c;但不支持单个ECS实例或ECI实例的配置变更。 应用场景&#xff1a;弹性扩张、…