0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

第十二章 SysTick——系统定时器

W55MH32 ? 来源:W55MH32 ? 作者:W55MH32 ? 2025-05-22 17:16 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

单芯片解决方案,开启全新体验——W55MH32 高性能以太网单片机

W55MH32是WIZnet重磅推出的高性能以太网单片机,它为用户带来前所未有的集成化体验。这颗芯片将强大的组件集于一身,具体来说,一颗W55MH32内置高性能Arm? Cortex-M3核心,其主频最高可达216MHz;配备1024KB FLASH与96KB SRAM,满足存储与数据处理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP协议栈、内置MAC以及PHY,拥有独立的32KB以太网收发缓存,可供8个独立硬件socket使用。如此配置,真正实现了All-in-One解决方案,为开发者提供极大便利。

在封装规格上,W55MH32 提供了两种选择:QFN100和QFN68。

W55MH32L采用QFN100封装版本,尺寸为12x12mm,其资源丰富,专为各种复杂工控场景设计。它拥有66个GPIO、3个ADC、12通道DMA、17个定时器、2个I2C、5个串口、2个SPI接口(其中1个带I2S接口复用)、1个CAN、1个USB2.0以及1个SDIO接口。如此丰富的外设资源,能够轻松应对工业控制中多样化的连接需求,无论是与各类传感器、执行器的通信,还是对复杂工业协议的支持,都能游刃有余,成为复杂工控领域的理想选择。 同系列还有QFN68封装的W55MH32Q版本,该版本体积更小,仅为8x8mm,成本低,适合集成度高的网关模组等场景,软件使用方法一致。更多信息和资料请进入http://www.w5500.com/网站或者私信获取。

此外,本W55MH32支持硬件加密算法单元,WIZnet还推出TOE+SSL应用,涵盖TCP SSL、HTTP SSL以及 MQTT SSL等,为网络通信安全再添保障。

为助力开发者快速上手与深入开发,基于W55MH32L这颗芯片,WIZnet精心打造了配套开发板。开发板集成WIZ-Link芯片,借助一根USB C口数据线,就能轻松实现调试、下载以及串口打印日志等功能。开发板将所有外设全部引出,拓展功能也大幅提升,便于开发者全面评估芯片性能。

若您想获取芯片和开发板的更多详细信息,包括产品特性、技术参数以及价格等,欢迎访问官方网页:http://www.w5500.com/,我们期待与您共同探索W55MH32的无限可能。

wKgZPGgbOfaANhwzACodXd3sVzg463.png

第十二章 SysTick——系统定时器

本章参考资料《Cortex-M3内核编程手册》-4.5 章节SysTick Timer(STK),和4.48章节SHPRx, 其中STK这个章节有SysTick的简介和寄存器的详细描述。因为SysTick是属于CM3内核的外设, 有关寄存器的定义和部分库函数都在core_CM3.h这个头文件中实现。所以学习SysTick的时候可以参考这两个资料,一个是文档,一个是源码。

1 SysTick简介

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

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

2 SysTick寄存器介绍

SysTick—系统定时器有4个寄存器,简要介绍如下。在使用SysTick产生定时的时候,只需要配置前三个寄存器,最后一个校准寄存器不需要使用。

寄存器名称 寄存器描述
CTRL SysTick 控制及状态寄存器
LOAD SysTick 重装载数值寄存器
VAL SysTick 当前数值寄存器
CALIB SysTick 校准数值寄存器
位段 名称 类型 复位值 描述
16 COUNTFLAG R/W 0 如果在上次读取本寄存器后,SysTick 已经计到了 0,则该位为 1。
2 CLKSOURCE R/W 0 时钟源选择位,0=AHB/8,1 = 处理器时钟 AHB
1 TICKINT R/W 0 1=SysTick 倒数计数到 0 时产生 SysTick 异常请求,0 = 数到 0 时无动作。也可通过读取 COUNTFLAG 标志位确定计数器是否递减到 0
0 ENABLE R/W 0 SysTick 定时器的使能位
位段 名称 类型 复位值 描述
23:0 RELOAD R/W 0 当倒数计数至零时,将被重装载的值
位段 名称 类型 复位值 描述
23:0 CURRENT R/W 0 读取时返回当前倒计数的值,写它则使之清零,同时还会清除在 SysTick 控制及状态寄存器中的 COUNTFLAG 标志
位段 名称 类型 复位值 描述
31 NOREF R 0 NOREF flag. Reads as zero. Indicates that a separate reference clock is provided.
The frequency of this clock is HCLK/8
30 SKEW R 1 Reads as one. Calibration value for the 1 ms inexact timing is not known because TENMS is not known. This can affect the suitability of SysTick as a software real time clock
23:0 TENMS R 0 Indicates the calibration value when the SysTick counter runs on HCLK max/8 as external clock.
The value is product dependent, refer to the Product Reference Manual, SysTick Calibration Value section. When HCLK is at max frequency, SysTick period is 1ms. If calibration info unknown, calculate from processor/external clock frequency.

系统定时器的校准数值寄存器在定时实验中不需要用到。有关各个位的描述这里引用手册里面的英文版本,比较晦涩难懂, 暂时不知道这个寄存器用来干什么。有研究过的朋友可以交流,起个抛砖引玉的作用。

3 SysTick定时介绍

3.1 代码分析

SysTick 属于内核的外设,有关的寄存器定义和库函数都在内核相关的库文件core_cm3.h中。

SysTick配置库函数

代码清单:SysTick-1SysTick配置库函数

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
    // 不可能的重装载值,超出范围
    if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) {
        return (1UL);
    }

    // 设置重装载寄存器
    SysTick->LOAD  = (uint32_t)(ticks - 1UL);

    // 设置中断优先级
    NVIC_SetPriority (SysTick_IRQn, (1UL VAL   = 0UL;

    // 设置系统定时器的时钟源为AHBCLK=72M
    // 使能系统定时器中断
    // 使能定时器
    SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                    SysTick_CTRL_TICKINT_Msk   |
                    SysTick_CTRL_ENABLE_Msk;
    return (0UL);
}

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

SysTick_Config()库函数主要配置了SysTick中的三个寄存器:LOAD、VAL和CTRL,有关具体的部分看代码注释即可。

配置SysTick中断优先级

在SysTick_Config()库函数还调用了固件库函数NVIC_SetPriority()来配置系统定时器的中断优先级,该库函数也在core_m3.h中定义,原型如下:

__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
    if ((int32_t)IRQn < 0) {
        SCB-?>SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] =
        (uint8_t)((priority IP[((uint32_t)(int32_t)IRQn)] =
        (uint8_t)((priority 

函数首先先判断形参IRQn的大小,如果是小于0,则表示这个是系统异常,系统异常的优先级由内核外设SCB的寄存器SHPRx控制, 如果大于0则是外部中断,外部中断的优先级由内核外设NVIC中的IPx寄存器控制。

因为SysTick属于内核外设,跟普通外设的中断优先级有些区别,并没有抢占优先级和子优先级的说法。在W55MH32中, 内核外设的中断优先级由内核SCB这个外设的寄存器:SHPRx(x=1.2.3)来配置。有关SHPRx寄存器的详细描述可参考《Cortex-M3内核编程手册》4.4.8章节。 下面我们简单介绍下这个寄存器。

SPRH1-SPRH3是一个32位的寄存器,但是只能通过字节访问,每8个字段控制着一个内核外设的中断优先级的配置。在W55MH32中, 只有位7:4这高四位有效,低四位没有用到,所以内核外设的中断优先级可编程为:0~15,只有16个可编程优先级,数值越小,优先级越高。 如果软件优先级配置相同,那就根据他们在中断向量表里面的位置编号来决定优先级大小,编号越小,优先级越高。

异常 字段 寄存器描述
Memory management fault PRI_4 SHPR1
Bus fault PRI_5 SHPR1
Usage fault PRI_6 SHPR1
SVCall PRI_11 SHPR2
PendSV PRI_14 SHPR3
SysTick PRI_15 SHPR3

如果要修改内核外设的优先级,只需要修改下面三个寄存器对应的某个字段即可:

wKgZPGgu6jSAd1UmAAClDQnSxDs974.pngwKgZPGgu6jSAYx7_AAFuK83AoaY704.pngwKgZO2gu6jSAJp_9AACUiKae9_g001.png

在系统定时器中,配置优先级为(1UL << __NVIC_PRIO_BITS) - 1UL), 其中宏__NVIC_PRIO_BITS为4,那计算结果就等于15, 可以看出系统定时器此时设置的优先级在内核外设中是最低的,如果要修改优先级则修改这个值即可,范围为:0~15。

// 设置系统定时器中断优先级
NVIC_SetPriority (SysTick_IRQn, (1UL 

但是,问题来了,刚刚我们只是学习了内核的外设的优先级配置。如果我同时使用了systick和片上外设呢?而且片上外设也刚好需要使用中断, 那systick的中断优先级跟外设的中断优先级怎么设置?会不会因为systick是内核里面的外设,所以它的中断优先级就一定比内核之外的外设的优先级高?

从《W55MH32中断应用概览》这章我们知道,外设在设置中断优先级的时候,首先要分组,然后设置抢占优先级和子优先级。 而systick这类内核的外设在配置的时候,只需要配置一个寄存器即可,取值范围为0~15。既然配置方法不同,那如何区分两者的优先级?下面举例说明。

比如配置一个外设的中断优先级分组为2,抢占优先级为1,子优先级也为1,systick的优先级为固件库默认配置的15。 当我们比较内核外设和片上外设的中断优先级的时候,我们只需要抓住NVIC的中断优先级分组不仅对片上外设有效,同样对内核的外设也有效。 我们把systick的优先级15转换成二进制值就是1111(0b),又因为NVIC的优先级分组2,那么前两位的11(0b)就是3,后两位的11(0b)也是3。 无论从抢占还是子优先级都比我们设定的外设的优先级低。如果当两个的软件优先级都配置成一样,那么就比较他们在中断向量表中的硬件编号,编号越小,优先级越高。

SysTick初始化函数

代码清单:SysTick-2 SysTick初始化函数

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

SysTick初始化函数由用户编写,里面调用了SysTick_Config()这个固件库函数, 通过设置该固件库函数的形参,就决定了系统定时器经过多少时间就产生一次中断。

SysTick中断时间的计算

SysTick定时器的计数器是向下递减计数的,计数一次的时间TDEC=1/CLKAHB, 当重装载寄存器中的值VALUELOAD减到0的时候,产生中断, 可知中断一次的时间TINT=VALUELOAD * TDEC= VALUELOAD/CLKAHB, 其中CLKAHB =72MHZ。如果设置VALUELOAD为72, 那中断一次的时间TINT=72/72M=1us。 不过1us的中断没啥意义,整个程序的重心都花在进出中断上了,根本没有时间处理其他的任务。

SysTick_Config(SystemCoreClock / 100000)

SysTick_Config()的形我们配置为SystemCoreClock / 100000=72M/100000=720, 从刚刚分析我们知道这个形参的值最终是写到重装载寄存器LOAD中的, 从而可知我们现在把SysTick定时器中断一次的时间TINT=720/72M=10us。

SysTick定时时间的计算

当设置好中断时间TINT后,我们可以设置一个变量t,用来记录进入中断的次数, 那么变量t乘以中断的时间TINT就可以计算出需要定时的时间。

SysTick定时函数

当设置好中断时间TINT后,我们可以设置一个变量t,用来记录进入中断的次数, 那么变量t乘以中断的时间TINT就可以计算出需要定时的时间。

SysTick定时函数

现在我们定义一个微秒级别的延时函数,形参为nTime,当用这个形参乘以中断时间TINT就得出我们需要的延时时间, 其中TINT我们已经设置好为10us。关于这个函数的具体调用看注释即可。

/**
* @brief   us延时程序,10us为一个单位
* @param
*   @arg nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
* @retval  无
*/
void Delay_us(__IO u32 nTime)
{
    TimingDelay = nTime;

    while (TimingDelay != 0);
}

函数Delay_us()中我们等待TimingDelay为0,当TimingDelay为0的时候表示延时时间到。变量TimingDelay在中断函数中递减, 即SysTick每进一次中断即10us的时间TimingDelay递减一次。

SysTick中断服务函数

void SysTick_Handler(void)
{
    TimingDelay_Decrement();
}

中断复位函数调用了另外一个函数TimingDelay_Decrement(),原型如下:

/**
* @brief  获取节拍程序
* @param  无
* @retval 无
* @attention  在 SysTick 中断函数 SysTick_Handler()调用
*/
void TimingDelay_Decrement(void)
{
    if (TimingDelay != 0x00) {
        TimingDelay--;
    }
}

TimingDelay的值等于延时函数中传进去的nTime的值,比如nTime=100000,则延时的时间等于100000*10us=1s。

我们知道,systick的counter从reload值往下递减到0的时候,CTRL寄存器的位16:countflag会置1,且读取该位的值可清0, 所有我们可以使用软件查询的方法来实现延时。具体代码见 代码清单:SysTick-3 和 代码清单:SysTick-4 ,我敢肯定这样的写法, 初学者肯定会更喜欢,因为它直接,套路浅。

代码清单:SysTick-3 systick 微秒级延时

void SysTick_Delay_Us( __IO uint32_t us)
{
    uint32_t i;
    SysTick_Config(SystemCoreClock/1000000);

    for (i=0; iCTRL)&(1CTRL &=~SysTick_CTRL_ENABLE_Msk;
}

代码清单:SysTick-4 systick 毫秒级延时

void SysTick_Delay_Ms( __IO uint32_t ms)
{
    uint32_t i;
    SysTick_Config(SystemCoreClock/1000);

    for (i=0; iCTRL)&(1CTRL &=~ SysTick_CTRL_ENABLE_Msk;
}

在这两个微秒和毫秒级别的延时函数中,我们还是调用了SysTick_Config这个固件库函数,有关这个函数的说明具体见 代码清单:SysTick-5 。 配套代码注释理解即可。其中SystemCoreClock是一个宏,大小为72000000,如果不想使用这个宏,也可以直接改成数字。

代码清单:SysTick-5 systick 配置函数

// 这个 固件库函数 在 core_cm3.h中
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
    // reload 寄存器为24bit,最大值为2^24
    if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);

    // 配置 reload 寄存器的初始值
    SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;

    // 配置中断优先级为 1VAL   = 0;

    // 配置systick 的时钟为 72M
    // 使能中断
    // 使能systick
    SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                    SysTick_CTRL_TICKINT_Msk   |
                    SysTick_CTRL_ENABLE_Msk;
    return (0);
}

WIZnet 是一家无晶圆厂半导体公司,成立于 1998 年。产品包括互联网处理器 iMCU?,它采用 TOE(TCP/IP 卸载引擎)技术,基于独特的专利全硬连线 TCP/IP。iMCU? 面向各种应用中的嵌入式互联网设备。

WIZnet 在全球拥有 70 多家分销商,在香港、韩国、美国设有办事处,提供技术支持和产品营销。

香港办事处管理的区域包括:澳大利亚、印度、土耳其、亚洲(韩国和日本除外)。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6068

    文章

    45032

    浏览量

    652191
  • 定时器
    +关注

    关注

    23

    文章

    3302

    浏览量

    119403
  • WIZnet
    +关注

    关注

    3

    文章

    20

    浏览量

    42475
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    数据采集光盘实例第六第十二章

    数据采集光盘实例第六第十二章
    发表于 06-28 21:17

    明德扬视频分享点拨FPGA课程---第十二章??学习自检方法

    第十二章学习自检方法1. 波形对比方法http://yunpan.cn/cjZTiDA9pY56x访问密码 c359
    发表于 11-13 11:01

    「正点原子STM32Mini板资料连载」第十二章 定时器中断实验

    1)实验平台:正点原子stm32mini 开发板2)摘自《正点原子STM32 不完全手册(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子第十二章 定时器中断实验这一,我们将向大家介绍
    发表于 04-08 10:21

    SysTick系统定时器

    程序简介 -工程名称:SysTick系统定时器 -实验平台: 秉火STM32 F429 开发板 -MDK版本:5.16 -ST固件库版本:1.5.1 【 !】功能简介: 控制开发板上的RGB彩灯
    发表于 12-12 19:12 ?7次下载

    【正点原子Linux连载】第十二章官方SDK移植试验-摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    【正点原子Linux连载】第十二章官方SDK移植试验-摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0
    发表于 11-23 17:51 ?11次下载
    【正点原子Linux连载】<b class='flag-5'>第十二章</b>官方SDK移植试验-摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    STM32 Systick系统定时器

    @STM32 Systick系统定时器#简介在之前的实验中,我们只用到的delay函数通过while语句做循环的方式来占用时间,达到延时的目的。但是这种方式延时的时间不好把控,无法应用于更加
    发表于 11-25 10:06 ?6次下载
    STM32 <b class='flag-5'>Systick</b><b class='flag-5'>系统</b><b class='flag-5'>定时器</b>

    STM32入门(十五)----SysTick系统定时器

    SysTick系统定时器SysTick简介SysTick框图SysTick
    发表于 12-01 15:06 ?8次下载
    STM32入门(十五)----<b class='flag-5'>SysTick</b><b class='flag-5'>系统</b><b class='flag-5'>定时器</b>

    SysTick 定时器

    SysTick定时器来实现延时,可以不占用系统定时器,节约资源。由于SysTick是在CPU核内部实现的,跟MCU外设无关,因此它的代码可
    发表于 12-05 14:51 ?9次下载
    <b class='flag-5'>SysTick</b> <b class='flag-5'>定时器</b>

    Stm32入门——Systick定时器

    Stm32入门——Systick定时器Systick定时器是什么?从原理上来说,Systick定时器
    发表于 12-07 17:51 ?12次下载
    Stm32入门——<b class='flag-5'>Systick</b><b class='flag-5'>定时器</b>

    STM32笔记(七)---Systick系统定时器

    SysTick系统定时器文章目录SysTick系统定时器一、 概念1-1
    发表于 12-23 20:01 ?1次下载
    STM32笔记(七)---<b class='flag-5'>Systick</b><b class='flag-5'>系统</b><b class='flag-5'>定时器</b>

    19-SysTick系统定时器

    SysTick 简介SysTick系统定时器是属于CM3 内核中的一个外设,内嵌在NVIC 中。系统
    发表于 01-17 09:54 ?1次下载
    19<b class='flag-5'>章</b>-<b class='flag-5'>SysTick</b>—<b class='flag-5'>系统</b><b class='flag-5'>定时器</b>

    systick定时器 延时计时

    systick定时器是属于cortex M内核的外设,专门为RTOS的系统时钟节拍设计的。systick是cortex M内核自带的,因此和debug调试接口一样,与单片机型号和厂商无
    发表于 01-18 10:28 ?7次下载
    <b class='flag-5'>systick</b><b class='flag-5'>定时器</b> 延时计时

    【STM32】SysTick滴答定时器(delay延时函数讲解)

    Systick定时器,是一个简单的定时器,对于CM3、CM4内核芯片,都有Systick定时器Syst
    发表于 02-10 10:35 ?13次下载
    【STM32】<b class='flag-5'>SysTick</b>滴答<b class='flag-5'>定时器</b>(delay延时函数讲解)

    RK3568驱动指南|第十二篇 GPIO子系统-第135 GPIO子系统与pinctrl子系统相结合实验

    RK3568驱动指南|第十二篇 GPIO子系统-第135 GPIO子系统与pinctrl子系统相结合实验
    的头像 发表于 05-23 13:47 ?406次阅读
    RK3568驱动指南|<b class='flag-5'>第十二</b>篇 GPIO子<b class='flag-5'>系统</b>-第135<b class='flag-5'>章</b> GPIO子<b class='flag-5'>系统</b>与pinctrl子<b class='flag-5'>系统</b>相结合实验

    RK3568驱动指南|第十二篇 GPIO子系统-第130 GPIO的调试方法

    RK3568驱动指南|第十二篇 GPIO子系统-第130 GPIO的调试方法
    的头像 发表于 06-03 11:32 ?594次阅读
    RK3568驱动指南|<b class='flag-5'>第十二</b>篇 GPIO子<b class='flag-5'>系统</b>-第130<b class='flag-5'>章</b> GPIO的调试方法