STM32F103 实例应用(5)

您所在的位置:网站首页 微控制器的应用实例 STM32F103 实例应用(5)

STM32F103 实例应用(5)

2024-02-19 08:58| 来源: 网络整理| 查看: 265

一、定时器简介

STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器。 基本定时器 TIM6 和 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。 通用定时器 TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部 IO。 高级定时器 TIM1/8是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有 8 个外部 IO。 在这里插入图片描述

1.1 基本定时器功能

在这里插入图片描述

①时钟源 定时器时钟 TIMxCLK,即内部时钟 CK_INT,经 APB1 预分频器后分频提供,如果APB1 预分频系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系数是 2,即 PCLK1=36M,所以定时器时钟 TIMxCLK=36*2=72M。②计数器时钟 定时器时钟经过 PSC 预分频器之后,即 CK_CNT,用来驱动计数器计数。PSC 是一个16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。具体计算方式为:CK_CNT=TIMxCLK/(PSC+1)。③计数器 计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。④自动重装载寄存器 自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。 1.2 基本定时器时基

基本定时器的核心是时基,不仅基本定时器有,通用定时器和高级定时器也有。基本定时器与通用定时器的时基有3个(TIMx_CNT、TIMx_PSC、TIMx_ARR)。高级定时器的时基有4个(TIMx_CNT、TIMx_PSC、TIMx_ARR、TIMx_RCR)。

二、基本定时器使用流程 2.1 NVIC 设置 /** @brief NVIC初始化(使用TIM6基本定时器) @param 无 @return 无 */ void BASIC_TIM_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为 0 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断来源 NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn ; // 设置主优先级为 0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 设置抢占优先级为 3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } 2.2 定时器中断配置

在这里插入图片描述

/** @brief 定时器中断配置(使用TIM6基本定时器) @param 无 @return 无 */ void BASIC_TIM_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; /* 可以从上图看出基本定时器和通用定时器使用APB1总线, 高级定时器使用APB2总线。 */ // 开启定时器时钟,即内部时钟 CK_INT=72M RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); /* 预分频将输入时钟频率按1~65536之间的值任意分频,分频值决定了计数频率。 计数值为计数的个数,当计数寄存器的值达到计数值时,产生溢出,发生中断。 如系统时钟为72MHz,预分频 TIM_Prescaler = 71, 计数值 TIM_Period = 1000, 则 TIM_Period * (TIM_Prescaler + 1) / 72000000 = 0.001, 即每1ms产生一次中断。 */ // 自动重装载寄存器周的值(计数值) TIM_TimeBaseStructure.TIM_Period = 1000; // 累计 TIM_Period 个频率后产生一个更新或者中断 // 时钟预分频数为 71, // 则驱动计数器的时钟 CK_CNT = CK_INT / (71+1)=1M TIM_TimeBaseStructure.TIM_Prescaler = 71; // 时钟分频因子 ,基本定时器没有,不用管 //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置 //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,基本定时器没有,不用管 //TIM_TimeBaseStructure.TIM_RepetitionCounter=0; /* 完成时基设置 */ // 初始化定时器 TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); /* 为了避免在设置时进入中断,这里需要清除中断标志位。 如果是向上计数模式(基本定时器采用向上计数), 则采用函数 TIM_ClearFlag(TIM6, TIM_FLAG_Update), 清除向上溢出中断标志。 */ // 清除计数器中断标志位 TIM_ClearFlag(TIM6, TIM_FLAG_Update); // 使能计数器 TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE); // 开启计数器 TIM_Cmd(TIM6, ENABLE); // 暂时关闭定时器的时钟,等待使用 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, DISABLE); } 2.3 中断服务程序 #define BASIC_TIM_IRQHandler TIM6_IRQHandler // 1ms发生一次中断,time 记录中断次数 uint16_t time; void BASIC_TIM_IRQHandler(void) { if(TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) { time++; TIM_ClearITPendingBit(TIM6, TIM_FLAG_Update); } } 三、设计实例

board_timer.h

#ifndef BOARD_TIMER_H #define BOARD_TIMER_H /************************************************** * INCLUDES */ #include "stm32f10x.h" /************************************************** * DEFINITIONS */ #define BASIC_TIM_IRQHandler TIM6_IRQHandler /************************************************** * API FUNCTIONS */ void BASIC_TIM_Config(void); void BASIC_TIM_NVIC_Config(void); #endif

board_timer.c

#include "board_timer.h" /************************************************** * GLOBAL VALUE */ uint16_t time; /************************************************** * PUBLIC FUNCTIONS */ /** @brief NVIC初始化(使用TIM6基本定时器) @param 无 @return 无 */ void BASIC_TIM_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为 0 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断来源 NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn ; // 设置主优先级为 0 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 设置抢占优先级为 3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } /** @brief 定时器中断配置(使用TIM6基本定时器) @param 无 @return 无 */ void BASIC_TIM_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; /* 可以从上图看出基本定时器和通用定时器使用APB1总线, 高级定时器使用APB2总线。 */ // 开启定时器时钟,即内部时钟 CK_INT=72M RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); /* 预分频将输入时钟频率按1~65536之间的值任意分频,分频值决定了计数频率。 计数值为计数的个数,当计数寄存器的值达到计数值时,产生溢出,发生中断。 如系统时钟为72MHz,预分频 TIM_Prescaler = 71, 计数值 TIM_Period = 1000, 则 TIM_Period * (TIM_Prescaler + 1) / 72000000 = 0.001, 即每1ms产生一次中断。 */ // 自动重装载寄存器周的值(计数值) TIM_TimeBaseStructure.TIM_Period = 1000; // 累计 TIM_Period 个频率后产生一个更新或者中断 // 时钟预分频数为 71, // 则驱动计数器的时钟 CK_CNT = CK_INT / (71+1)=1M TIM_TimeBaseStructure.TIM_Prescaler = 71; // 时钟分频因子 ,基本定时器没有,不用管 //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置 //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,基本定时器没有,不用管 //TIM_TimeBaseStructure.TIM_RepetitionCounter=0; /* 完成时基设置 */ // 初始化定时器 TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); /* 为了避免在设置时进入中断,这里需要清除中断标志位。 如果是向上计数模式(基本定时器采用向上计数), 则采用函数 TIM_ClearFlag(TIM6, TIM_FLAG_Update), 清除向上溢出中断标志。 */ // 清除计数器中断标志位 TIM_ClearFlag(TIM6, TIM_FLAG_Update); // 使能计数器 TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE); // 开启计数器 TIM_Cmd(TIM6, ENABLE); // 暂时关闭定时器的时钟,等待使用 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, DISABLE); }

main.c

#include "board_timer.h" extern uint16_t time; int main() { /* 基本定时器 TIMx,x[6,7] 定时配置 */ BASIC_TIM_Config(); /* 配置基本定时器 TIMx,x[6,7]的中断优先级 */ BASIC_TIM_NVIC_Config(); /* 基本定时器 TIMx,x[6,7] 重新开时钟,开始计时 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); while(1) { if(time == 1000) { /* 1000 * 1 ms = 1s 时间到 */ time = 0; /* LED1 取反 */ static uint8_t tmp = 0; /*LED1 反转*/ if(tmp == 0) { // 该函数在GPIO输出章节中 UseLibSetOutput(GPIOB, GPIO_Pin_0,0); tmp = 1; } else { // 该函数在GPIO输出章节中 UseLibSetOutput(GPIOB, GPIO_Pin_0,1); tmp = 0; } } } return 0; }

• 由 青梅煮久 写于 2021 年 01 月 06 日



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3