定时器介绍

定时器是一种片上外设,专门用来定时,类似于手表,每一秒跳动一下,定时器也是每隔一个时间段计数器值+1,精准定时

定时器F1系列最多有14个,不同芯片数量不同,如下图,分为基本定时器,通用定时器和高级定时器,后两者分别多了从模式控制器和高级功能

定时器整体结构图

共五个部分,分别是时基单元,输入捕获,输出比较,从模式控制器,高级功能,铁头山羊已经用粉色虚线和绿色虚线分隔开了

时基单元

时基单元结构图

时钟来源

From RCC:Tim是一个片上外设,它的时钟都是来自于RCC的,但不同Tim的时钟来源不同,可以是APB1,也可以来自于APB2,需要查询数据手册和参考手册,找框图来确定

数据手册的框图:

参考手册的框图:

这里都表明TIM1来自于APB2,TIM234来自于APB1,但是参考手册上还表明,如果APBx分频系数为1,则频率不变,如果不是,则频率*2

铁头山羊视频中没说为什么,只好去文心一言问了一下,原来是因为数据手册更倾向于概念,框架,而参考手册则更具体一些,所以写代码,参考手册比数据手册要更重要一些

知识点小结

分频计数器以及计数模式

分频计数器

时基单元的三个部分:预分频器,自动重装寄存器+计数器,重复计数器内部结构其实是相同的,另外两部分也都是由自动重装寄存器+计数器组成的,区别仅仅是概念上的功能不同

计数模式

上计数模式

假设自动重装寄存器值为N,那么计数器在经过N个脉冲后,也会计数到N(初值为0),再来一个脉冲就会溢出,向后产生一个脉冲并且计数器归0,所以计数的个数是N+1,也就是输入N+1个脉冲后,计数器值归0并产生一个脉冲

个人理解:

假设ARR为36,看计数器寄存器那一行和计数器溢出那一行,数字是从0~36的不断轮回,假设把时钟脉冲也计数,那就是输入脉冲是1,计数器为1,然后输入脉冲是2,3,4,计数器也是2,3,4,同步相加,一直到都是36,再往后输入脉冲是37,计数器为0,接着分别是38,39,40和1,2,3,计数器的值可以看成是输入脉冲对37取余数,也就是对(36+1)取余数,每到计数器为0产生一个脉冲,就是每数到37的整数倍产生一个脉冲,所以说计数周期=36+1也即N+1,还有另外两个部件与分频器和重复计数器也好理解了:预分频器的功能是把进来的脉冲经过PSC+1进行分频,也就是说APB2脉冲个数为(PSC+1)整数倍时,向中间部件输入一个脉冲,也就是说APB2给了预分频器k*(PSC+1)个脉冲,预分频器就给中间部件k个脉冲,分频了;同理重复计数器也是,中间部件向R重复计数器输入(RCR+1)个脉冲后,向外输出一个脉冲,就是说"表转了RCR+1"圈,产生一个updata事件,但是重复计数器只有高级定时器才有,基本和通用在计数器产生脉冲后就直接产生updata事件了。

下计数模式

假设自动重装寄存器值为N,那么计数器初值为N,在经过N个脉冲后,会降到0,再来一个脉冲就会溢出向后产生一个脉冲,并且计数器值归为N,所以计数的个数是N+1,也就是输入N+1个脉冲后,计数器值归为N并产生一个脉冲

与上计数模式类似,输入脉冲从0~36~37~73~74,计数器从36~0~36~0~36,可以看成是

36-输入脉冲值%37=计数器值,每当数到36时会产生一个脉冲,也就是说产生脉冲时

36-输入脉冲值%37=计数器值=36,此时输入脉冲值%37=0,也就是说输入脉冲为(36+1)的整数倍时,向后产生一个时钟,技术周期也为N+1

中间对齐计数模式

这个模式看的有点懵,如果只看时序图的话:ARR为N只看时序图按前两个计数模式思考的话,是输入脉冲值数到12的整数倍时,会产生计数器下溢,类似于之前的溢出,也就是说计数周期是2N,可是那个更新事件却更新了两次,铁头山羊总结的计数周期分别是N+1,N+1,2N+1,我思考后的是N+1,N+1,2N,问文心一样,和我的是一样的,我暂且按自己的来记,去b站问一下铁头山羊大大,但是那个更新事件两次我非常不理解。

练习定时-多长时间产生一次脉冲(产生一次update事件,在后面)

update事件与预加载

结构图中寄存器后面有阴影,是一个叫做影子寄存器的东西,自动重装寄存器中的值决定了技术周期,有时候需要动态改变这个N的值,但是产生计数器产生脉冲并自动归0是在计数器值恰好等于N后,再来一个脉冲的时候,如果计数器内的值大于自动重装寄存器内的值(N),再来一个脉冲不会产生脉冲也不会产生归零,假如原先N为10,计数器值已经是8,突然将N改为5,那么计数器值>自动重装寄存器内的值,接下来一直来的脉冲只会让计数器值不断增大,却不会出现等于自动重装寄存器内的值的情况,直到计数器数到65535再来一次脉冲才会归零,也就是说有一段很长时间的无脉冲时间,影子寄存器是预先将新N值写入影子寄存器,在update事件后,三个部件内部计数器归零,此时影子寄存器内的新值再放入"自动重装寄存器",就不会出现刚刚的情况了,影子寄存器,两边的部件是自动开启的,中间部件需要手动开启,在设置完定时器需要手动用软件产生一次update事件,将影子寄存器内的值放入自动重装寄存器再工作

在完成计数周期后,中间部件或者重复计数器向后输出一个脉冲,产生update事件,update事件作用:将影子寄存器中的值填入预分频器,自动重装寄存器,重复计数器,并产生一个中断标志(是否产生中断源要看是否使能这个中断,同一个定时器的update和输入捕获等中断共享同一个通道),闪电是update事件,事件作用是将影子寄存器内值放入自动重装寄存器,将update中断的标志位置1(UIF),是否产生中断源,要看是否使能这个中断(UIE)

编程接口与自制函数

函数思路:

中断服务函数:先设一个变量,每过1ms+1。

获取当前时间(毫秒级)直接返回变量

获取当前时间(微秒级)返回变量*1000+计数器内值

延时函数(毫秒级):获取当前时间,然后设一个变量目标时间=当前毫秒级时间+延迟毫秒数,wihle循环,当前毫秒级时间<目标事件内则在延迟函数里等待即可

延时函数(微秒级):获取当前时间,然后设一个变量目标时间=当前微秒级时间+延迟微秒数,wihle循环,当前微秒级时间<目标事件内则在延迟函数里等待即可

中断号通过参考手册找,知道中断号后设置NVIC的通道在stm32f10x.h中找,设置完NVIC,编写中断服务函数时,要取代的函数名称在启动文件中找

代码结构

定时器.c

main.c

zong

工作后的总结

Update 事件+中断使能=Update 中断
递减模式CNT到0时,算一个周期的话,假设RCR值为N,则
每N+1个周期产生Update 事件,RCR值取0时就是每0+1个周期也就是每个周期产生Update 事件,若再加上对应的中断使能UIE为1,则每0+1个周期也就是每个周期产生对应Update 中断

关于系统时钟和时间片的复习

想看一下freeRTOS每个任务运行时长是多少,搜了一下,和configTICK_RATE_HZ相关:每个时间片为1/configTICK_RATE_HZ秒,或者说每秒调度configTICK_RATE_HZ次

想知道为什么可以软件配置configTICK_RATE_HZ就可以了,而不需要管操作系统所用的硬件定时器。

全局搜索configTICK_RATE_HZ,发现

转到portNVIC_SYSTICK_LOAD_REG定义

经同事指点,这个是系统定时器的重载寄存器,0xe000e014应该就是这个寄存器的地址,STM32参考手册搜不到,只能在M3权威内核指南里看。

#define portNVIC_SYSTICK_LOAD_REG            ( * ( ( volatile uint32_t * ) 0xe000e014 ) )

volatile指的是让编译器不要优化,每次都要从硬件地址进行真实读写, 0xe000e014被强制类型转换为uint32t类型的指针,必须去真实硬件该地址处进行读取,最左边的*就是寻址

*p=a:p指向的空间写入a的值

portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;

就是  ( * ( ( volatile uint32_t * ) 0xe000e014 ) ) = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;

也就是

0xe000e014指向空间写入(系统时钟HZ/configTICK_RATE_HZ) - 1
也就是SysTick重装载数值寄存器(地址:0xE000_E014)值写入(系统时钟HZ/configTICK_RATE_HZ) - 1


0--------------初始值
x-1
x-2
...
1
0---------------中断
x-1
x-2
...
1
0---------------中断
x-1
x-2
...
1
0---------------中断
x-1
x-2
...
1
0---------------中断

一次中断后当前值为0,,到下一次中断经历x+1个点,距离为x格,跳一次走一格,跳x发送一次中断,又回到一次终端后,当前值为0的状态,下一次仍然需要x次,也就是重载计数器为x-1的情况下,跳x次才会发生一次中断

重载寄存器 = (系统时钟HZ/configTICK_RATE_HZ) - 1

也就是跳(系统时钟HZ/configTICK_RATE_HZ)进入中断

每跳一次为 1/系统时钟HZ 秒

每跳(系统时钟HZ/configTICK_RATE_HZ)进入一次中断,就是

每个中断要这么长时间进一次:

(系统时钟HZ/configTICK_RATE_HZ) * 1/系统时钟HZ 秒 = 1/configTICK_RATE_HZ 秒

也就是每1/configTICK_RATE_HZ 秒 进一次中断,每个中断会进行一次调度,也就是进行一次时间片轮转,时间片长度就是调度一次的时间,也就是1/configTICK_RATE_HZ 秒,也就是1ms,每个任务占据不同时间片,也就是时间片数*1ms=该任务获取调度后可以运行的时间(不算被中断打断的时间)
freeRTOS时间片每个任务固定为1个tick,也就是1ms,时间片数没找到,问的AI才知道每个任务的时间片数都是是固定为1的

configSYSTICK_CLOCK_HZ就是系统时钟,追踪路径

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐