CortexM4内核Stm32-HAL_Init()及HAL_InitTick(TICK_INT_PRIORITY()详解——Systick中断优先级

上次写完HAL_NVIC_SetPriorityGrouping(),设置分组为2,抢占优先级与响应优先级都是2

HAL_Init还剩下一个HAL_InitTick(TICK_INT_PRIORITY)函数就讲完了,其中,TICK_INT_PRIORITY为Systick时钟默认中断,为0x0F。

如上文抢占有限级和响应优先级都是2来说,那么Systick的中断优先级是最低的

只要任何出现中断优先级高的,就会打断Systick中断,这样怎么保障如何保障其定时准确呢?

首先看了正点原子的开发指南
在这里插入图片描述
他的意思是使用内部实现的,不占用外部中断
那么有一个问题了,内部外设和普通外设的中断优先级谁更高一些?
是根据设定的优先级顺序来决定还是根据内核优先原则?
找到一篇这样的博客,可以看一下

https://blog.csdn.net/To_be_a_fisher/article/details/84986790

其结论为
Systick虽然作为与CPU紧耦合的内核外设,但其中断优先级并不比普通外设要高,并不因为它是内核外设而特殊,它还是遵循中断优先级高低的规则来响应。

所以如果需要保障计时更准确一些,应该将Systick中断优先级提高,具体我先埋个坑-。-

然后进入函数

__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /* Configure the SysTick to have interrupt in 1ms time basis*/
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  {
    return HAL_ERROR;
  }

  /* Configure the SysTick IRQ priority */
  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  {
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  {
    return HAL_ERROR;
  }

  /* Return function status */
  return HAL_OK;
}

这一步很巧妙,通过if来判断括号中的1ms时间是否设置完成,
中心思路:系统时钟为16Mhz,然后记16/1000,那么就是1/1000s,也就是1ms

其具体实现如下:
首先第一个if判断语句,HAL_SYSTICK_Config(),该函数如下,首先判断ticks是否超过24位,如果没有的话,就送到SysTick->LOAD中。
STK_ LOAD 寄存器是重置值,当计数为0的时候充值为LOAD值,HAL库将其设置为16000 (0x00003E80)
VAL寄存器是Systick时钟当前计数值,将其清零
CTRL是控制寄存器,其由以下组成
在这里插入图片描述
16 COUNTFLAG 计数标志位: 当倒计时到0时,输出1
CLKSOURSE时钟源选择 0: AHB/8 1:AHB
TICKINT 1:当计数到0会发出计数信号
ENABLE 1:计数 0:关闭使能

默认的这三个都设置为1

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);                                                   /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* 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 (0UL);                                                     /* Function successful */
}

中间还有一个NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
该函数设置SysTick_IRQn 优先级为0111,特别注意这个是函数内部设置优先级为0111,

__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)  //0x0c  1100
{

  if ((int32_t)(IRQn) >= 0)
  {
		
    NVIC->IP[((uint32_t)IRQn)]               = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);//(1100 << 4 = 1100 0000)
  }
  else
  {
    SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL);
  }
}

设置好标准时间之后,再设置中断时钟的优先级,入口参数为SysTick_IRQn,0x0F,0

void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)
{ 
  uint32_t prioritygroup = 0x00U;

  /* Check the parameters */
  assert_param(IS_NVIC_SUB_PRIORITY(SubPriority));
  assert_param(IS_NVIC_PREEMPTION_PRIORITY(PreemptPriority));
  
  prioritygroup = NVIC_GetPriorityGrouping();

  NVIC_SetPriority(IRQn, NVIC_EncodePriority(prioritygroup, PreemptPriority, SubPriority));
}

assert 函数就不说了,然后再获取当前分组,设置优先级,这个与上面不同的是,上面设置优先级的值是函数内部初始化,NVIC_EncodePriority 将中断分组名,宏定义的优先级与SubPriority 进行编码

__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
{
  uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL);   /* only values 0..7 are used          */
  uint32_t PreemptPriorityBits;
  uint32_t SubPriorityBits;

  PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); //get min of this
  SubPriorityBits     = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS));

  return (
           ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | 
           ((SubPriority     & (uint32_t)((1UL << (SubPriorityBits    )) - 1UL)))                          
         );
}

C语法:(>)?A:B如果括号内成立则执行A,不成立执行B
这里两个赋值语句执行的都是B
还是贴一下F4的中断分组
在这里插入图片描述
PriorityGroupTmp :当前AIRCR二进制
PreemptPriorityBits :获取当前抢占优先级是几位
SubPriorityBits :获取当前响应优先级是几位

注意当计算减法的时候,都转为十进制进行计算。
最后返回的便是抢占优先级与相应优先级的具体位上的值

最后便进行优先级设置,设置好之后,再把当前优先级送到uwTickPrio中。便完成了HAL_ini

写的很啰嗦-。- 下次会好好想怎么写的更好一些。

会持续更新的,欢迎0基础同学们持续关注
也欢迎大家指点,谢谢!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值