配置SysTick嘀嗒定时器(延时函数)、SYSCLK系统时钟

本文不通过NVIC中断延时,只基于SysTick的寄存器CTRL-控制及状态寄存器、VAL-当前数值寄存器、LOAD-重装载数值寄存器,编写基础的延时代码。

附带SYSCLK系统时钟的简单配置。


一、delay函数

Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计数到0时,从自动重装载寄存器中自动装载定时初值,并开始倒计时,循环往复,只要不关闭其使能位,嘀嗒定时器SysTick就会一直计时。

咱先上寄存器手册:

先创建一个delay.h文件,里面定义函数名,delay初始化、毫秒延时、微秒延时,

注意:本文代码中delay_init函数中的形参SYSCLK是系统时钟,单位是M。

再创建一个delay.c的文件存放功能函数,在写功能函数之前先定义两个静态延时倍乘数fac_us、fac_ms,之所以要定义两个延时倍乘数,是因为不同频率下,systick计数一次所经过的时间不同,为了能使两个延时函数delay_us、delay_ms的延时是我们所设置的形参的值,需要一个延时倍乘数去乘以形参,得到一个重装载值,而这个重装载值一但倒计数完毕,所经过的时间便是我们所设置的形参的值。

1.delay_init:

假如:HCLK为72M,则SysTick就是72/8=9M,在9M的频率下,SysTick每倒计数一次,所经过的时间便是1/9us,那么定时1us所需的计数次数就是9次,要使delay_us(1)成功延时1us,那么delay_us函数中,systick的重装载值要设置为9,即形参1乘以延时倍乘数fac_us得9,fac_us就为9

因此在delay_init函数中我们需设置好延时倍乘数fac_us、fac_ms,代码如下:

delay初始化完成之后,就要编写delay_ms、delay_us函数

2.delay_us:

配置寄存器时,一定要先配置重装载值,再清空计数器,若先清空计数器在设置重装载值,开启定时器后,定时器的第一个计数周期是从0开始计数,第二周期才是从你设置的重装载值开始计数,逻辑十分不严谨,极有可能会出现bug,导致延时无效。

计数完成后,即延时成功后,需先关闭计数器,再清空它,若先清空在关闭,就相当于没清空计数器,对下次使用十分不友好。在编写代码时,除非必要,否则我们要习惯在不使用某个寄存器或功能时,要让它处于复位值,即默认状态。这样才能减少在编写复杂代码时出现未知bug。

3.delay_ms:

代码跟delay_us类似,在此就不在赘述了,直接上代码

完整代码如下:

#include "delay.h"

/*---------------------------------------
此代码不通过NVIC中断延时
基于SysTick的寄存器CTRL-控制及状态寄存器、VAL-当前数值寄存器、LOAD-重装载数值寄存器
编写基础的延时代码
-----------------------------------------*/

static int8_t fac_us = 0;  // us延时倍乘数
static int16_t fac_ms = 0; // ms延时倍乘数

// SYSTICK固定为HCLK的1/8
// 系统时钟:SYSCLK,单位:M

void delay_init(u8 SYSCLK) // 延时初始化
{
    SysTick->CTRL &= ~(1 << 2);      // 选择时钟源,0=AHB/8,1=AHB
    fac_us = SYSCLK / 8;             // us倍乘数为SYSCLK的1/8
    fac_ms = (int16_t)fac_us * 1000; // ms倍乘数为fac_us的1000倍
}

void delay_us(u32 nus)
{
    uint32_t temp; // 定义一个32的变量,便于后面的循环判断
    /*
    设置重装载值,即延时时间;直接整体赋值,无需位操作
    LOAD为24位寄存器,最大可设为16 777 216
    */
    SysTick->LOAD = nus * fac_us;

    SysTick->VAL = 0X00; // 清零,VAL只要写入则清零,同时清除CTRL中的COUNTFLAG标
    /*
    位段0写1,开启定时器使能,开始倒数
    复位值为0,且其余位是默认设置,因此直接赋值0X01不影响其余位
     */
    SysTick->CTRL = 0X01;

    /*
    while循环用于等待时间到达
    当SysTick计数到0时,COUNTFLAG置一,即位段16置一,否则位段16置0
    (temp&(0X01)判断定时器是否开启,防止定时器意外关闭导致延时错误
    */
    do
    {
        temp = SysTick->CTRL;
    } while ((temp & (0X01) && !(temp & (1 << 16))));
    SysTick->CTRL = 0X00; // 关闭计数器
    SysTick->VAL = 0X00;  // 清空计数器
}

/*
LOAD为24位寄存器,所以最大延时为:nms<= 0xffffff x 8 x 1000/SYSCLK
SYSCLK单位为Hz,nms单位为ms,72MHz 条件下,nms<= 1864
*/
void delay_ms(u16 nms)
{
    uint32_t temp; // 定义一个32的变量,便于后面的循环判断

    SysTick->LOAD = (u32)nms * fac_ms;
    SysTick->VAL = 0X00; // 清零,VAL只要写入则清零,同时清除CTRL中的COUNTFLAG标
    SysTick->CTRL = 0X01;
    do
    {
        temp = SysTick->CTRL;
    } while ((temp & (0X01) && !(temp & (1 << 16))));
    SysTick->CTRL = 0X00; // 关闭计数器
    SysTick->VAL = 0X00;  // 清空计数器
}


 

二、设置系统时钟

本文只简单介绍系统时钟配置步骤及代码,具体原理请读者自行阅览时钟树及寄存器手册,如下:

寄存器手册请对照RCC_CR、RCC_CFGR,

详情参考:http://t.csdnimg.cn/T3WzI

FLASH_ACR如下:

1.配置步骤:

  1. 选择输入时钟,一般选HSE(外部高速时钟),并等待输入时钟就绪
  2. 选择三条总线AHB、APB1、APB2分频系数
  3. 选择PLL锁相环倍频系数,开启PLL输出,当PLL输出>72M时,flash需等待2个延时周期
  4. 等待PLL锁定
  5. 选定PLL输出频率作为系统时钟,等待其设置成功。

代码如下:

 

  • 11
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值