STM32 定时器

Posted 一只小阿大嗷

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32 定时器相关的知识,希望对你有一定的参考价值。

三种定时器的区别

STM32F1xx系列总共有 八个定时器
两个高级定时器 + 四个通用定时器 + 两个基本定时器
在这里插入图片描述

通用定时器的特点描述

1.位于ABP1低速总线上
2.16位向下,向上/向下(中心对齐模式)计数模式,自动重装载计数器(TIMx_CNT)
3.16位可编程(可以实现修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为1~65535任意数值
4.四个独立通道(TIMx_CH1~4),通道用来支持:
①输入捕获
②输出比较
③PWM生成
④单脉冲模式输出
5.可使用外部信号(TIM_ETR)控制定时器和定时器互连的同步电路。

AHB系统总线是72M的,桥接出来的APB2也是72M的,APB1有个二分频,所以是36M,是低速的时钟。
在这里插入图片描述
定时器中断/事件产生 : (六个独立的IRQ/DMA 请求生成器)

①更新: 计数器向上/向下溢出,计数器初始化(软件或者外部/内部触发)
②触发事件:计数器的启动,停止,初始化或者由内部/外部触发计数
③输入捕获
④输出比较
⑤支持针对定位的增量编码器和霍尔传感器电路
⑥触发输入作为外部时钟或者按周期的电流管理

STM32通用定时器 可以被用于:测量输入信号的脉冲长度(输入捕获),或者产生输入波形(输出比较和PWM)等。

定时器的预分频器和RCC时钟控制预分频器,脉冲长度和波形周期可以在us到ms之间调整,每个通用定时器都是完全独立,没有互相共享任何内存。

计数器模式

STM32通用定时器 可以向上,向下,向上/向下双向计数模式
① 向上计数模式:计数值从0 计数到自动加载值(TIM_ARR),产生一个计数溢出事件,然后重新从0开始计数
②向下计数模式:计数器从自动装入的值(TIM_ARR)开始向下计数到0,产生一个计数溢出事件,然后从计数装入值重新开始。
③中央对齐模式:计数器从0开始到(自动装入值-1),产生计数溢出事件,然后向下计数到1,产生定时器溢出事件,然后从0开始计数。
在这里插入图片描述

通用定时器工作过程

1.时钟部分(时钟来源)

①内部时钟APB1倍频器
②外部引脚(通用定时器2,3,4)
③其他定时器
④外部通道

2.时基单元

①预分频(除法)
②计数器时钟
③自动重装载值

3.输入部分

①输入引脚
②边沿检测

4.输出部分

①输出比较寄存器
周期—重装载值
占空比—比较值
在这里插入图片描述

计数器时钟计算方法

在这里插入图片描述
CK_INT定时器时钟,APB1到CK_INT会 乘于1或者除于2
为什么要 乘于1或者除于2?
在这里插入图片描述
除非APB1分频系数为1,否则通用定时器时钟为PAB1的两倍

举例:
AHB= 72M
APB1=36M (分频系数为2)
通用定时器时钟为 36 x2= 72M

CK_PSC:预分频器时钟的频率
在这里插入图片描述
CK_PSC分频多少就除于N,就可以得到CK_CNT(计数器的频率)

定时器相关寄存器

1.计数器寄存器CNT : 当前计数值
2.预分频寄存器 : 分频系数 (PSC+1) / N = CNT
3.自动重装载寄存器: 重装载值
4.控制寄存器: 控制计数方向

定时器库函数结构体

常用的是前四个成员,后面一个用于高级定时器
typedef struct
{
uint16_t TIM_Prescaler; //初始化预分频值
uint16_t TIM_Period; //设定自动装载值
uint16_t TIM_CounterMode; //设定计数模式
uint16_t TIM_ClockDivision; //输入捕获使用
uint8_t TIM_RepetitionCounter; //高级定时器使用

} TIM_TimeBaseInitTypeDef;

定时器库函数结构体

void TIM_TimeBaseInit 定时器初始化
(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

void TIM_Cmd 定时器使能
(TIM_TypeDef* TIMx, FunctionalState NewState);

FlagStatus TIM_GetFlagStatus 定时器状态标志位
(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);

void TIM_ClearFlag 定时器清楚标志位
(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);

ITStatus TIM_GetITStatus 定时器中断标志位
(TIM_TypeDef* TIMx, uint16_t TIM_IT);

void TIM_ClearITPendingBit 定时器清楚中断标志位
(TIM_TypeDef* TIMx, uint16_t TIM_IT);

定时器总断配置过程

1.使能时钟 定时器时钟
2. 配置定时器结构体 ,
3.开启定时器中断,配置中断结构体
4.中断服务函数

定时器配置LED每秒闪烁一次
Tout = [ 重装载值(ARR+1) * 分频系数(PSC+1)] /Tclk(定时器的时钟)

Tout = 100000(9999+1) *7200(分频系数 7199+1) /72M(72 000 000)

通过定时器让LED灯间隔1s闪烁

led.h

#include "stm32f10x.h"
void Led_init(void);

led.c

#include "stm32f10x.h"
#include "led.h"

void Led_init(void)
{
	GPIO_InitTypeDef Led_init;
	
	//1.ʹÄÜAPB2µÄʱÖÓGPIO
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
	//2.½á¹¹ÌåÅäÖÃ
	Led_init.GPIO_Mode 	= GPIO_Mode_Out_PP;
	Led_init.GPIO_Pin	  = GPIO_Pin_13;
	Led_init.GPIO_Speed = GPIO_Speed_10MHz;
	
	GPIO_Init(GPIOC, &Led_init);
}

tim.h

#include "stm32f10x.h"
void tim_Init(void);

tim.c

#include "stm32f10x.h"
#include "tim.h"

/*
	1.ʹÄÜʱÖÓ£¬¶¨Ê±Æ÷ʱÖÓ
	2.ÅäÖö¨Ê±Æ÷½á¹¹Ìå
	3.¿ªÆô¶¨Ê±Æ÷Öжϣ¬ÅäÖÃÖжϽṹÌå
*/

void tim_Init(void)
{
	TIM_TimeBaseInitTypeDef timInitStruct;
	NVIC_InitTypeDef        nvicInitStruct;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

	timInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	timInitStruct.TIM_CounterMode   = TIM_CounterMode_Up;
	timInitStruct.TIM_Period			  = 10000 - 1;
	timInitStruct.TIM_Prescaler     = 7200  - 1;
	TIM_TimeBaseInit(TIM2,&timInitStruct);
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	TIM_Cmd(TIM2,ENABLE);

	nvicInitStruct.NVIC_IRQChannel 									 = TIM2_IRQn;
	nvicInitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	nvicInitStruct.NVIC_IRQChannelSubPriority 			 = 1;
	nvicInitStruct.NVIC_IRQChannelCmd 							 = ENABLE;
	NVIC_Init(&nvicInitStruct);

}

main.c

#include "stm32f10x.h"
#include "led.h"
#include "relay.h"
#include "shake.h"
#include "exti.h"
#include "usart.h"
#include "stdio.h"
#include "tim.h"

void delay(uint16_t time)
{
	uint16_t i =0;
	while(time--){
		i=12000;
		while(i--);
	}
}

int main()
{
	Led_init();
	Relay_Init();
	Shake_init();
	exti_init();
	usart_init();
	tim_Init();
	
	//³õʼ»¯Òý½Å
	GPIO_SetBits(GPIOA, GPIO_Pin_3);
	GPIO_SetBits(GPIOC, GPIO_Pin_13);

//	while(1)
//	{
//		usartSendStr(USART1,"°ÂÀï¸ø\\r\\n");
//		int i = printf("Finny\\r\\n");
//		printf("%d\\r\\n",i);
//		putchar('2');
		
//		delay(1000);
//	}

}

//ÍⲿÖжÏ
//void EXTI1_IRQHandler(void)
//{
//	if (EXTI_GetITStatus( EXTI_Line1 ) != RESET){// ÅжÏÊÇ·ñ·¢ÉúÖжÏ
//		GPIO_ResetBits(GPIOA, GPIO_Pin_3);
//		usartSendStr(USART1,"Open light success\\r\\n");
//		delay(1000);
//		GPIO_SetBits(GPIOA, GPIO_Pin_3);
//		usartSendStr(USART1,"Close light success\\r\\n");
//	}

//	EXTI_ClearFlag(EXTI_Line1);
//	
//}

//´®¿ÚÖжÏ
//void USART1_IRQHandler(void)
//{
//	char temp;
//	
//	if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET){
//		
//		temp = USART_ReceiveData(USART1);

//		if(temp == 'o'){
//			GPIO_ResetBits(GPIOC, GPIO_Pin_13);
//			usartSendStr(USART1,"Open LED light success\\r\\n");
//		}
//		
//		if(temp == 'c'){
//			GPIO_SetBits(GPIOC, GPIO_Pin_13);
//			usartSendStr(USART1,"Close LED light success\\r\\n");
//		}
//		
//	}

//}
	
//¶¨Ê±Æ÷ÖжÏ
void TIM2_IRQHandler(void)
{
	static uint16_t temp;
	if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
	{
		if(temp++ %2 == 1){
			GPIO_ResetBits(GPIOC, GPIO_Pin_13);
		}else{
			GPIO_SetBits(GPIOC, GPIO_Pin_13);
		}
		
	}
	TIM_ClearITPendingBit(TIM2,TIM_IT_Update);

}

以上是关于STM32 定时器的主要内容,如果未能解决你的问题,请参考以下文章

如何让stm32产生多路输出 PWM 最好有代码

STM32CubeMX-定时器产生PWM驱动舵机

STM32定时器溢出模式计时设置

STM32F103VET6基于STM32CubeMX创建定时器中断控制LED闪烁

STM32学习笔记

stm32-定时器中断