【GD32F427开发板试用】Systick系统定时器的使用

news2024/7/6 19:56:55

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:HonestQiao

基于Arm Cortex-M系列内核的MCU,都包含了SysTick定时器。

所谓SysTick即为系统定时器,又称嘀嗒定时器,是Cortex-M内核的一个外设,集成在NVIC中。SysTick是一个24bit的向下递减的计数器,每计数一次的时间为1/SYSCLK。它的节拍,就相当于是MCU的心跳,让系统用整齐的步伐,来运行具体的系统和程序。操作系统需要执行多任务管理,用SysTick产生中断,确保单个任务不会锁定整个系统,同时SysTick还可用于闹钟定时、时间测量等。

GD32F4xx系列是基于Arm® Cortex®-M4处理器的32位通用微控制器,自然也包含了都包含了SysTick。

通过用户手册4.2.1章节,可以了解系统时钟树的具体信息:

其中具体说明如下:

预分频器可以配置 AHB、APB2 和 APB1 域的时钟频率。AHB 和 APB2/APB1 域的最高时率 分别为 240 MHz/120 MHz/60 MHz。RCU 通过 AHB 时钟(HCLK)8 分频后作为 Cortex 系 统定时器(SysTick)的外部时钟。通过对 SysTick 控制和状态寄存器的设置,可选择上述时 钟或 AHB(HCLK)时钟作为 SysTick 时钟。

通过硬件开发手册,可以了解到GD32F4xx系列的运行频率:

注意:GD32F405xx/ GD32F407xx系列MCU最高主频为168M;GD32F425xx/ GD32F427xx/ GD32F450xx系列MCU最高主频为200M;GD32F470xx系列MCU最高主频为240M。

从上面的信息可以得知,GD32F427开发板最高运行主频为200MHz。
在开发板系统定义文件system_gd32f4xx.c中,也有如下的定义:

/* select a system clock by uncommenting the following line */
//#define __SYSTEM_CLOCK_IRC16M                   (uint32_t)(__IRC16M)
//#define __SYSTEM_CLOCK_HXTAL                    (uint32_t)(__HXTAL)
//#define __SYSTEM_CLOCK_120M_PLL_IRC16M          (uint32_t)(120000000)
//#define __SYSTEM_CLOCK_120M_PLL_8M_HXTAL        (uint32_t)(120000000)
//#define __SYSTEM_CLOCK_120M_PLL_25M_HXTAL       (uint32_t)(120000000)
//#define __SYSTEM_CLOCK_168M_PLL_IRC16M          (uint32_t)(168000000)
//#define __SYSTEM_CLOCK_168M_PLL_8M_HXTAL        (uint32_t)(168000000)
//#define __SYSTEM_CLOCK_168M_PLL_25M_HXTAL       (uint32_t)(168000000)
//#define __SYSTEM_CLOCK_200M_PLL_IRC16M          (uint32_t)(200000000)
//#define __SYSTEM_CLOCK_200M_PLL_8M_HXTAL        (uint32_t)(200000000)
#define __SYSTEM_CLOCK_200M_PLL_25M_HXTAL       (uint32_t)(200000000)
//#define __SYSTEM_CLOCK_240M_PLL_IRC16M          (uint32_t)(240000000)
//#define __SYSTEM_CLOCK_240M_PLL_8M_HXTAL        (uint32_t)(240000000)
//#define __SYSTEM_CLOCK_240M_PLL_25M_HXTAL       (uint32_t)(240000000)

其中,运行频率定义为200MHz。

通常说的,12MHZ=12×10的6次方,即每秒发出12000000个脉冲信号,那么发出一个脉冲的时间就是时钟周期,也就是1/12微秒。

那200MHz,每秒就会发出2000000000个脉冲信号,那一个时钟周期,将达到1/200微秒。

那么在GD32F427开发板上,基于SysTick,就能实现us级的精确计时。

在系统内核定义文件core_m4.h中,有关于SySTick的具体定义:

typedef struct
{
  __IO uint32_t CTRL;                    /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
  __IO uint32_t LOAD;                    /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register       */
  __IO uint32_t VAL;                     /*!< Offset: 0x008 (R/W)  SysTick Current Value Register      */
  __I  uint32_t CALIB;                   /*!< Offset: 0x00C (R/ )  SysTick Calibration Register        */
} SysTick_Type;

其具体含义如下:

  • CTRL:控制和状态寄存器,用于使能SysTick计数
  • LOAD:重装载寄存器,倒计时计数初值
  • VAL:当前值寄存器,当前计数值
  • CALIB:校准值寄存器,系统自动配置的

那要使用SysTick,一个基础的用法就是用来做高精度延时:

  1. 初始化SysTick,并设置重置初值,也就是SysTick->LOAD
  2. 设置用户计数变量和初值
  3. 使能SysTick
  4. SysTick计数到零,中断触发,用户计数变量递减
  5. 判断用户计数变量是否归零

在core_m4.h中,提供了SysTick出初始化的调用:

__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 */
  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->LOAD,当前计数值SysTick->VAL归零,设置SysTick->CTRL使能中断和定时。

在系统中断服务程序gd32f4xx_it.c中,有关于SysTick中断的调用:

void SysTick_Handler(void)
{
    delay_decrement();
}

我们要使用SysTick,就需要具体定义其具体的处理逻辑,用于用户计数变量的
处理。

在演示代码的systick.c中,有如下的定义:

volatile static uint32_t delay;

void delay_decrement(void)
{
    if(0U != delay) {
        delay--;
    }
}

那么,一旦重新使能SysTick定时器,给delay赋一个初值,那么每经过一次SysTick中断触发,就会递减,直到归零为止。

而我们的代码中,就可以通过判断delay的值,来检查是否经过了所需次数的Tick。因为系统时钟周期为1/200微秒,那么只要设定好合理的Tick重置初值,通过合适的Tick数量,就能实现精确的us计时。

在systick.c中,有演示的SysTick设置:

void systick_config(void)
{
    /* setup systick timer for 1000Hz interrupts */
    if(SysTick_Config(SystemCoreClock / 1000U)) {
        /* capture error */
        while(1) {
        }
    }
    /* configure the systick handler priority */
    NVIC_SetPriority(SysTick_IRQn, 0x00U);
}

上述代码中,取系统时钟频率的千分之一进行设置,就使得每计数一千次,刚好经过1秒,那么每一次就是1毫秒。

参考上述代码,编写可以实现us级别的初始化设置:

void systick_config_us(void)
{
    /* SystemCoreClock / 1000    1ms中断一次
     * SystemCoreClock / 100000  10us中断一次
     * SystemCoreClock / 1000000 1us中断一次
     */
    /* setup systick timer for 1000Hz interrupts */
    if(SysTick_Config(SystemCoreClock / 1000000U)){
        /* capture error */
        while(1){
        }
    }

    // 关闭滴答定时器
    SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;

    /* configure the systick handler priority */
    NVIC_SetPriority(SysTick_IRQn, 0x00U);
}

void delay_us(uint32_t count)
{
    delay = count;

    // 使能滴答定时器
    SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk;

    while(0U != delay){
    }
}

在上述代码中,定义了1us中断一次,然后定义了delay_us()函数:

  • 定义用户计数变量初值
  • 使能SysTick定时器
  • 然后检测delay是否归零,归零说明1us时间到达

然后,在程序中,就可以调用上述的初始化函数,以及延时us的操作了。
main.c具体如下:

#include "gd32f4xx.h"
#include "gd32f427v_start.h"
#include "systick.h"

int main(void)
{
    systick_config_us();    //配置系统时钟
    
    rcu_periph_clock_enable(RCU_GPIOC);                                                //使能外部时钟

    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6);                //配置端口模式
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);    //输出选项配置
    gpio_bit_reset(GPIOC, GPIO_PIN_6);                                                //PC6复位

    while(1) 
    {
        gpio_bit_toggle(GPIOC, GPIO_PIN_6);    //反转PC6
        delay_us(1000*1000);
    }

在上述代码中,延时时间为1000*1000us,也就是1000ms,即1秒。

编译烧录代码后,就可以看到板载的LED2按秒亮灭;如果修改延时数值为100* 1000,那么就会大幅提高闪烁频率了,即1/10秒。

当设置为100* 1000时,使用逻辑分析仪分析了一下信号:

通过上图可以看到,这个延时,快准狠!!!

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

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

相关文章

Docker Swarm

Swarm 是什么&#xff1f; Docker Swarm 是Docker官方的跨节点的容器编排工具。用户只需要在单一的管理节点上操作&#xff0c;即可管理集群下的所有节点和容器。 主要解决什么问题 1. 解决docker server的集群化管理和部署。 2. Swarm通过对Docker宿主机上添加的标签信息来…

分享60个PHP源码,总有一款适合您

PHP源码 分享60个PHP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 60个PHP源码下载链接&#xff1a;https://pan.baidu.com/s/1SvjbzolwuMrQyhVb_byG5Q?pwdx831 提取码&#xff…

生物素点击标记试剂:DBCO-SS-PEG3-biotin,1430408-09-5,生物素PEG3二硫键DBCO

1、理论分析&#xff1a;中文名&#xff1a;生物素-三聚乙二醇-二硫-二苯并环辛炔&#xff0c;生物素-PEG3-二硫-DBCO &#xff0c;生物素PEG3-二硫二苯并环辛炔英文名&#xff1a;DBCO-S-S-PEG3-biotin&#xff0c;Biotin-PEG3-SS-DBCOCAS号&#xff1a;1430408-09-5化学式&am…

如何使用ArcGIS进行点抽稀

01 概述对于制图工作者而言&#xff0c;遇到大量的点要素&#xff08;POI、村名等&#xff09;标注的时候往往非常的麻烦&#xff0c;因为这些点往往都是十分的密集&#xff0c;直接标注很影响制图的美观。如果直接去处理原始的数据&#xff0c;会导致后续的数据更新维护麻烦&a…

pdf合并在线,大家都在用的工具

工作和生活当中都有很多场景需要我们提交PDF文档&#xff0c;而且有时候要求仅能提交一份&#xff0c;如果这时候刚好你的文档分成了几份&#xff0c;就得先合并之后才能提交。要在线合并PDF并不麻烦&#xff0c;关键是用对工具。下面就来给大家介绍几款热门的软件&#xff0c;…

Spring Boot(五十五):基于redis防止接口恶意刷新和暴力请求

下面的教程&#xff0c;通过intercept和redis针对urlip在一定时间内访问的次数来将ip禁用&#xff0c;可以根据自己的需求进行相应的修改&#xff0c;来达到自己的目的 下面只讲解大致步骤&#xff0c;不详细讲解&#xff0c;需要完整代码的可以自行下载。 https://download.c…

数据结构之查找详解

一、什么是查找表&#xff1f; 1.1 定义 查找表是由同一类型的数据元素构成的集合。例如电话号码簿和字典都可以看作是一张查找表。 1.2 查找表的几种操作&#xff1a; 1&#xff09;在查找表中查找某个具体的数据元素&#xff1b; 2&#xff09;在查找表中插入数据元素&am…

win10环境使用nvm安装多版本nodejs并配置环境变量

win10环境使用nvm安装多版本nodejs并配置环境变量nvm安装环境变量配置测试安装全局模块对于旧版本的node&#xff0c;手动安装npm最近使用node工程&#xff0c;需要多版本&#xff0c;并且进行切换&#xff0c;来回安装卸载不同版本的node比较麻烦&#xff0c;后面自己就简单捯…

MySQL 5.5版本的两个执行引擎

目录执行引擎引入MySQL执行引擎生成的文件MyIsamInnoDB聚簇索引与非聚簇索引稀疏索引回表覆盖索引执行引擎引入 我们真正的索引结构要去落地的时候呢&#xff0c;也就是MySQL底层BTree数据结构要去落地的话&#xff0c;那么一定要和我们的存储引擎相结合。接下来我们会说MySQL…

【游戏逆向】老飞飞怀恋魅力爱玩等老飞飞瞬移分析代码

【游戏逆向】老飞飞怀恋魅力爱玩等老飞飞瞬移分析代码 在游戏中&#xff0c;每个人物都有一个坐标。x坐标和y坐标。老飞飞也一样&#xff0c;可能有些朋友用ce找到当前的人物坐标。然后修改坐标就能达到瞬移到效果。不过有些老飞飞是无法实现的。只要瞬移就会掉客户端。今天就…

3>2,看看U.3升级了啥

关注企业级NVMe SSD的小伙伴对U.2接口一定不会感到陌生。然而&#xff0c;在U.2之外&#xff0c;还存在一种名为“U.3”的硬盘接口&#xff0c;二者外观完全相同&#xff0c;接口性能也都一样&#xff0c;甚至不少客户直接将U.3的NVMe SSD部署在U.2服务器上使用。但既然3&#…

分布式应用解决方案之一致性Hash

什么是一致性Hash 一致性Hash就是将整个hash值空间按照顺时针方向形成一个虚拟的环&#xff0c;整个环状结构就称之为Hash环。那为什么叫做一致性Hash环&#xff1f;一致性是由于Hash环应用场景一般在分布式应用服务中&#xff0c;各个服务提供者分布在hash环中&#xff0c;当某…

【Qt】一文总结新工程的创建

文章目录一、导读二、浅谈开发方式&#xff08;2-1&#xff09;C开发方式&#xff08;2-2&#xff09;QtQuick qml开发方式&#xff08;2-3&#xff09;python开发方式三、新工程创建向导下的Library四、其他项目五、其他工程项目六、Import Project选项七、总结一、导读 在使…

Linux-Find命令

目录 Find 命令格式&#xff1a; 常用查找条件 案例展示&#xff1a; Find find 命令根据预设的条件递归查找文件或目录所在位置 命令格式&#xff1a; 命令格式&#xff1a;find 查找路径 查找条件1 查找条件2 .. [-exec 处理命令 {} \; ] –exec 可接额外的命令来处理查…

【Kubernetes 企业项目实战】03、基于 Alertmanager 发送报警到多个接收方(下)

目录 一、promethues 采集 tomcat 监控数据 1.1 制作 tomcat 镜像 1.2 基于上面的镜像创建一个 tomcat 实例 1.3 采集数据 二、promethues 采集 redis 监控数据 2.1 配置一个 Redis 的 exporter 2.2 查看 Prometheus 2.3 grafana 导入模板 三、Prometheus 监控 mysql …

【微服务】Nacos 前端设计

目录 一、背景 二、选型 React 1、Vue vs React vs Angular 1.1、npm trends 2、GitHub Stats 3、根据自身情况选型 4、现状 5、小结 6、React/Vue ⽣态 三、方案 &#x1f496;微服务实战 &#x1f496; Spring家族及微服务系列文章 一、背景 我们需要提供⼀个简单…

Xilinx关于Aurora IP核仿真和使用

平台&#xff1a;vivado2017.4芯片&#xff1a;xc7k325tfbg676-2 (active)关于Aurora的开发学习。使用xilinx官方提供的IP核。官方资料&#xff0c;pg046-aurora-8b10b.pdf和pg074-aurora-64b66b-en-us-12.0.pdf。IP核的生成步骤首先在IP Catalog中搜索Aurora IP核关于此IP有两…

SpringBoot指标监控

目录 一、SpringBoot Actuator 1、简介 2、1.x与2.x的不同 3、如何使用 二、Actuator Endpoint 1、最常使用的端点 2、Health Endpoint 3、Metrics Endpoint 4、管理Endpoints 1、开启与禁用Endpoints 2、暴露Endpoints 三、定制 Endpoint 1、定制 Health 信息 2…

RepPoints原理与代码解析

paper&#xff1a;RepPoints: Point Set Representation for Object Detectioncode&#xff1a;https://github.com/microsoft/RepPoints背景在目标检测中&#xff0c;包含图像矩形区域的边界框bounding box作为处理的基本元素&#xff0c;贯穿整个检测流程&#xff0c;从ancho…

DevOps利器之一Docker

一、背景本篇文章主要阐述Docker在DevOps中的应用与价值&#xff0c;Docker部署与安装&#xff1b;因为搭建DevOps流程中所应用的工具及框架都部署到Docker&#xff0c;所以首先介绍Docker为后续做准备。Docker的主要目标是Build&#xff0c;Ship and Run Any App,Anywhere&…