关于中断嵌套中的SysTick中断

中断优先级组

  • STM32用4个比特位来指定中断源的优先级,并可分为5个优先级组(Cortex-M3中定义了8个比特位用于设置中断源的优先级,并且允许具有较少中断源时使用较少的寄存器位指定中断源的优先级)。
//stm32f10x.h

#define __NVIC_PRIO_BITS          4 /*!< STM32 uses 4 Bits for the Priority Levels    */
//misc.h

/**
@code  
 The table below gives the allowed values of the pre-emption priority and subpriority according
 to the Priority Grouping configuration performed by NVIC_PriorityGroupConfig function
  ============================================================================================================================
    NVIC_PriorityGroup   | NVIC_IRQChannelPreemptionPriority | NVIC_IRQChannelSubPriority  | Description
  ============================================================================================================================
   NVIC_PriorityGroup_0  |                0                  |            0-15             |   0 bits for pre-emption priority
                         |                                   |                             |   4 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------
   NVIC_PriorityGroup_1  |                0-1                |            0-7              |   1 bits for pre-emption priority
                         |                                   |                             |   3 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------    
   NVIC_PriorityGroup_2  |                0-3                |            0-3              |   2 bits for pre-emption priority
                         |                                   |                             |   2 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------    
   NVIC_PriorityGroup_3  |                0-7                |            0-1              |   3 bits for pre-emption priority
                         |                                   |                             |   1 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------    
   NVIC_PriorityGroup_4  |                0-15               |            0                |   4 bits for pre-emption priority
                         |                                   |                             |   0 bits for subpriority                       
  ============================================================================================================================
@endcode
*/

抢占优先级和响应优先级

执行顺序(同时到达)

  • 抢占优先级不同时,抢占优先级高的先执行。
  • 抢占优先级相同时,响应优先级高的先执行。
  • 抢占优先级和响应优先级相同时,根据中断向量表的顺序执行。

打断规则(先后到达)

  • 低抢占优先级在中断处理时,高抢占优先级可以被响应(中断的嵌套)。
  • 相同抢占优先级在中断处理时,不管响应优先级是否高于前者,都不可打断前者的执行(需要等到前者处理完才可被处理)。

SysTick的中断优先级

  • 当我们调用SysTick_Config()设置装载寄存器时,SysTick_Config()已经为我们将SysTick的中断优先级设置为最低。
  • 以下是SysTick_Config()的实现。
//core_cm3.h

/**
 * @brief  Initialize and start the SysTick counter and its interrupt.
 *
 * @param   ticks   number of ticks between two interrupts
 * @return  1 = failed, 0 = successful
 *
 * Initialise the system tick timer and its interrupt and start the
 * system tick timer / counter in free running mode to generate 
 * periodical interrupts.
 */
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);            /* Reload value impossible */

  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Cortex-M0 System Interrupts */
  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 */
}
  • 主要是看NVIC_SetPriority(SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1)这一句。这一句设置了SysTick_IRQn的优先级。
  • 以下是NVIC_SetPriority()的实现。
//core_cm3.h

/**
 * @brief  Set the priority for an interrupt
 *
 * @param  IRQn      The number of the interrupt for set priority
 * @param  priority  The priority to set
 *
 * Set the priority for the specified interrupt. The interrupt 
 * number can be positive to specify an external (device specific) 
 * interrupt, or negative to specify an internal (core) interrupt.
 *
 * Note: The priority cannot be set for every core interrupt.
 */
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
  if(IRQn < 0) {
    SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */
  else {
    NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff);    }        /* set Priority for device specific Interrupts  */
}
  • (1<<__NVIC_PRIO_BITS) - 1)((1<<4) - 1),即1111(b)。故SysTick的中断优先级被设置为不管是哪个优先级分组始终是最低的。
  • 如下表所示。
优先级分组抢占优先级响应优先级
NVIC_PriorityGroup_0-15
NVIC_PriorityGroup_117
NVIC_PriorityGroup_233
NVIC_PriorityGroup_371
NVIC_PriorityGroup_415-

配置SysTick的中断优先级

  • 只需要在使用SysTick_Config()后使用NVIC_SetPriority(SysTick_IRQn, xx) 配置SysTick的中断优先级。
  • 需要注意的是,NVIC_SetPriority()中的优先级是4比特位的数(0~15),需要根据优先级组选择合适的优先级。
  • 如下代码将SysTick的中断优先级始终设置为最高优先级(设置任何优先级分组时都是最高优先级)。
NVIC_SetPriority(SysTick_IRQn, 0); 
<think>好的,用户想了解如何在GD32F103上使用SysTick实现中断。首先,我需要回忆一下GD32F103的基本信息。GD32F103是基于Arm Cortex-M3内核的微控制器,而SysTick是Cortex-M内核中的一个系统定时器,常用于产生定时中断,比如用于操作系统的时间片调度或者普通的定时任务。 首先,SysTick的基本原理。SysTick是一个24位的递减计数器,时钟源可以选择内核时钟(HCLK)或者HCLK的8分频。用户需要配置重装载值(LOAD),当计数器减到0时,会触发中断,并自动重新加载LOAD的值重新开始递减。 接下来,GD32F103的具体配置步骤可能涉及几个方面:选择时钟源、设置重装载值、启用中断、启动计数器。此外,还需要编写中断服务函数(ISR),并在其中处理相关任务,比如更新计数器或者执行周期性操作。 需要注意的地方包括:计算正确的重装载值以实现所需的定时周期,比如如果系统时钟是108MHz,想要1ms的中断,那么重装载值应该是108000-1,因为计数器从LOAD递减到0需要LOAD+1个周期。同时,要确保在SysTick配置中启用中断,并且在中断服务函数中清除中断标志,否则可能会一直进入中断。 可能用户会遇到的问题包括中断不触发,这时候需要检查时钟源是否正确,重装载值是否过大(超过24位),或者中断是否被启用。另外,中断服务函数的名称是否正确,是否在向量表中正确注册,比如在GD32中,SysTick中断处理函数通常命名为SysTick_Handler,需要在启动文件中确认该名称是否正确,或者是否需要用户自行定义。 此外,GD32的库函数可能会有特定的配置函数,比如使用库函数中的systick_config(),这个函数可能会封装LOAD值和时钟源的配置,以及中断的启用。用户可能需要查阅GD32的标准外设库文档,确认具体的函数调用方式。 还有,用户可能希望了解如何在中断服务函数中执行任务,比如翻转GPIO引脚来测试中断是否正常工作,或者进行软件计时器的更新。这时候需要注意中断服务函数应尽量简短,避免长时间的操作影响系统性能。 总结步骤可能是:初始化系统时钟,配置SysTick的时钟源和重装载值,启用中断,编写中断服务函数,最后启动SysTick计数器。同时需要提醒用户注意优先级设置,虽然SysTick通常用于系统核心功能,但如果有其他中断,可能需要调整优先级。 现在需要将这些思路整理成结构化的回答,分步骤说明配置过程,并给出示例代码,帮助用户理解具体实现。同时需要指出常见问题和注意事项,确保用户能够正确应用。</think>SysTick是Arm Cortex-M内核中的系统定时器,常用于生成周期性中断。在GD32F103(基于Cortex-M3)中,通过SysTick中断可实现精确计时、任务调度等功能。以下是关键实现步骤: --- ### **一、SysTick中断配置步骤** #### 1. **设置时钟源** ```c SysTick_CTRL_ENABLE_Msk; // 使能SysTick SysTick_CTRL_CLKSOURCE_Msk; // 选择时钟源:HCLK(默认)或 HCLK/8 ``` - 若系统时钟为108MHz,选择HCLK可提高定时精度。 #### 2. **计算重装载值(LOAD)** 计算公式: $$ \text{LOAD} = (\text{系统时钟频率} \times \text{中断周期}) - 1 $$ - 例:1ms中断周期,系统时钟108MHz: $$ \text{LOAD} = 108\text{MHz} \times 0.001\text{s} - 1 = 107999 $$ #### 3. **初始化SysTick** ```c SysTick_Config(LOAD_VALUE); // 自动配置LOAD并启用中断 ``` 或手动配置: ```c SysTick->LOAD = LOAD_VALUE; // 设置重装载值 SysTick->VAL = 0; // 清空当前计数器 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; // 启用计数器及中断 ``` #### 4. **编写中断服务函数(ISR)** ```c void SysTick_Handler(void) { // 执行周期性任务(如翻转LED、更新计时器等) static uint32_t tick = 0; tick++; // 清除中断标志(部分芯片需手动清除) SysTick->CTRL &= ~SysTick_CTRL_COUNTFLAG_Msk; } ``` #### 5. **启用全局中断** ```c __enable_irq(); // 在main()中启用全局中断 ``` --- ### **二、完整示例代码** ```c #include "gd32f10x.h" void SysTick_Handler(void) { static uint32_t ticks = 0; ticks++; // 示例:每1000次中断(1秒)翻转LED if (ticks % 1000 == 0) { gpio_bit_write(GPIOC, GPIO_PIN_13, (BIT_STATUS)(1 - gpio_input_bit_get(GPIOC, GPIO_PIN_13))); } SysTick->CTRL &= ~SysTick_CTRL_COUNTFLAG_Msk; // 清除标志 } int main(void) { // 初始化系统时钟(假设配置为108MHz) rcu_clock_freq_set(RCU_CKSYSSRC_PLL, RCU_PLLSRC_HXTAL_8M, 108); // 初始化LED(PC13) rcu_periph_clock_enable(RCU_GPIOC); gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13); // 配置SysTick(1ms中断SysTick_Config(108000000 / 1000 - 1); __enable_irq(); // 启用全局中断 while (1) { // 主循环可执行低优先级任务 } } ``` --- ### **三、常见问题与注意事项** 1. **中断未触发** - 检查`LOAD`是否超过24位最大值(0xFFFFFF)。 - 确认中断服务函数名称**必须为`SysTick_Handler`**(与启动文件一致)。 - 确保全局中断已启用(`__enable_irq()`)。 2. **中断频率偏差** - 确认系统时钟频率配置正确(如使用外部晶振需稳定起振)。 - 若使用HCLK/8,需调整计算公式: $$ \text{LOAD} = (\frac{\text{系统时钟频率}}{8} \times \text{中断周期}) - 1 $$ 3. **中断嵌套优先级** - SysTick默认优先级最低,可通过`NVIC_SetPriority(SysTick_IRQn, 0)`提高优先级。 --- 通过上述步骤,可稳定实现SysTick中断,适用于实时操作系统(RTOS)心跳、按键消抖、PWM生成等场景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值