STM32
直播中

凌流浪

7年用户 955经验值
擅长:可编程逻辑 电源/新能源
私信 关注
[问答]

滴答定时器SysTick有哪些作用呢

滴答定时器Systick有哪些作用呢?
有多少寄存器去控制SysTick定时器呢?

回帖(1)

冯虎虔

2021-11-24 09:47:29
  滴答定时器(SysTick)的作用:
  1、作为操作系统时基
  2、作为精确延时函数时基(delay函数)
  滴答定时器是一个 24 位的倒计数定时器,当计到 0 时,将从 RELOAD 寄存器中自动重装载定时器初值,只要不把它在 SysTick 控制寄存器以及状态寄存器中的使能位清零,就将永久不息。
  Cortex‐M3/4 在内核水平上搭载了一个异常响应系统,支持为数众多的系统异常和外部中断。
  编号为 1-15 的对应系统异常,大于等于 16 的则全是外部中断。
  有 3 个固定优先级的系统异常:复位,NMI 以及硬 fault,它们的优先级是不可编程的,它们的优先级号是负数,从而高于所有其它异常。
  其它异常的优先级则都是可编程的(但不能编程为负数)做成芯片后,支持的中断源数目常常不到 240
  个,并且优先级的位数也由芯片厂商最终决定。但是16个异常一般都是拥有的,这16个异常都有共同的特性,比如它们的位操作是一样的,这增加了同一内核不同芯片之间代码的可移植性。
  
  SysTick寄存器:(可通过M3/4权威指南查看)
  SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。
  在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。
  有4个寄存器控制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;
  看后面的注释知道四个结构体成员对应上面四个寄存器。
  SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间(delay延时函数)等。
  要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。
  是个定时器都需要时钟来源,从时钟树来看,SysTick定时器的时钟是AHB/8(也就是HCLK/8)。如果我们外部晶振为 8M,然后倍频到 168M,那么 SysTick 的时钟即为 21Mhz。也就是 SysTick 的计数器 VAL (定时器的CURRENT寄存器)每减 1,就代表时间过了 1/21us ——在21Mhz的频率跳动时,每跳1次所用的时间,1/21us称它为时基:1/(21x10^6hz)=1/21us。(这就是为什么后面程序里面fac_us=SYSCLK/8的原因,在这里SYSCLK=168,所以fac_us=21)
  
  具体代码:
  //SYSTICK的时钟固定为AHB时钟的1/8
  //SYSCLK:系统时钟频率
  void delay_init(u8 SYSCLK)
  {
  /*定义SysTick的时钟来源,可以是HCLK或者是HCLK/8*/
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
  /*SYSCLK是传进来的参数,这里是STM32F4,所以SYSCLK是168*/
  /*HCLK/8定时器时基为1/21us,所以1us跳21次,这就是SYSCLK/8的原因*/
  fac_us=SYSCLK/8; //fac_us其实就是定时1us了,这里是一个值21
  fac_ms=(u16)fac_us*1000; //代表每个ms需要的systick时钟数
  }
  那么我们看看us的延时函数:
  //延时nus
  //nus为要延时的us数。
  //注意:nus的值,不要大于798915us(最大值即2^24/fac_us@fac_us=21)
  void delay_us(u32 nus)
  {
  u32 temp;
  SysTick-》LOAD=nus*fac_us; //时间加载fac_us=21,每个us跳21次
  SysTick-》VAL=0x00; //清空计数器
  SysTick-》CTRL|=SysTick_CTRL_ENABLE_Msk ; //SysTick定时器使能,开始倒数,SysTick_CTRL_ENABLE_Msk=1
  do
  {
  /*判断SysTick的控制及状态寄存器(CTRL)第16位是否置1(置1代表倒计数结束)
  temp&0x01这个语句是判断SysTick是否已经使能(其实可以省略这个语句)
  !(temp&(1《《16)判断CTRL寄存器16位是否置1,置1取反后为0则跳出循环
  */
  temp=SysTick-》CTRL; //把CTRL寄存器的值赋给temp
  }while((temp&0x01)&&!(temp&(1《《16))); //等待时间到达
  SysTick-》CTRL&=~SysTick_CTRL_ENABLE_Msk; //ysTick定时器使能位清零,关闭计数器
  SysTick-》VAL =0X00; //清空计数器
  }
  
  注释已经在代码中了,十分详细。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分