STM32——timer
原文地址:
http://blog.sina.com.cn/s/blog_49cb42490100s6ud.html
1. STM32的Timer简介
STM32中一共有11个定时器,其中2个高级控制定时器,4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。其中系统嘀嗒定时器是前文中所描述的SysTick,看门狗定时器以后再详细研究。今天主要是研究剩下的8个定时器。
|
定时器 |
计数器分辨率 |
计数器类型 |
预分频系数 |
产生DMA请求 |
捕获/比较通道 |
互补输出 |
|
TIM1 TIM8 |
16位 |
向上,向下,向上/向下 |
1-65536之间的任意数 |
可以 |
4 |
有 |
|
TIM2 TIM3 TIM4 TIM5 |
16位 |
向上,向下,向上/向下 |
1-65536之间的任意数 |
可以 |
4 |
没有 |
|
TIM6 TIM7 |
16位 |
向上 |
1-65536之间的任意数 |
可以 |
0 |
没有 |
其中TIM1和TIM8是能够产生3对PWM互补输出的高级登时其,常用于三相电机的驱动,时钟由APB2的输出产生。TIM2-TIM5是普通定时器,TIM6和TIM7是基本定时器,其时钟由APB1输出产生。由于STM32的TIMER功能太复杂了,所以只能一点一点的学习。因此今天就从最简单的开始学习起,也就是TIM2-TIM5普通定时器的定时功能。
2. 普通定时器TIM2-TIM5
2.1 时钟来源
计数器时钟可以由下列时钟源提供:
·内部时钟(CK_INT)
·外部时钟模式1:外部输入脚(TIx)
·外部时钟模式2:外部触发输入(ETR)
·内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。
由于今天的学习是最基本的定时功能,所以采用内部时钟。TIM2-TIM5的时钟不是直接来自于APB1,而是来自于输入为APB1的一个倍频器。这个倍频器的作用是:当APB1的预分频系数为1时,这个倍频器不起作用,定时器的时钟频率等于APB1的频率;当APB1的预分频系数为其他数值时(即预分频系数为2、4、8或16),这个倍频器起作用,定时器的时钟频率等于APB1的频率的2倍。APB1的分频在STM32_SYSTICK的学习笔记中有详细描述。通过倍频器给定时器时钟的好处是:APB1不但要给TIM2-TIM5提供时钟,还要为其他的外设提供时钟;设置这个倍频器可以保证在其他外设使用较低时钟频率时,TIM2-TIM5仍然可以得到较高的时钟频率。
2.2 计数器模式
TIM2-TIM5可以由向上计数、向下计数、向上向下双向计数。向上计数模式中,计数器从0计数到自动加载值(TIMx_ARR计数器内容),然后重新从0开始计数并且产生一个计数器溢出事件。在向下模式中,计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。而中央对齐模式(向上/向下计数)是计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
2.3 编程步骤
1. 配置系统时钟;
2. 配置NVIC;
3. 配置GPIO;
4. 配置TIMER;
其中,前3项在前面的笔记中已经给出,在此就不再赘述了。第4项配置TIMER有如下配置:
(1) 利用TIM_DeInit()函数将Timer设置为默认缺省值;
(2) TIM_InternalClockConfig()选择TIMx来设置内部时钟源;
(3) TIM_Perscaler来设置预分频系数;
(4) TIM_ClockDivision来设置时钟分割;
(5) TIM_CounterMode来设置计数器模式;
(6) TIM_Period来设置自动装入的值
(7) TIM_ARRPerloadConfig()来设置是否使用预装载缓冲器
(8) TIM_ITConfig()来开启TIMx的中断
其中(3)-(6)步骤中的参数由TIM_TimerBaseInitTypeDef结构体给出。步骤(3)中的预分频系数用来确定TIMx所使用的时钟频率,具体计算方法为:CK_INT/(TIM_Perscaler+1)。CK_INT是内部时钟源的频率,是根据2.1中所描述的APB1的倍频器送出的时钟,TIM_Perscaler是用户设定的预分频系数,其值范围是从0 – 65535。
步骤(4)中的时钟分割定义的是在定时器时钟频率(CK_INT)与数字滤波器(ETR,TIx)使用的采样频率之间的分频比例。TIM_ClockDivision的参数如下表:
|
TIM_ClockDivision |
描述 |
二进制值 |
|
TIM_CKD_DIV1 |
tDTS = Tck_tim |
0x00 |
|
TIM_CKD_DIV2 |
tDTS = 2 * Tck_tim |
0x01 |
|
TIM_CKD_DIV4 |
tDTS = 4 * Tck_tim |
0x10 |
数字滤波器(ETR,TIx)是为了将ETR进来的分频后的信号滤波,保证通过信号频率不超过某个限定。
步骤(7)中需要禁止使用预装载缓冲器。当预装载缓冲器被禁止时,写入自动装入的值(TIMx_ARR)的数值会直接传送到对应的影子寄存器;如果使能预加载寄存器,则写入ARR的数值会在更新事件时,才会从预加载寄存器传送到对应的影子寄存器。
ARM中,有的逻辑寄存器在物理上对应2个寄存器,一个是程序员可以写入或读出的寄存器,称为preload register(预装载寄存器),另一个是程序员看不见的、但在操作中真正起作用的寄存器,称为shadow register(影子寄存器);设计preload register和shadow register的好处是,所有真正需要起作用的寄存器(shadow register)可以在同一个时间(发生更新事件时)被更新为所对应的preload register的内容,这样可以保证多个通道的操作能够准确地同步。如果没有shadow register,或者preload register和shadow register是直通的,即软件更新preload register时,同时更新了shadow register,因为软件不可能在一个相同的时刻同时更新多个寄存器,结果造成多个通道的时序不能同步,如果再加上其它因素(例如中断),多个通道的时序关系有可能是不可预知的。
3. 程序源代码
本例实现的是通过TIM2的定时功能,使得LED灯按照1s的时间间隔来闪烁
#include "stm32f10x_lib.h"
void RCC_cfg();
void TIMER_cfg();
void NVIC_cfg();
void GPIO_cfg();
int main()
{
RCC_cfg();
NVIC_cfg();
GPIO_cfg();
TIMER_cfg();
//开启定时器2
TIM_Cmd(TIM2,ENABLE);
while(1);
}
void RCC_cfg()
{
//定义错误状态变量
ErrorStatus HSEStartUpStatus;
//将RCC寄存器重新设置为默认值
RCC_DeInit();
//打开外部高速时钟晶振
RCC_HSEConfig(RCC_HSE_ON);
//等待外部高速时钟晶振工作
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
//设置AHB时钟(HCLK)为系统时钟
RCC_HCLKConfig(RCC_SYSCLK_Div1);
//设置高速AHB时钟(APB2)为HCLK时钟
RCC_PCLK2Config(RCC_HCLK_Div1);
//设置低速AHB时钟(APB1)为HCLK的2分频
RCC_PCLK1Config(RCC_HCLK_Div2);
//设置FLASH代码延时
FLASH_SetLatency(FLASH_Latency_2);
//使能预取指缓存
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//设置PLL时钟,为HSE的9倍频 8MHz * 9 = 72MHz
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//使能PLL
RCC_PLLCmd(ENABLE);
//等待PLL准备就绪
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
//设置PLL为系统时钟源
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//判断PLL是否是系统时钟
while(RCC_GetSYSCLKSource() != 0x08);
}
//允许TIM2的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//允许GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
}
void TIMER_cfg()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//重新将Timer设置为缺省值
TIM_DeInit(TIM2);
//采用内部时钟给TIM2提供时钟源
TIM_InternalClockConfig(TIM2);
//预分频系数为36000-1,这样计数器时钟为72MHz/36000 = 2kHz
TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;
//设置时钟分割
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//设置计数器模式为向上计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//设置计数溢出大小,每计2000个数就产生一个更新事件
TIM_TimeBaseStructure.TIM_Period = 2000 - 1;
//将配置应用到TIM2中
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
//清除溢出中断标志
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
//禁止ARR预装载缓冲器
TIM_ARRPreloadConfig(TIM2, DISABLE);
//开启TIM2的中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
}
void NVIC_cfg()
{
NVIC_InitTypeDef NVIC_InitStructure;
//选择中断分组1
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//选择TIM2的中断通道
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;
//抢占式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
//响应式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
//使能中断
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void GPIO_cfg()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //选择引脚5
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出频率最大50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //带上拉电阻输出
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
在stm32f10x_it.c中,我们找到函数TIM2_IRQHandler(),并向其中添加代码
void TIM2_IRQHandler(void)
{
u8 ReadValue;
//检测是否发生溢出更新事件
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
//清除TIM2的中断待处理位
TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
//将PB.5管脚输出数值写入ReadValue
ReadValue = GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5);
if(ReadValue == 0)
{
GPIO_SetBits(GPIOB,GPIO_Pin_5);
}
else
{
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
}
}
}
STM32——timer的更多相关文章
- STM32 Timer Clock sources -- External Clock Both Edge
Timers get their clock source from External pins or Internal timer sources. External External = pins ...
- STM32 Timer : Base Timer, Input Capture, PWM, Output Compare
http://www.cs.indiana.edu/~geobrown/book.pdf An example of a basic timer is illustrated in Figure 10 ...
- STM32: TIMER门控模式控制PWM输出长度
搞了两天单脉冲没搞定,无意中发现,这个利用主从模式的门控方式来控制一路PWM的输出长度很有效. //TIM2 PWM输出,由TIM4来控制其输出与停止 //frequency_tim2:TIM2 PW ...
- STM32 TIMER OUTPUT DIAGRAM
- STM32 TIMER DIAGRAM
- STM32 TIMER REGISTER
- STM32 Timer : Auto-reload register register
Auto-reload register (TIMx_ARR) The auto-reload register is preloaded. Writing to or reading from th ...
- STM32:TIMER PWM 输入检测
PWM输入检测是输入捕获的一个特例,可以测量频率与占空比 与输入捕获不同的是PWM输入模式会将同一个输入信号(TI1或TI2)连接到两个捕获装置(IC1和IC2).这两个捕获装置一个捕获上升沿一个捕获 ...
- Stm32高级定时器(四)
Stm32高级定时器(四) 1 编码器接口模式 1.1 编码器原理 什么是正交?如果两个信号相位相差90度,则这两个信号称为正交.由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向.根 ...
随机推荐
- HDU 2102 A计划 经典搜索
A计划 Time Limit : 3000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submissio ...
- git:解决The current branch is not configured for pull No value for key branch.master.merge found in config
网上多半都是命令行下的解决方案,我用的是EGit,所以要在eclipse里(我的版本是kepler)把下面这句话添加到配置文件中. Window->Preference->Team-> ...
- android使用support的ActionBar时遇到的问题
多从网上下载好了support library之后,把android-support-v7-appcompat.jar放到了libs目录下,并加入到了编译路径,本以为万事大吉,可是却报了下面的一个错误 ...
- zf-关于通知公告显示问题
1 公告结束日期超过当前时间是不能在通知公告上显示出来的 2 无限制时间的公告也是要在通知公告上显示出来的 于是我在后台实现类增加了如下代码 需要注意的是 当初解决第一个问题的时候增加了一个AND 当 ...
- tcp 重组原理
原文: http://blog.chinaunix.net/uid-21768364-id-4823449.html 1 .引言TCP/IP 协议现在已经广泛的被应用.数据在网络上应用 TCP/IP ...
- expdp.sh and impdp.sh
####expdp.sh ###### ------------- -- UAT -- ------------- @D:\dba\change\UAT\eais\env\env_eaisua ...
- photoshop基础教程视频-贺叶铭-传智播客-笔记
界面构成 1.菜单栏 2.工具箱 3.工具属性栏 4.悬浮面板 5.画布 ctrl+n 新建对话框 (新建画布) 画布200*200大小,是指以毫米为单位,当不说单位,默认是毫米. 打开对话框:ctr ...
- 我的第一个Android项目之环境搭建
开发IDE Android Studio2.0 + Genymotion + JDK1.8 网盘地址:http://pan.baidu.com/s/1kUSVqaN Android Studio 我的 ...
- HDU 4421 ZOJ 3656 Bit Magic
2-SAT,不要所有位置全部建好边再判断,那样会MLE的. 正解是,每一位建好边,就进行一次2-SAT. #include<cstdio> #include<cstring> ...
- 基于Nginx的Rtmp流媒体服务器环境搭建
一.编译安装 wget http://nginx.org/download/nginx-1.4.2.tar.gz wget https://github.com/arut/nginx-rtmp-mod ...