09_Systick系统定时器

一:Systick定时器介绍

  SysTick 定时器也叫 SysTick 滴答定时器, 它是 Cortex-M3 内核的一个外设,被嵌入在 NVIC 中。 它是一个 24 位向下递减的定时器, 每计数一次所需时间为1/SYSTICK, SYSTICK 是系统定时器时钟, 它可以直接取自系统时钟, 还可以通过系统时钟 8 分频后获取, 我们采用后者, 即每计数一次所需时间为1/(72/8)us, 换句话说在 1us 的时间内会计数 9 次。 当定时器计数到 0 时, 将从LOAD 寄存器中自动重装定时器初值, 重新向下递减计数, 如此循环往复。 如果开启 SysTick 中断的话, 当定时器计数到 0, 将产生一个中断信号。 因此只要知道计数的次数就可以准确得到它的延时时间。
  SysTick 定时器通常应用在操作系统中, 为其提供时钟周期。

二:Systick定时器操作

  在 STM32F1 库函数中, 并没有提供相应的 SysTick 定时器配置函数, 我们要操作 SysTick 定时器就需要了解它的寄存器功能。 其实 SysTick 定时器寄存器很简单, 只有 4 个, 分别是 CTRL、 LOAD、 VAL、 CALIB。

1.  Systick定时器寄存器

(1) CTRL 寄存器
  CTRL 是 SysTick 定时器的控制及状态寄存器。 其相应位功能如下:
  

   注: CLKSOUTCE 位是用于选择 SysTick 定时器时钟来源, 如果该位为 1, 表示其时钟是由系统时钟直接提供即 72M。 如果为 0, 表示其时钟是由系统时钟八分频后提供即 72/8=9M。

(2) LOAD 寄存器
  LOAD 是 SysTick 定时器的重装载数值寄存器。 其相应位功能如下:

  

   因为 STM32F1 的 SysTick 定时器是一个 24 位递减计数器, 因此重装载寄存器中只使用到了低 24 位, 即 bit0-bit23。 当系统复位时, 其值为 0。

(3) VAL 寄存器
  VAL 是 SysTick 定时器的当前数值寄存器。 其相应位功能如下:

  

   同样只有 bit0-bit23 有效, 复位时值为 0。

(4) CALIB 寄存器
  CALIB 是 SysTick 定时器的校准数值寄存器。 其相应位功能如下:

  

 2.  Systick定时器操作步骤

  SysTick 定时器的操作可以分为 4 步:
  (1) 设置 SysTick 定时器的时钟源。
  (2) 设置 SysTick 定时器的重装初始值(如果要使用中断的话, 就将中断使能打开) 。
  (3) 清零 SysTick 定时器当前计数器的值。
  (4) 打开 SysTick 定时器。

三:软件设计

  软件设计部分我们就不再讲述怎么复制工程、 新建文件以及添加对应的头文件路径, 我们直接打开实验例程内的工程进行讲解。 同样 SysTick定时器延时函数在任何一个 STM32F1 应用程序中都用得上, 因此将其驱动文件放在 Public 文件夹内。

1.   Systick_Init()函数

  void SysTick_Init(u8 SYSCLK)
  {
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    fac_us=SYSCLK/8; //SYSCLK的 8分频 保存 1us所需的计数次数
    fac_ms=(u16)fac_us*1000; //每个 ms 需要的 systick 时钟数
  }
   SysTick_Init 函数形参 SYSCLK 表示的系统时钟大小, 默认配置我们使用的系统时钟是 72M, 所以调用这个函数时, 形参值即为 72。 函数内部调用了一个库函数     SysTick_CLKSourceConfig, 此函数用来对 SysTick 定时器时钟的选择, 我们 使 用 的 SysTick 定 时 器 时 钟 是 系 统 时 钟 的 8 分 频 , 所 以 参 数 是SysTick_CLKSource_HCLK_Div8。 如果使用系统时钟作为 SysTick 定时器时钟,那么参数即为 SysTick_CLKSource_HCLK。 这个函数在 misc.c 库文件内, 如何查找我们前面介绍过方法。
  下面的两条语句是用来求取 SysTick 定时器在 1us 时间内和 1ms 时间内的计数次数。

2.  delay_ms()函数

  注 意 :nus 的 值 , 不 要 大 于 798915us( 最 大 值 即2^24/fac_us@fac_us=21)

void delay_us(u32 nus)
{
  u32 temp;
  SysTick->LOAD=nus*fac_us; //时间加载
  SysTick->VAL=0x00; //清空计数器
  SysTick->CTRL|=0x01 ; //开始倒数
  do
{
  temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
  SysTick->CTRL&=~0x01; //关闭计数器
  SysTick->VAL =0X00; //清空计数器
}
①将需要延时多少 us 的计数值加载到 SysTick 的 LOAD 寄存器中, fac_us值是延时 1us 所需的计数值。
②清空当前计数值寄存器 VAL。
③打开 SysTick 定时器, 定时器开始向下递减计数。
④CTRL 寄存器的第 16 位是 SysTick 递减到 0 的标志位, 如果递减到 0, 此为置 1, 通过读取该位来判断延时是否完成, 从而退出 while 循环。
⑤关闭 SysTick 定时器。
⑥清空当前计数值寄存器 VAL。

3.  delay_ms()函数

 注意:nms 的值,SysTick->LOAD 为 24 位寄存器,不要大于 0xffffff*8*1000/SYSCLK对 72M 条件下,nms<=1864ms

void delay_ms(u16 nms)
{
  u32 temp;
  SysTick->LOAD=(u32)nms*fac_ms; // 时 间 加 载(SysTick->LOAD 为 24bit)
  SysTick->VAL =0x00; //清空计数器
  SysTick->CTRL|=0x01 ; //开始倒数
  do{
    temp=SysTick->CTRL;
  }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
  SysTick->CTRL&=~0x01; //关闭计数器
  SysTick->VAL =0X00; //清空计数器
}
  此函数功能与 delay_us 基本一样, 只不过这里是延时 ms。 要注意的是,SysTick 定 时 器 是 24 位 的 , 其 计 数 最 大 值 为 0xffffff , 时 间 为nms<=0xffffff*8*1000/SYSCLK, SYSCLK 是系统时钟为 72M, 所以最大延时为1864ms。 如果需要延时大于 1.864S, 可以调用多个 delay_ms 函数即可。

4. 主函数

  int main()
  {
    SysTick_Init(72);
    LED_Init();
    while(1)
    {
      led1=0;
      led2=1;
      delay_ms(500); //精确延时 500ms
      led1=1;
      led2=0;
      delay_ms(500); //精确延时 500ms
    }
  }
  主函数实现的功能比较简单, 首先对 SysTick 定时器进行初始化配置, 选择系统时钟 8 分频作为 SysTick 的时钟, 然后初始化 LED, 这个初始化过程前面已经介绍过, 大家也可以进入这个函数内查看。 最后进入 while 循环语句, 对 PC0和 PC1 管脚进行位操作, 里面也调用了 delay_ms 延时函数, 这时候的延时是非常精确的。

猜你喜欢

转载自www.cnblogs.com/eokey/p/11990427.html
今日推荐