目录
14.6 使用高级定时器实现精确计时
14.6.1 实验要求
使用高级定时器实现LED灯和蜂鸣器状态1s翻转一次。
14.6.2 软件设计
14.6.2.1 设计思路
首先对高级定时器的时钟,周期,中断等信息进行宏定义即bsp_AdvanceTim.h文件便于之后对代码的移植,完成后需要对定时器的模式和中断优先级进行配置即bsp_AdvaceTim.c文件,配置完成过后还需要在stm32f10x_it.c文件中编写中断服务函数,以上都完成后就能够在main.c文件中编写我们所需要的功能代码了。
14.6.2.2 代码分析
bsp_AdvanceTim.h
#ifndef _BSP_ADVANCETIM_H
#define _BSP_ADVANCETIM_H
#include "stm32f10x.h"
#define ADVANCE_TIM1
#ifdef ADVANCE_TIM1 //使用高级定时器1
#define ADVANCE_TIM TIM1
#define ADVANCE_TIM_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADVANCE_TIM_CLK RCC_APB2Periph_TIM1
#define ADVANCE_TIM_Period (1000-1)
#define ADVANCE_TIM_Prescaler 71
#define ADVANCE_TIM_IRQ TIM1_UP_IRQn
#define ADVANCE_TIM_IRQHandler TIM1_UP_IRQHandler
#else //使用高级定时器8
#define ADVANCE_TIM TIM8
#define ADVANCE_TIM_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADVANCE_TIM_CLK RCC_APB2Periph_TIM8
#define ADVANCE_TIM_Period (1000-1)
#define ADVANCE_TIM_Prescaler 71
#define ADVANCE_TIM_IRQ TIM8_UP_IRQn
#define ADVANCE_TIM_IRQHandler TIM8_UP_IRQHandler
#endif
void ADVANCE_TIM_Init(void);
#endif /*_BSP_ADVANCETIM_H*/
bsp_AdvanceTim.c
#include "bsp_AdvanceTim.h"
static void ADVANCE_TIM_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//开启定时器时钟,即内部CK_INT = 72M
ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);
//自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Period = ADVANCE_TIM_Period;
//时钟分频系数
TIM_TimeBaseStructure.TIM_Prescaler = ADVANCE_TIM_Prescaler;
//时钟分频因子,基本定时器没有不用管
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//计数器的计数模式,基本定时器只能向上计数,没有计数模式的设置
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//重复计数器的值,基本定时器没有,不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
//初始化定时器
TIM_TimeBaseInit(ADVANCE_TIM,&TIM_TimeBaseStructure);
//清除计数器的中断标志位
TIM_ClearFlag(ADVANCE_TIM,TIM_FLAG_Update);
//开启计数器中断
TIM_ITConfig(ADVANCE_TIM,TIM_IT_Update,ENABLE);
//使能计数器
TIM_Cmd(ADVANCE_TIM,ENABLE);
}
static void ADVANCE_TIM_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
//设置中断优先级分组位0
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
//设置中断源
NVIC_InitStruct.NVIC_IRQChannel = ADVANCE_TIM_IRQ;
//设置主优先级为0
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
//设置抢占优先级为3
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void ADVANCE_TIM_Init(void)
{
ADVANCE_TIM_NVIC_Config();
ADVANCE_TIM_Mode_Config();
}
中断服务函数
#include "stm32f10x_it.h"
#include "bsp_AdvanceTim.h"
extern volatile uint32_t time;
void ADVANCE_TIM_IRQHandler(void)
{
if ( TIM_GetITStatus(ADVANCE_TIM, TIM_IT_Update) != RESET )
{
time++;
TIM_ClearITPendingBit(ADVANCE_TIM, TIM_FLAG_Update);
}
}
main.c
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_buzzer.h"
#include "bsp_AdvanceTim.h"
volatile uint32_t time = 0; //ms计时变量
int main(void)
{
LED_GPIO_Config();
ADVANCE_TIM_Init();
BUZZER_GPIO_Config();
while(1)
{
//1000 * 1ms = 1s
if(time == 1000)
{
time = 0;
LED2_Toggle;
BUZZER_Toggle;
}
}
}
14.6.3 下载验证
编译下载到开发板中能够观察到板载的LED灯和蜂鸣器亮,响一秒,反复循环此状态。
14.7 TIM高级定时器PWM波互补输出
14.7.1 PWM波是什么
PWM波(Pulse Width Modulation),即脉宽调制,是一种用于控制电子元件(如开关、电机、LED等)的技术。它通过改变脉冲的宽度和周期来控制电流或电压的大小,从而实现对目标设备的精确控制。
PWM波可以通过快速切换电源开关来产生,其中一段时间为高电平,另一段时间为低电平。这样产生的信号被称为矩形波形。改变矩形波形的频率,可以改变PWM波信号所控制器件的响应速度。当频率高于人耳能听到的范围时,人们无法感知。
通常情况下,PWM波信号被用于控制DC电机、步进电机、LED灯等。以LED为例,当PWM波信号中高电平占空比较大时,即高电平时间长且低电平时间短时,LED会发出较亮的光芒。反之,则发出弱光。因此,通过控制PWM波信号的占空比来调节LED灯的亮度。
总之,PWM波作为一种常见的控制技术,在工业生产中有着广泛应用,并得到了很好的实践效果。
14.7.2 实验要求
实现频率为1MHz占空比50%的PWM波并使用KingstLA1010逻辑分析仪或者使用Keil5自带的仿真器观察输出的波形。
14.7.3 软件设计
14.7.3.1 设计思路
首先对定时器用到的 GPIO 初始化,定时器时基结构体 TIM_TimeBaseInitTypeDef 初始化,定时器输出比较结构体 TIM_OCInitTypeDef 初始化,定时器刹车和死区结构体 TIM_BDTRInitTypeDef 初始化。
14.7.3.2 代码分析
bsp_AdvanceTim.h
#ifndef _BSP_ADVANCETIM_H
#define _BSP_ADVANCETIM_H
#include "stm32f10x.h"
#define ADVANCE_TIM TIM1
#define ADVANCE_TIM_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADVANCE_TIM_CLK RCC_APB2Periph_TIM1
// PWM 信号的频率 F = TIM_CLK/{(ARR+1)*(PSC+1)}
#define ADVANCE_TIM_PERIOD (8-1)
#define ADVANCE_TIM_PSC (100-1)
#define ADVANCE_TIM_PULSE 4
#define ADVANCE_TIM_IRQ TIM1_UP_IRQn
#define ADVANCE_TIM_IRQHandler TIM1_UP_IRQHandler
// TIM1 输出比较通道
#define ADVANCE_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADVANCE_TIM_CH1_PORT GPIOA
#define ADVANCE_TIM_CH1_PIN GPIO_Pin_8
// TIM1 输出比较通道的互补通道
#define ADVANCE_TIM_CH1N_GPIO_CLK RCC_APB2Periph_GPIOB
#define ADVANCE_TIM_CH1N_PORT GPIOB
#define ADVANCE_TIM_CH1N_PIN GPIO_Pin_13
// TIM1 输出比较通道的刹车通道
#define ADVANCE_TIM_BKIN_GPIO_CLK RCC_APB2Periph_GPIOB
#define ADVANCE_TIM_BKIN_PORT GPIOB
#define ADVANCE_TIM_BKIN_PIN GPIO_Pin_12
void ADVANCE_TIM_Init(void);
#endif /*_BSP_ADVANCETIM_H*/
bsp_AdvanceTim.c
#include "bsp_AdvanceTim.h"
static void ADVANCE_TIM_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//输出比较通道GPIO端口初始化
RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPI