分为四部分
1、定时器基本定时功能功能——定一个时间,让定时器每个这个时间产生一个中断——实现——每隔一个固定时间执行一段程序的目的
2、定时器输出比较——常见用途——产生PWM波形、用于驱动电机
3、定时器输入捕获——实现——测量方波频率
4、定时器的编码器接口——更加方便读取正交编码器的输出波形——编码电机测速
定时器——instinct——计数器
- 当此计数器的输入是一个准确可靠的基准时钟,当它对此基准时钟计数的过程,实际也就是计时的过程,例如STM32中,定时器的基准时钟——主频72MHz,如果我对72MHz计72个数,那么1MHz即也就是1us的时间
- 实现最大59.65s的定时 = 1/(72M/65536/65536)
- (72M/65536/65536)——中断频率
- 1/(72M/65536/65536)——中断定时时间
级联定时器
级联一个定时器——59.65s * 65536 *65536 = 8千多年
通向时基单元的计数基准频率是72MHz
基本定时器
时基单元——预分频器16位——对72MHz的计数时钟进行预分频
- 预分频器寄存器写0——一分频、不分频——output频率 = input频率 = 72MHz
- 预分频器寄存器写1——二分频——output频率 = input频率 = 72MHz/2 = 36MHz
- 预分频器寄存器写2——三分频——output频率 = input频率 = 72MHz/3 = 18MHz
- 实际分频系数 = 预分频器的值 + 1
- 最大值可以写65535,即也就是65536分频
- function:对输入的基准频率提前进行分频操作
时基单元——CNT计数器16位
- function:对预分频后的计数时钟进行计数
时基单元——自动重装寄存器
- function:存储目标值的寄存器
- 计数值 = 自动重装值产生的中断——更新中断
——之后这个更新中断通往NVIC,我们再配置好NVIC的定时器通道——》则此时定时器的更新中断就能得到CPU的响应
更新事件——更新事件不会触发中断,但可以触发内部其他电路工作
主模式触发DAC的功能
- function——让内部硬件在不受程序的控制下实现自动运行
- 使用好——在某些情境下,会极大减轻CPU的负担
- 向上计数模式——从0开始自增**
- 向下计数模式——从重装值开始向下自减,减到0之后,回到重装值,同时申请中断
- 中央对齐模式——从0开始先向上自增,计到重装值,申请中断,而后向下自减,减到0,再申请中断
- 基本定时器仅支持向上计数这一种模式且只能选择内部时钟,即也就是系统频率72MHz
- 通用定时器、高级定时器支持以上三种模式
- 通用定时器选择72MHz内部时钟、外部时钟
今天效率有点低下了
中断输出控制即就是中断的允许位
研究时基单元运行的一些细节问题
预分频器为了防止计数中途更改数值造成错误——缓冲、影子寄存器——in order to——值的变化和更新事件同步发送
- SystemInit函数——配置时钟树——先启动内部时钟(RC振荡器)8MHz为系统时钟——》再启动外部时钟——外部晶振(石英振荡器OSC) ——》进入PLL锁相环进行倍频,8MHz倍频9倍 = 72MHz——》锁相环输出稳定后,选择锁相环输出为系统时钟
- 以上实现了把系统时钟由8MHz切换至72MHz
若你的外部时钟出现问题,导致结果——你的程序时钟慢了大概10倍
CSS——Clock Security System——时钟安全系统
- fuction:检测外部时钟的运行状态,若外部时钟出现故障,会将系统时钟由外部时钟切换成内部时钟——保证系统时钟的运行,防止程序卡死造成事故
我们的基本定时器、通用定时器接在APB1上——36MHz ,但是,我们又说,所有的定时器时钟都是72MHz,why?
因为下图
滤波器——滤掉信号的抖动干扰——参数——采样频率f、采样点数N
- 如何工作??——在固定的时钟频率f下采样,连续N个采样点为相同电平——输入信号稳定
- 采样频率f从何而来?
- 手册中写道可由内部时钟直接而来,也可以由内部时钟加一个时钟分频而来,那么分频多少即由参数
决定
关于TIM的重要函数
时基单元初始化
使能计数器——运行控制
使能中断输出信号——中断输出控制
时基单元的内部选择——RCC外部时钟、ETR外部时钟、ITRx其他定时器、TIx捕获通道
- 定时1s——定时频率=1Hz
TIM_BaseInitStructure.TIM_Period = 10000 - 1;//周期——ARR自动重装器的值 TIM_BaseInitStructure.TIM_Prescaler = 7200 - 1;//PSC预分频器的值 // 计数器预分频器都有一个属的偏差
- 注意i:PSC、ARR的取值在0-65535之间
- 预分频PSC对72M进行7200分频,得到10k的计数频率,在10k频率下计10000个数 = 1s
关于NVIC的小小使用技巧:
跨文件变量
//Num在中断函数里执行++,但中断函数是在Timer模块里的,若直接在Timer模块里写Num++,则Num成为跨越不同.c文件的变量
solutions——solution1使用跨文件变量,用extern声明
1.若想使用跨文件变量,可以在使用变量的那个文件上面用extern声明一下要使用的变量
solution2——直接复制中断函数,放置主函数main.c之后
找出图片上的错误
现在问题出现:我的OLED显示屏的Num数值不会自我更新
- 经排查,是
的问题
- 我好像开启了TIM12的时钟——找准病根,稳准狠出击
老师提出的问题——复位后,Num从1 开始计数,即一上电,Num立即变为1——说明——中断函数在初始化之后就立即进入了一次
老师的研究
- 原因——预分频器有缓存寄存器、影子寄存器,我们写的值只有在更新事件时,才会真正起作用——目的:为了让值value立刻immediately起作用——在最后,手动生成一个更新事件——》这样,预分频器PSC的值就有效了——副作用——更新事件、更新中断同时发生,更新中断会置更新中断标志位,一旦初始化完成,更新中断立即进入——即就是我们刚一上电,就进入中断的原因
- solution——//手动清除更新中断标志位,可以避免刚初始化完就进入中断
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
//手动清除更新中断标志位,可以避免刚初始化完就进入中断
预分频值和自动重装值对中断频率的影响
6-1 定时器的内部时钟思路步骤
- // 1.RCC开启时钟——定时器基准时钟、整个外设工作时钟
- // 2.选择时基单元的时钟源——内部时钟源——定时器上电后默认为使用内部时钟
- // 3.配置时基单元
- // 4.配置输出中断控制,允许更新中断输出到NVIC —— 开启中断
- // 5.配置NVIC,在NVIC中打开定时器中断通道,并且分配一个优先级
- // 6.运行控制——使能计数器
6-2 定时器的外部时钟
老师不太喜欢浮空输入——因为一旦悬空,电平就会跳个没完
浮空输入——使用条件——外部的输入信号功率很小,内部上拉电阻可能会影响到这个输入信号,来防止影响外部输入的电平