STM32学习笔记(3) TIM基本定时器
目录
1.基本定时器
2.基本定时器TIM的工作原理
2.1范例:定时1ms的计算
3.程序流程:
3.1配置时基初始化结构体
3.1.1时钟线的选择
3.1.2开启定时器更新中断
3.1.3TIM_ClearFlag()和函数TIM_ClearITPendingBit()区别
3.1.4允许更新中断函数及其寄存器DIER
3.2配置中断优先级
3.2.1移位
3.3使能定时器
3.4编写中断服务函数
3.5Main函数
4.代码示例
1.基本定时器
功能:定时,无PWM
● 计数器寄存器(TIMx_CNT)
● 预分频寄存器(TIMx_PSC)
● 自动重装载寄存器(TIMx_ARR)
2.基本定时器TIM的工作原理
来自内部时钟源的CK_PSC(频率=72MHz,72*10^6)进入到预分频器,预分频器PSC再对内部时钟CK_PSC分频,得到计数器时钟 CK_CNT = CK_PSC/(PSC+1)
当CNT_EN使能为1后,计数器CNT在CK_CNT时钟信号下,从0开始计数,电压周期性(计数一次的时间 1/CK_CNT) 的变为1/0,电压每变为1就记作是一次,当CNT的值与ARR的值相等时,就自动生成事件,且CNT自动清0,再重新开始计数
2.1范例:定时1ms的计算
PSC=72-1,72MHz=1/(72*10^6)usCNT=72MHz/(72-1+1)=1MHz=1us;即每过1us,有一次脉冲ARR=1000-1,从0计数到999,所以就记了1000次ARR*CNT=1ms
3.程序流程:
先配置中断,再配置TIM
3.1配置时基初始化结构体
TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;RCC_APB1PeriphClockCmd(TIM_CLK,ENABLE);TIM_BaseInitStructure.TIM_Prescaler=TIM_PRE-1;TIM_BaseInitStructure.TIM_Period=TIM_ARR-1;
首先肯定要开启时钟线啦,至于开哪条呢?下面我也展示出来了
3.1.1时钟线的选择
APB1外设时钟使能寄存器(RCC_APB1ENR)
【28】PWR_EN是电源
APB2 外设时钟使能寄存器(RCC_APB2ENR)
我们可以观察到,APB1往往跟四大通讯方式,基本定时器,通用定时器(TIM2~TIM7)有关
而APB2往往与GPIO,EXTI(AFIO),高级定时器(TIM1,TIM8),注意还有一个USART1
总而言之呢,APB2在我们项目中比较常用的一些模块
3.1.2开启定时器更新中断
TIM_ClearFlag(BASICTIM,TIM_FLAG_Update);//清除更新中断标志位
TIM_ITConfig(BASICTIM,TIM_IT_Update,ENABLE);//TIM_IT_Update,开启更新中断
3.1.3TIM_ClearFlag()
和函数TIM_ClearITPendingBit()区别
代码中有这样一条,有人会问函数TIM_ClearFlag()
和函数TIM_ClearITPendingBit()
有什么区别?其实重点在Flag和IT,前者是外设的状态标志,而后者是外设的中断标志。状态标志就是一个外设它有自身的一些标志位(Flag),来表明它处于什么状态,下图就是定时器的状态标记。中断标志就是使能外设的中断后,每次发生一次中断,它会表明发生了什么样的中断,同样中断也有相应的标记。两者分别靠函数TIM_GetFlagStatus()
和函数TIM_GetITStatus()
来获取
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG)
{ /* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_TIM_CLEAR_FLAG(TIM_FLAG));/* Clear the flags */TIMx->SR = (uint16_t)~TIM_FLAG;
}
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_TIM_IT(TIM_IT));/* Clear the IT pending Bit */TIMx->SR = (uint16_t)~TIM_IT;
}
可以看到,两个函数基本一样,只是对TIM_FLAG或TIM_IT操作不同
3.1.4允许更新中断函数及其寄存器DIER
对于允许更新中断函数
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
{ /* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_TIM_IT(TIM_IT));assert_param(IS_FUNCTIONAL_STATE(NewState));if (NewState != DISABLE){/* Enable the Interrupt sources */TIMx->DIER |= TIM_IT;}else{/* Disable the Interrupt sources */TIMx->DIER &= (uint16_t)~TIM_IT;}
}
可以简单看到,这个函数就是对中断使能寄存器【DIER】至0或至1操作
3.2配置中断优先级
NVIC_InitStructure.NVIC_IRQChannel=TIM_IRQN;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=NVIC_HIGHT_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=NVIC_LOW_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
我们可以看一下 NVIC_InitTypeDef 这个结构体里面都有什么
NVIC_IRQChannel
这一个是定义你的中断源,中断源可以在启动文件中找到
NVIC_IRQChannelPreemptionPriority
这一个是设置主优先级的结构体,由于我们是
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
所以范围只能选(0~3)
NVIC_IRQChannelSubPriority
设置从优先级,同理
那下面这句话有什么用呢
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
我们不妨先来看看这段NVIC_Init的函数
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;/* Check the parameters */assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority)); assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE){/* Compute the Corresponding IRQ Priority --------------------------------*/ tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;tmppre = (0x4 - tmppriority);tmpsub = tmpsub >> tmppriority;tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;tmppriority = tmppriority << 0x04;NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;/* Enable the Selected IRQ Channels --------------------------------------*/NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);}else{/* Disable the Selected IRQ Channels -------------------------------------*/NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);}
}
NVIC_InitStruct->NVIC_IRQChannelCmd会读取你是否是ENABLE,然后把配置好的主从优先级,中断源写进相关寄存器中
tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;
tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
这一段代码,主要是先判断选择了哪一组的中断分组,然后把主从优先级依次写进AIRCR寄存器中,因为AIRCR只有10-8位才是控制优先级的,所以我们需要移位
3.2.1移位
关于移位,我用C写了一小段代码,当作是复习
3.3使能定时器
TIM_Cmd(BASICTIM,ENABLE);//打开定时器
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
{/* Check the parameters */assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_FUNCTIONAL_STATE(NewState));if (NewState != DISABLE){/* Enable the TIM Counter */TIMx->CR1 |= TIM_CR1_CEN;}else{/* Disable the TIM Counter */TIMx->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));}
}
3.4编写中断服务函数
void TIM6_IRQHandler()
{if(TIM_GetFlagStatus(TIM6,TIM_FLAG_Update)!=RESET){N++;}TIM_ClearITPendingBit(TIM6,TIM_IT_Update);
}
3.5Main函数
//对基本定时器初始化
BasicTIM_Init();
4.代码示例
基本定时器示例
代码的移植性很高,里面也已经有大量的注释
STM32学习笔记(3) TIM基本定时器相关推荐
- STM32学习笔记(四)丨TIM定时器及其应用(定时中断、内外时钟源选择)
本篇文章包含的内容 一.TIM 定时器 1.1 TIM 定时器简介 1.2 TIM 定时器类型及其工作原理简介 1.2.1 基本定时器工作原理及其结构 1.2.2 通用定时器工作原理及其结构 1.2. ...
- STM32学习笔记(六)丨TIM定时器及其应用(输入捕获丨测量PWM波形的频率和占空比)
本篇文章包含的内容 一.输入捕获 1.1 输入捕获简介 1.2 输入捕获通道的工作原理 1.3 输入捕获的主从触发模式 1.4 输入捕获和PWMI结构 二.频率的测量方法 2.1 测频法 2.2 测周 ...
- STM32学习笔记(10)——高级定时器TIM
前排提示:本笔记参考了野火PPT的大部分内容.本人初学定时器,倍感冗杂,有错烦请指出,谢谢! STM32学习笔记(10)--高级定时器TIM 一.时钟源 1. 内部时钟源 2. 外部时钟模式 1 (1 ...
- STM32学习笔记(八)丨ADC模数转换器(ADC单、双通道转换)
本篇文章包含的内容 一.ADC 模数转换器 1.1 ADC简介 1.2 逐次逼近型ADC工作原理 1.3 STM32中的ADC基本结构 1.4 STM32中ADC的输入通道 1.5 STM32中的AD ...
- STM32学习笔记(三)丨中断系统丨EXTI外部中断(对射式红外传感器计次、旋转编码器计次)
本篇文章包含的内容 一.中断系统 1.1 中断的定义 1.2 中断优先级 1.3 中断的嵌套 1.4 STM32中的中断系统 1.4.1 STM32的中断资源 1.4.2 嵌套中断向量控制器 NVIC ...
- 《STM32学习笔记》4——核心功能电路与编程(下)
接上文,文中的图片,大多数来自视频的截图(来自洋桃电子). 欢迎大家批评指正! STM32学习笔记-专栏 文章目录 一.蜂鸣器驱动 1.蜂鸣器介绍 2.蜂鸣器电路 3.蜂鸣器程序 二. MIDI 音乐 ...
- 硬件学习、高速dsp开发板制作、STM32学习笔记
1.硬件工程师成长之路(1)--元件基础_[云轩]的博客-CSDN博客_硬件工程师的成长之路 总目录:https://blog.csdn.net/weixin_44407238/category_10 ...
- 《STM32学习笔记》3——核心功能电路与编程(上)
接上文,文中的图片,大多数来自视频的截图(来自洋桃电子). 欢迎大家批评指正! STM32学习笔记-专栏 文章目录 一.核心板电路分析 二.点灯 LED 1.LED电路 2.LED功能相关初始化配置 ...
- STM32学习笔记(七)---SysTick
STM32学习笔记(七)-SysTick 文章目录 STM32学习笔记(七)---SysTick 一.SysTick简介 二.SysTick功能框图 三.SysTick寄存器 四.SYSTICK使用 ...
- STM32学习笔记——基于正点原子例程编码器模式小结
STM32学习笔记--基于正点原子例程编码器模式小结 最近一段时间学习了,STM32f4的编码器功能,经过自己探索和他人的热心帮助,对于编码器模式有了一定了解.STM32f4单片机提供编码器模式,以便 ...
最新文章
- 一文全面解析 Postman 工具
- VRRP与VLAN实验(HuaWei)
- 9-Building FIP images with support for Trusted Board Boot
- 1337:【例3-2】单词查找树
- 中根遍历二叉查找树所得序列一定是有序序列_二叉搜索树(BST)
- “3+3”看华为云FusionInsight如何引领“数据新基建”持续发展
- MySQL自动化审核平台部署说明
- Linux 命令(131)—— usermod 命令
- 各种翻页的效果! FILTER: revealTrans使用说明
- 恒生电子:O45好在哪儿(深度)| 国君计算机李沐华
- android studio怎么创建布局,Android Studio--活动创建简单布局
- Could not initialize class com.android.build.gradle.internal.VariantManager解决方案
- 解决Chrome账户无法同步
- 第五课:实现花样流水灯
- arm linux关机命令,嵌入式Linux的关闭命令是什么?
- 1、零基础学工控——初识plc
- 小马哥----高仿苹果6s 主板型号S106s 更换内核 刷机拆机主板图与开机识别图
- 操作系统学习——分时操作系统
- nginx通过获取环境变量实现动态IP代理配置
- warning: go env -w GO111MODULE=... does not override conflicting OS environment variable
热门文章
- 计算机基础 进制转化,计算机基础知识_进制转化(示例代码)
- 【C生万物】 指针篇 (进级) 上
- Kettle Could not initialize class org.apache.batik.bridge.CursorManager
- 微信的一些优点整理(持续更新)
- CSDN 的中铁粉是什么?如何获得粉丝与铁粉呢?一篇文章告诉你,干货满满,建议收藏
- 数据分析技能点-Excel的36个常规操作
- RuntimeError: cuda runtime error (30) : unknown error at /pytorch/aten/src/THC/THCGeneral.cpp:50
- keil 跳转不了(Go To Definition “XXX”失败)
- 现代OpenGL学习笔记二:第一个三角形
- 博弈论——万元陷阱和智猪博弈