赞
踩
SysTick定时器,可称之为滴答定时器,中断配置可选择而被 归置于NVIC管理,可作为整个系统的时基来确保某个任务不会霸占系统,也可以给任务分配时间,集成在Cortex内部(便于代码移植)。
该定时器通过递减计数,当定时器递减计数至0时,就会告诉管家NVIC,并且重新载入一个初值,循环往复(当然,计数到0后的操作,是有必要条件的)。
VAL 当前值寄存器
反应实时数据,把要定的时间写进去,然后就会自己一直减一,开启/结束定时器工作之前记得清零就好
LOAD 重载寄存器
在定时器开启工作前要写入,决定了每次定时的长短,CAL的初值就是来源于它
CTRL 状态控制寄存器
最为灵活的地方就在于此,它的4个bit位具有意义,分别决定了定时器工作与否、中断工作否、时钟源、计数到0否。
CALIB 校检寄存器
目前菜鸡水平,没用过,包含外部参考时钟可用性,1ms计时准确性等
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)函数,可用于确定该定时器的时钟源,提供可选择的参数有:
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的抽象实现,看看那些代码;可以针对自己的功能改写库函数,做做优化,博采众长才是王道,无招胜奇招,而不是死磕一个工具,本末倒置。
stm32芯片的完整的封装,目前采用也多,没有什么移植性,接近寄存器操作,近几年新出的芯片不提供std库。正因为接近寄存器而又没有查寄存器的麻烦,所以还是很适合学习的。
官方重点发展对象,官方提供了配套炫酷的桌面软件StmCubeMX,开发者可以直接进行可视化配置,移植性比较好,节省开发时间,而这套工具就提供了LL库和HAL库,不过LL库更接近底层。可以说HAL库就是用来取代之前的标准外设库的。相比标准外设库,HAL库表现出更高的抽象整合水平,HAL API集中关注各外设的公共函数功能,这样便于定义一套通用的用户友好的API函数接口,从而可以轻松实现从一个STM32产品移植到另一个不同的STM32系列产品。HAL库是ST未来主推的库,从前年开始ST新出的芯片已经没有STD库了,比如F7系列。目前,HAL库已经支持STM32全线产品。
与HAL库捆绑,接近硬件,移植性差,可独立使用,可与HAL库混合使用。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。