SysTick系统定时器(功能框图和优先级配置)

SysTick定时器作为CM3内核的一部分,广泛应用于基于CM3的单片机中,用于产生时基,维持操作系统心跳。本文详细介绍了SysTick定时器的功能、工作原理、寄存器配置及中断优先级设置,通过具体实例展示了如何使用SysTick定时器实现精确的时间间隔中断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SysTick系统定时器(功能框图和优先级配置)

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

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

1

    SysTick的执行过程:counter在时钟的驱动下,从reload初值开始往下递减计数到0(在递减的过程中值可以在STK_VAL中查看到),产生中断和置位COUNTFLAG标志。然后又从reload 值开始重新递减计数,如此循环。

 

SysTick相关寄存器

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

 2

 

SysTick寄存器结构体

      SysTick寄存器(在固件库文件:core_cm3.h中定义)

复制代码

typedef struct{
   _IO uint32_t  CTRL;      /*控制及状态寄存器*/
  _IO uint32_t   LOAD;      /*重装载数值寄存器*/
  _IO uint32_t   VAL;       /*当前数值寄存器*/
 _IO uint32_t   CALIB;      /*校准寄存器*/


}

复制代码

SysTick库函数

      SysTick配置库函数(在固件库文件:core_cm3.h中定义)

复制代码

__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_PRIO_BITS 4(1111)系统定时器此时设置的优先级在内核外设中是最低的
 NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);

 // 设置当前数值寄存器
 SysTick->VAL = 0UL;

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

复制代码

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

配置 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 << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
 } else {
 NVIC->IP[((uint32_t)(int32_t)IRQn)] =(uint8_t)((priority << (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
 }
 }

复制代码

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

      因为 SysTick 属于内核外设,跟普通外设的中断优先级有些区别,并没有抢占优先级和子优先级的说法。在 STM32F103 中,内核外设的中断优先级由内核 SCB 这个外设的寄存器:SHPRx(x=1.2.3)来配置。

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

     

外设中断优先级和内核外设优先级比较

     内核优先级是不分抢占优先级和子优先级,但不是内核外设的优先级就一定比外设的优先级高.

    判别方法:根据内核外设设置优先级0-15的值,把内核外设的中断优先级的四个位按照外设的中断优先级来分组来解析即可,即人为的分出抢占优先级和子优先级。

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

SysTick 初始化函数

复制代码

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定时时间计算

    时间单位换算: 1s = 1000ms = 1000 000 us = 1000 000 000ns

          t = reload * ( 1/clk )

  1. Clk = 72M时,t = (72) *(1/ 72 M )= 1US
  2. Clk = 72M时,t = (72000) *(1/ 72 M )= 1MS
<think>首先,用户的问题是:“我想配置STM32F103C8T6最小系统板的内部中断及其优先级 请问STM32F103C8T6 配置内部中断设置中断优先级”。我需要基于提供的引用系统指令来回答。 系统指令包括: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。 参考引用: - 引用[1]: 关于STM32F103C8T6中断系统,包括中断示意图、中断过程、中断数量、中断向量表、中断框图、中断管理的结构(AFIO、EXTI、NVIC)等。 - 引用[2]: 关于STM32F103C8T6中断编程,包括Encoder.h文件、初始化函数中断编程建议。 - 引用[3]: 关于外部中断的配置与使用,包括GPIO_EventOutputConfigGPIO_EventOutputCmd函数。 用户的问题是关于“内部中断”的配置设置中断优先级。在STM32上下文中,“内部中断”可能指的是内核中断或系统中断,如SysTick定时器中断或PendSV中断,而不是外部中断(如GPIO中断)。用户指定了“内部中断”,所以我需要专注于内部中断。 在STM32F103C8T6中,内部中断包括: - SysTick定时器中断 - PendSV中断 - 其他内核中断 中断优先级是通过NVIC(Nested Vectored Interrupt Controller)来设置的。 从引用中: - 引用[1]提到NVIC、中断优先级、中断嵌套等。 - 引用[2]提到中断编程建议。 - 引用[3]是关于外部中断的,可能不直接相关,但可以借鉴配置流程。 我需要构建一个清晰的、逐步的指南来配置内部中断设置优先级。 步骤大纲: 1. 理解内部中断:解释什么是内部中断,并列出常见的内部中断源。 2. 配置中断:初始化相关外设(如SysTick)。 3. 设置中断优先级:使用NVIC。 4. 编写中断服务例程(ISR)。 5. 使能中断。 具体步骤: - 对于SysTick中断: - 配置SysTick定时器。 - 设置SysTick中断优先级。 - 编写SysTick_Handler。 - 对于其他内部中断,类似。 中断优先级设置: - NVIC_IRQChannelPreemptionPriorityNVIC_IRQChannelSubPriority。 - 使用NVIC_Init函数或直接操作寄存器。 从引用[1]中,有中断管理的结构,包括NVIC。 从引用[2]中,有中断编程建议。 在回答中,我需要自然地添加引用标识。 最后,生成相关问题。 确保回答结构清晰: - 介绍内部中断。 - 逐步配置。 - 代码示例(用代码块)。 - 总结。 使用中文回答。 现在,构建回答:</think>### STM32F103C8T6内部中断配置优先级设置指南 在STM32F103C8T6微控制器中,内部中断(如SysTick定时器中断、PendSV中断等)是内核级事件,由NVIC(Nested Vectored Interrupt Controller)统一管理。配置过程包括初始化中断源、设置优先级、编写中断服务例程(ISR),并最终使能中断。以下步骤基于STM32标准库(如STM32F10x标准外设库)逐步说明,确保代码可移植性可靠性。参考了STM32中断系统架构NVIC工作原理[^1]。 #### 步骤1: 理解内部中断源 STM32F103C8T6的内部中断主要指内核中断,常见源包括: - **SysTick定时器中断**: 系统节拍定时器,用于操作系统调度或延时。 - **PendSV中断**: 可挂起的系统服务中断,常用于上下文切换。 - **其他内核中断**: 如HardFault、MemManage等(通常由错误触发)。 这些中断通过NVIC管理,优先级范围为0-15(数字越小优先级越高),支持中断嵌套[^1]。 #### 步骤2: 配置中断源(以SysTick为例) 首先,初始化内部中断源。例如,配置SysTick定时器: - 设置重载值(Reload Value),决定中断频率。 - 使能SysTick中断。 使用标准库函数`SysTick_Config()`简化配置。 ```c #include "stm32f10x.h" // 包含设备头文件 void SysTick_Init(uint32_t ticks) { // 配置SysTick定时器:设置重载值并启用中断 if (SysTick_Config(ticks)) { // 参数ticks = SystemCoreClock / 频率(Hz) while (1); // 配置失败处理 } // 可选:设置SysTick优先级(步骤3中详述) } ``` - **说明**: `SysTick_Config()`函数自动设置重载值、选择时钟源(HCLK/8),并使能中断。频率计算:例如,SystemCoreClock=72MHz时,`ticks = 72000000 / 1000` 产生1ms中断[^2]。 #### 步骤3: 设置中断优先级 所有中断优先级通过NVIC配置。STM32F103C8T6使用4位优先级分组(Preemption PrioritySub Priority),需先设置优先级分组,再为每个中断通道指定优先级。 - **优先级分组设置**: 使用`NVIC_PriorityGroupConfig()`定义抢占优先级优先级的位数。 - **中断优先级配置**: 使用`NVIC_InitTypeDef`结构体初始化。 ```c void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; // 步骤3.1: 设置优先级分组(例如,组2:2位抢占优先级,2位子优先级) NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 步骤3.2: 配置SysTick中断优先级 NVIC_InitStructure.NVIC_IRQChannel = SysTick_IRQn; // 中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级(0最高) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能通道 NVIC_Init(&NVIC_InitStructure); // 类似地,可配置其他内部中断(如PendSV) // NVIC_InitStructure.NVIC_IRQChannel = PendSV_IRQn; // ...(设置优先级使能) } ``` - **关键点**: - 抢占优先级高的中断可打断低优先级中断(嵌套)。 - 优先级值范围:0-3(当分组为Group2时),值越小优先级越高[^1]。 - 中断编程建议:避免在ISR中执行耗时操作,优先使用硬件功能[^2]。 #### 步骤4: 编写中断服务例程(ISR) 在启动文件(如`startup_stm32f10x_md.s`)中预定义了中断向量表。需在用户代码中实现ISR函数。 - **SysTick ISR示例**: ```c void SysTick_Handler(void) { // 函数名必须与向量表一致 // 中断处理逻辑(例如,更新系统时钟计数器) static uint32_t tick = 0; tick++; // 添加其他任务... } ``` - **注意**: ISR函数应简短高效,避免阻塞。使用`__attribute__((weak))`在库中已定义弱符号,可直接覆盖[^1]。 #### 步骤5: 使能全局中断 在`main()`函数中初始化配置,并开启全局中断。 ```c int main(void) { // 初始化系统时钟等 SystemInit(); // 配置中断源优先级 SysTick_Init(72000); // 假设1ms中断(72MHz系统时钟) NVIC_Configuration(); // 使能全局中断 __enable_irq(); while (1) { // 主循环代码 } } ``` - **调试提示**: 使用调试器(如ST-Link)检查NVIC寄存器(如`NVIC->ISER`)确认中断使能状态[^1]。 #### 总结 - **核心配置流程**: 初始化中断源 → 设置NVIC优先级分组 → 配置中断通道优先级 → 编写ISR → 使能全局中断。 - **可靠性注意**: 内部中断无需GPIO配置(区别于外部中断),但需确保时钟使能(如SysTick使用内核时钟)。优先级分组应在程序开始时统一设置,避免冲突[^2]。 - **性能优化**: 对于实时应用,可调整优先级减少中断延迟,例如SysTick设为最高优先级[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值