STM32笔记之 Time(定时器)

写在前面:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。

目录

一、定时器简单介绍

二、高级控制定时器(TIM1 & TIM8)

三、通用定时器(TIM2 - TIM5)

四、基本定时器(TIM6 & TIM7)

五、代码实现


一、定时器简单介绍

        在大容量的 STM32F103xx增强型系列产品包含最多2个高级控制定时器、4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器,本次的目标芯片(STM32F103VET6)也是大容量系列,所以具备以上所述的定时器种类

根据上图我们可以划分出

定时器名称 功能等级
TIM1 高级控制定时器
TIM8
TIM2 通用定时器
TIM3
TIM4
TIM5
TIM6 基本定时器
TIM7

二、高级控制定时器(TIM1 & TIM8)

三、通用定时器(TIM2 - TIM5)

四、基本定时器(TIM6 & TIM7)

五、代码实现

        在本次例程中,使用 TIM2做一个固定的定时扫描定时器,拿来处理一些需要精准定时操作的东西;可能有人会问,为什么不直接用 Systick(滴答时钟)呢,还要重开一个定时器来做基准时间计时;要知道 Systick(滴答时钟)是硬件,也就是 CM3所提供的,之前那篇 STM32笔记之 Systick(滴答定时器)也有说 Systick最好的功能就是为 RTOS制作时钟节拍,而且,有这么多定时器可用,没必要用这么牛皮的定时嘛,除非真的不够用

bsp_time.c 源文件

#include "bsp_time.h"
#include "bsp_gpio.h"
#include "bsp_uart.h"


Time_TypeDef Time2;

/************************************************
函数名称 : Timer2_Config
功    能 : Timer2配置
参    数 : 无
返 回 值 : 无
*************************************************/
void Timer2_Config(void)
{
	uint16_t PrescalerValue = 0;
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	/* Compute the prescaler value */
	PrescalerValue = (uint16_t)(SystemCoreClock / 1000000) - 1;		// us
	
	/* TIM2 clock enable */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

	/* Enable the TIM2 global Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 1000 - 1;                    // 自动重装载寄存器的值
	TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;           // 时钟预分频数
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;         // 时钟分频因子
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     // 计数器计数模式
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;                // 重复计数器的值
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	
	/* Clear TIM2 update flag */
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);

	/* TIM2 IT enable */
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	/* Time2 counter enable */
	TIM_Cmd(TIM2, ENABLE);
}

/************************************************************************/
/*            STM32F10x Time Interrupt Handlers                         */
/************************************************************************/

/**
  * @brief  This function handles TIM2 global interrupt request.
  * @param  None
  * @retval None
  */
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) 
	{
		TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
		
		Time2.Time_ms++;                       // 毫秒计数
		if(1000 == Time2.Time_ms)
		{
			Time2.Time_ms = 0;                 // 秒计数
			Time2.Time_s++;
			if(Time2.Time_s > 60)
			{
				Time2.Time_s = 0;
			}
			GPIO_WriteBit(LED_GPIO_PORT, LED_GPIO_PIN, (BitAction)(1 - GPIO_ReadOutputDataBit(LED_GPIO_PORT, LED_GPIO_PIN)));  // LED每隔一秒闪烁
		}
		else if(0 == Time2.Time_ms % 50)       // 每隔 50ms检查
		{
			if(Usart1.Receiving_Time)
			{
				Usart1.Receiving_Time--;
				if(!Usart1.Receiving_Time)     // 接收超时
					Usart1.Frame_flag = 1;     // 串口一帧接收完成
			}
		}
	}		 	
}


/*---------------------------- END OF FILE ----------------------------*/


bsp_time.h 头文件

#ifndef __BSP_TIME_H
#define __BSP_TIME_H


#include "stm32f10x.h"

typedef struct
{
	uint16_t Time_ms;
	uint16_t Time_s;
}Time_TypeDef;
extern Time_TypeDef Time2;

void Timer2_Config(void);


#endif	/* __BSP_TIME_H */


/*---------------------------- END OF FILE ----------------------------*/

在 STM32库中,并没有提供像 C51那样 I/O位取反操作,所以想要利用库进行 I/O位取反,就只能像上面的 GPIO_WriteBit(LED_GPIO_PORT, LED_GPIO_PIN, (BitAction)(1 - GPIO_ReadOutputDataBit(LED_GPIO_PORT, LED_GPIO_PIN))) 操作,先把当前的 IO电平读出来再置反写入,当然,这样做会消耗点时间,毕竟只是为了实现一个功能就调用两个库函数;这里我们可以自己利用寄存器封装一个函数,毕竟 ST他不做,那我们就自己造,原理很简单,就像 C51那样,把对应的位取反就好了,先来看下与输出相关联的 IO寄存器先

所以我们就可以封装成下面的样子

/**
  * @brief  Reverse the selected data port bits.
  * @param  GPIOx: where x can be (A..G) to select the GPIO peripheral.
  * @param  GPIO_Pin: specifies the port bits to be written.
  *   This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
  * @retval None
  */
void GPIO_PinReverse(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  
  GPIOx->ODR ^= GPIO_Pin;
}
发布了40 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42992084/article/details/104099659
今日推荐