SysTick定时器

概述

SysTick定时器,可称之为滴答定时器,中断配置可选择而被 归置于NVIC管理,可作为整个系统的时基来确保某个任务不会霸占系统,也可以给任务分配时间,集成在Cortex内部(便于代码移植)。
该定时器通过递减计数,当定时器递减计数至0时,就会告诉管家NVIC,并且重新载入一个初值,循环往复(当然,计数到0后的操作,是有必要条件的)。

寄存器

VAL 当前值寄存器

反应实时数据,把要定的时间写进去,然后就会自己一直减一,开启/结束定时器工作之前记得清零就好

LOAD 重载寄存器

在定时器开启工作前要写入,决定了每次定时的长短,CAL的初值就是来源于它

CTRL 状态控制寄存器

最为灵活的地方就在于此,它的4个bit位具有意义,分别决定了定时器工作与否、中断工作否、时钟源、计数到0否。

CALIB 校检寄存器

目前菜鸡水平,没用过,包含外部参考时钟可用性,1ms计时准确性等

半库函数操作

void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)函数,可用于确定该定时器的时钟源,提供可选择的参数有:

  • SysTick_CLKSource_HCLK_Div8:SYSCLK进行8分频
  • SysTick_CLKSource_HCLK:直接采用SYSCLK时钟

SysTick结构体指针,拿来操作那几个寄存器,成员变量有以下

  • ->LOAD 计数初值,如果计数x微秒,写入x*SYSCLK/Div就行(SYSCLK为时钟源频率,Div是分频系数,就是上面那个函数的分频值,不是1就是8),注意它是24位别瞎赋值

  • ->VAL 实时值,工作前/工作后写个0x00就行,有理由你懂的

  • ->CTRL 最难折腾的东西,32bit,操作它就能控制定时器工作状态,不同位不同功能,汇编去查个寄存器表,不过函数操作封装了很多值,拿去一顿与或非操作,具体在core_cm3.h文件中以SysTick_CTRL_*格式宏定义了,这里举个栗子:

      SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;//开启中断
      SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;//开启定时器
      ......
      SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk//关闭定时器
    

    Gameover?并没有,定时器讲了开启关闭,总的告诉定时状态吧!还是那该死的BIT位,于是我们不让他自动重载初始值,它计数完了就卡住,我们就一直去看它计时完了没有(当然,你也可以写中断,不过很多时候写中断太烦)。直接上轮询的代码:

      do{
      temp = SysTick->CTRL;
      }while((temp&0x01)&&!(temp&(1<<16)));//不断检查标志位,参考CTEL各位的意义
    

参考上面的东西,我们可以写一个完整的微秒级别的延迟函数(先得初始化时钟配置):

/**
* @brief 初始化SysTick定时器 
* @para 系统时钟频率(MHz)
*   例如
*       @SYSTICK 72
*/
void SysTick_Init(u8 SYSCLK)
{
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    fac_us = SYSCLK/8; //用于微秒计数换算
    fac_ms = (u16)fac_us*1000;//用于秒计数换算
}

/**
* @brief 精确定时
* @note 第一次调用此函数前提:调用void SysTick_Init(u8 SYSCLK)
*   @para 定时时间(us)
*     例如
*       @nus 5
*/
void delay_us(u32 nus)
{
    u32 temp;
    SysTick->LOAD = nus*fac_us;
    SysTick->VAL = 0x00;
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;//状态控制
    do{
        temp = SysTick->CTRL;
    }while((temp&0x01)&&!(temp&(1<<16)));//是否计时完毕
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;//关闭计时
    SysTick->VAL = 0x00;
}

OK,我们的延时函数可以凑活用了,不过这还是在半玩寄存器半函数调用,不够抽象,索性有没有全部是函数调用的,不必关心寄存器位操作?

库函数操作

为什么不直接写库函数操作,我不会告诉你3.5的库不支持太多函数的(相对老版本),能用的只有SysTick_Config()和SysTick_CLKSourceConfig()了。
3.5的库函数SysTick_Config()把初值、中断优先级、中断使能、开启定时器一把完成了(PS:人性化真香,真抽象),要用3.5的库函数实现延时的话:直接定义一个全局变量,然后在中断函数里面自加,统计中断次数就完成了。
所以要么用老库,要么用上述的半函数半寄存器,要么配置中断去。值得商榷的是老库还是提供了很多函数的,不过,半寄存器版本已经完工(其实没有),纯粹函数调用也完工了,老库的函数就会鸡肋了。

各个库的问题

stm32的库有很多版,HAL库,标准外设库(std库)、LL库。本文采用的3.5的std库。并非越接近硬件电路的库越好,也并非越抽象越好,若真要提高下自己程序的效率,去参考下Ardunio的抽象实现,看看那些代码;可以针对自己的功能改写库函数,做做优化,博采众长才是王道,无招胜奇招,而不是死磕一个工具,本末倒置。

std库

stm32芯片的完整的封装,目前采用也多,没有什么移植性,接近寄存器操作,近几年新出的芯片不提供std库。正因为接近寄存器而又没有查寄存器的麻烦,所以还是很适合学习的。

Hal库

官方重点发展对象,官方提供了配套炫酷的桌面软件StmCubeMX,开发者可以直接进行可视化配置,移植性比较好,节省开发时间,而这套工具就提供了LL库和HAL库,不过LL库更接近底层。可以说HAL库就是用来取代之前的标准外设库的。相比标准外设库,HAL库表现出更高的抽象整合水平,HAL API集中关注各外设的公共函数功能,这样便于定义一套通用的用户友好的API函数接口,从而可以轻松实现从一个STM32产品移植到另一个不同的STM32系列产品。HAL库是ST未来主推的库,从前年开始ST新出的芯片已经没有STD库了,比如F7系列。目前,HAL库已经支持STM32全线产品。

LL库

与HAL库捆绑,接近硬件,移植性差,可独立使用,可与HAL库混合使用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值