失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 第十五章 TIM高级定时器(下)

第十五章 TIM高级定时器(下)

时间:2022-06-12 02:02:11

相关推荐

第十五章 TIM高级定时器(下)

目录

14.6 使用高级定时器实现精确计时

14.6.1 实验要求

14.6.2 软件设计

14.6.3 下载验证

14.7 TIM高级定时器PWM波互补输出

14.7.1 PWM波是什么

14.7.2 实验要求

14.7.3 软件设计

14.7.4 下载验证

14.8 TIM高级定时器输入捕获

14.6.1 实验要求

14.6.2 软件设计

14.6.3 下载验证

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_TIMTIM1#define ADVANCE_TIM_APBxClock_FUNRCC_APB2PeriphClockCmd#define ADVANCE_TIM_CLKRCC_APB2Periph_TIM1#define ADVANCE_TIM_Period(1000-1)#define ADVANCE_TIM_Prescaler71#define ADVANCE_TIM_IRQTIM1_UP_IRQn#define ADVANCE_TIM_IRQHandlerTIM1_UP_IRQHandler#else//使用高级定时器8#define ADVANCE_TIMTIM8 #define ADVANCE_TIM_APBxClock_FUNRCC_APB2PeriphClockCmd#define ADVANCE_TIM_CLKRCC_APB2Periph_TIM8#define ADVANCE_TIM_Period(1000-1)#define ADVANCE_TIM_Prescaler71#define ADVANCE_TIM_IRQTIM8_UP_IRQn#define ADVANCE_TIM_IRQHandlerTIM8_UP_IRQHandler#endifvoid 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 = 72MADVANCE_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;//设置中断优先级分组位0NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//设置中断源NVIC_InitStruct.NVIC_IRQChannel = ADVANCE_TIM_IRQ;//设置主优先级为0NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;//设置抢占优先级为3NVIC_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 = 1sif(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_FUNRCC_APB2PeriphClockCmd#define ADVANCE_TIM_CLKRCC_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_IRQTIM1_UP_IRQn#define ADVANCE_TIM_IRQHandler TIM1_UP_IRQHandler// TIM1 输出比较通道#define ADVANCE_TIM_CH1_GPIO_CLKRCC_APB2Periph_GPIOA#define ADVANCE_TIM_CH1_PORTGPIOA#define ADVANCE_TIM_CH1_PIN GPIO_Pin_8// TIM1 输出比较通道的互补通道#define ADVANCE_TIM_CH1N_GPIO_CLKRCC_APB2Periph_GPIOB#define ADVANCE_TIM_CH1N_PORTGPIOB#define ADVANCE_TIM_CH1N_PIN GPIO_Pin_13// TIM1 输出比较通道的刹车通道#define ADVANCE_TIM_BKIN_GPIO_CLKRCC_APB2Periph_GPIOB#define ADVANCE_TIM_BKIN_PORTGPIOB#define ADVANCE_TIM_BKIN_PIN GPIO_Pin_12void 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_GPIO_CLK,ENABLE);//打开端口时钟GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1_PIN;//选择对应端口GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//配置为复用推挽输出模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度为50MHzGPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);//输出比较互补通道GPIO端口初始化RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_GPIO_CLK,ENABLE);//打开端口时钟GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1N_PIN;//选择对应端口GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//配置为复用推挽输出模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度为50MHzGPIO_Init(ADVANCE_TIM_CH1N_PORT, &GPIO_InitStructure);//输出比较通道刹车通道 GPIO 初始化RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_GPIO_CLK,ENABLE);//打开端口时钟GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_BKIN_PIN;//选择对应端口GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//配置为复用推挽输出模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度为50MHzGPIO_Init(ADVANCE_TIM_BKIN_PORT, &GPIO_InitStructure);//BKIN引脚默认先输出低电平GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT,ADVANCE_TIM_BKIN_PIN);}static void ADVANCE_TIM_Mode_Config(void){// 开启定时器时钟,即内部时钟CK_INT=72MADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);/*--------------------时基结构体初始化-------------------------*/TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD;// 驱动CNT计数器的时钟 = Fck_int/(psc+1)TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC;// 时钟分频因子 ,配置死区时间时需要用到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_OCInitTypeDef TIM_OCInitStructure;// 配置为PWM模式1TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;// 输出使能TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// 互补输出使能TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 设置占空比大小TIM_OCInitStructure.TIM_Pulse = ADVANCE_TIM_PULSE;// 输出通道电平极性配置TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 互补输出通道电平极性配置TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;// 输出通道空闲电平极性配置TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;// 互补输出通道空闲电平极性配置TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable);/*-------------------刹车和死区结构体初始化-------------------*/TIM_BDTRInitTypeDef TIM_BDTRInitStructure;// 有关刹车和死区结构体的成员具体可参考BDTR寄存器的描述TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;// 输出比较信号死区时间配置,具体如何计算可参考 BDTR:UTG[7:0]的描述// 这里配置的死区时间为152nsTIM_BDTRInitStructure.TIM_DeadTime = 11;TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;// 当BKIN引脚检测到高电平的时候,输出比较信号被禁止,就好像是刹车一样TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure);// 使能计数器TIM_Cmd(ADVANCE_TIM, ENABLE);// 主输出使能,当使用的是通用定时器时,这句不需要TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE);}void ADVANCE_TIM_Init(void){ADVANCE_TIM_GPIO_Config();ADVANCE_TIM_Mode_Config();}

main.c

#include "stm32f10x.h"#include "bsp_AdvanceTim.h"int main(void){//高级定时器初始化ADVANCE_TIM_Init();while(1){ }}

14.7.4 下载验证

代码经编译后没错误后使用KingstVIS逻辑分析仪观察波形,逻辑分析仪的GND引脚接到开发板的GND引脚,开发板的PA8,PB13分别接到逻辑分析仪的CH0,CH1上,也可以使用Keil5软件自带的逻辑分析仪来观察波形,能够观察到两条互补的PWM波,频率为1MHz,占空比为50%。

14.8 TIM高级定时器输入捕获

14.6.1 实验要求

使用通用定时器来产生不同占空比的PWM波然后用高级定时器来捕获通用定时器输出的PWM波通过串口显示频率和占空比。

14.6.2 软件设计

14.6.2.1 设计思路

(1) 通用定时器产生 PWM 配置

(2) 高级定时器 PWM 输入配置

(3) 编写中断服务程序,计算测量的频率和占空比,并打印出来比较编程的要点主要分成两部分,一个是通用定时器的 PWM 信号输出,另一个是 PWM 信号输入捕获。

14.6.2.2 代码分析

bsp_GeneralTim.h

#ifndef __BSP_GENERALTIME_H#define __BSP_GENERALTIME_H#include "stm32f10x.h"/************通用定时器TIM参数定义,只限TIM2、3、4、5************/// 当使用不同的定时器的时候,对应的GPIO是不一样的,这点要注意#define GENERAL_TIM TIM3#define GENERAL_TIM_APBxClock_FUNRCC_APB1PeriphClockCmd #define GENERAL_TIM_CLKRCC_APB1Periph_TIM3// 输出PWM的频率为 72M/{ (ARR+1)*(PSC+1) }#define GENERAL_TIM_PERIOD (100-1)#define GENERAL_TIM_PSC(72-1)#define GENERAL_TIM_CCR1 50#define GENERAL_TIM_CCR2 40#define GENERAL_TIM_CCR3 30#define GENERAL_TIM_CCR4 20// TIM3 输出比较通道1#define GENERAL_TIM_CH1_GPIO_CLKRCC_APB2Periph_GPIOA#define GENERAL_TIM_CH1_PORTGPIOA#define GENERAL_TIM_CH1_PIN GPIO_Pin_6// TIM3 输出比较通道2#define GENERAL_TIM_CH2_GPIO_CLKRCC_APB2Periph_GPIOA#define GENERAL_TIM_CH2_PORTGPIOA#define GENERAL_TIM_CH2_PIN GPIO_Pin_7// TIM3 输出比较通道3#define GENERAL_TIM_CH3_GPIO_CLKRCC_APB2Periph_GPIOB#define GENERAL_TIM_CH3_PORTGPIOB#define GENERAL_TIM_CH3_PIN GPIO_Pin_0// TIM3 输出比较通道4#define GENERAL_TIM_CH4_GPIO_CLKRCC_APB2Periph_GPIOB#define GENERAL_TIM_CH4_PORTGPIOB#define GENERAL_TIM_CH4_PIN GPIO_Pin_1/**************************函数声明********************************/void GENERAL_TIM_Init(void);#endif/* __BSP_GENERALTIME_H */

bsp_GeneralTim.c

#include "bsp_GeneralTim.h"static void GENERAL_TIM_GPIO_Config(void) {GPIO_InitTypeDef GPIO_InitStructure;// 输出比较通道1 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure);// 输出比较通道2 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH2_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH2_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH2_PORT, &GPIO_InitStructure);// 输出比较通道3 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH3_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH3_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH3_PORT, &GPIO_InitStructure);// 输出比较通道4 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH4_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH4_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GENERAL_TIM_CH4_PORT, &GPIO_InitStructure);}///*// * 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有// * TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,// * 另外三个成员是通用定时器和高级定时器才有.// *-----------------------------------------------------------------------------// *typedef struct// *{ TIM_Prescaler 都有// *TIM_CounterModeTIMx,x[6,7]没有,其他都有// * TIM_Period都有// * TIM_ClockDivision TIMx,x[6,7]没有,其他都有// * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有// *}TIM_TimeBaseInitTypeDef; // *-----------------------------------------------------------------------------// *//* ---------------- PWM信号 周期和占空比的计算--------------- */// ARR :自动重装载寄存器的值// CLK_cnt:计数器的时钟,等于 Fck_int / (psc+1) = 72M/(psc+1)// PWM 信号的周期 T = ARR * (1/CLK_cnt) = ARR*(PSC+1) / 72M// 占空比P=CCR/(ARR+1)static void GENERAL_TIM_Mode_Config(void){// 开启定时器时钟,即内部时钟CK_INT=72MGENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);/*--------------------时基结构体初始化-------------------------*/TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 配置周期,这里配置为100K// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_PERIOD;// 驱动CNT计数器的时钟 = Fck_int/(psc+1)TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_PSC;// 时钟分频因子 ,配置死区时间时需要用到TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;// 计数器计数模式,设置为向上计数TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;// 重复计数器的值,没用到不用管TIM_TimeBaseStructure.TIM_RepetitionCounter=0;// 初始化定时器TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);/*--------------------输出比较结构体初始化-------------------*/TIM_OCInitTypeDef TIM_OCInitStructure;// 配置为PWM模式1TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 输出使能TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// 输出通道电平极性配置TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 输出比较通道 1TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR1;TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 输出比较通道 2TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR2;TIM_OC2Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC2PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 输出比较通道 3TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR3;TIM_OC3Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC3PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 输出比较通道 4TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CCR4;TIM_OC4Init(GENERAL_TIM, &TIM_OCInitStructure);TIM_OC4PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);// 使能计数器TIM_Cmd(GENERAL_TIM, ENABLE);}void GENERAL_TIM_Init(void) {GENERAL_TIM_GPIO_Config();GENERAL_TIM_Mode_Config();}

bsp_AdvanceTim.h

#ifndef __BSP_ADVANCETIME_H#define __BSP_ADVANCETIME_H#include "stm32f10x.h"/************高级定时器TIM参数定义,只限TIM1和TIM8************/// 当使用不同的定时器的时候,对应的GPIO是不一样的,这点要注意// 这里我们使用高级控制定时器TIM1#define ADVANCE_TIM TIM1#define ADVANCE_TIM_APBxClock_FUNRCC_APB2PeriphClockCmd#define ADVANCE_TIM_CLKRCC_APB2Periph_TIM1// 输入捕获能捕获到的最小的频率为 72M/{ (ARR+1)*(PSC+1) }#define ADVANCE_TIM_PERIOD (1000-1)#define ADVANCE_TIM_PSC(72-1)// 中断相关宏定义#define ADVANCE_TIM_IRQTIM1_CC_IRQn#define ADVANCE_TIM_IRQHandler TIM1_CC_IRQHandler// TIM1 输入捕获通道1#define ADVANCE_TIM_CH1_GPIO_CLKRCC_APB2Periph_GPIOA #define ADVANCE_TIM_CH1_PORTGPIOA#define ADVANCE_TIM_CH1_PIN GPIO_Pin_8#define ADVANCE_TIM_IC1PWM_CHANNEL TIM_Channel_1#define ADVANCE_TIM_IC2PWM_CHANNEL TIM_Channel_2/**************************函数声明********************************/void ADVANCE_TIM_Init(void);#endif/* __BSP_ADVANCETIME_H */

bsp_AdvanceTim.c

#include "bsp_AdvanceTim.h"static void ADVANCE_TIM_NVIC_Config(void){NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断组为0NVIC_InitStructure.NVIC_IRQChannel = ADVANCE_TIM_IRQ; // 设置中断来源NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// 设置抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;// 设置子优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);}static void ADVANCE_TIM_GPIO_Config(void)  {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);//开启PA8时钟GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1_PIN;//选择PA8端口GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//模式配置为浮空输入GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);}static void ADVANCE_TIM_Mode_Config(void){// 开启定时器时钟,即内部时钟CK_INT=72MADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);/*--------------------时基结构体初始化-------------------------*/TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD;// 驱动CNT计数器的时钟 = Fck_int/(psc+1)TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC;// 时钟分频因子 ,配置死区时间时需要用到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);// 初始化定时器/*--------------------输入捕获结构体初始化-------------------*/// 使用PWM输入模式时,需要占用两个捕获寄存器,一个测周期,另外一个测占空比TIM_ICInitTypeDef TIM_ICInitStructure;// 捕获通道IC1配置TIM_ICInitStructure.TIM_Channel = ADVANCE_TIM_IC1PWM_CHANNEL;// 选择捕获通道TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;// 设置捕获的边沿// 设置捕获通道的信号来自于哪个输入通道,有直连和非直连两种TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;// 1分频,即捕获信号的每个有效边沿都捕获TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStructure.TIM_ICFilter = 0x0;// 不滤波// 初始化PWM输入模式TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);// 当工作做PWM输入模式时,只需要设置触发信号的那一路即可(用于测量周期)// 另外一路(用于测量占空比)会由硬件自带设置,不需要再配置// 捕获通道IC2配置//TIM_ICInitStructure.TIM_Channel = ADVANCE_TIM_IC1PWM_CHANNEL;//TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;//TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;//TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//TIM_ICInitStructure.TIM_ICFilter = 0x0;//TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);TIM_SelectInputTrigger(ADVANCE_TIM, TIM_TS_TI1FP1);// 选择输入捕获的触发信号// 选择从模式: 复位模式// PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT会被复位TIM_SelectSlaveMode(ADVANCE_TIM, TIM_SlaveMode_Reset);TIM_SelectMasterSlaveMode(ADVANCE_TIM,TIM_MasterSlaveMode_Enable); // 使能捕获中断,这个中断针对的是主捕获通道(测量周期那个)TIM_ITConfig(ADVANCE_TIM, TIM_IT_CC1, ENABLE);// 清除中断标志位TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);// 使能高级控制定时器,计数器开始计数TIM_Cmd(ADVANCE_TIM, ENABLE);}void ADVANCE_TIM_Init(void){ADVANCE_TIM_NVIC_Config();ADVANCE_TIM_GPIO_Config();ADVANCE_TIM_Mode_Config();}

bsp_usart.h

#ifndef _BSP_USART_H#define _BSP_USART_H#include "stm32f10x.h"#include <stdio.h>#define DEBUG_USART11#define DEBUG_USART20#define DEBUG_USART30#define DEBUG_USART40#define DEBUG_USART50#if DEBUG_USART1//串口1-USART1#define DEBUG_USARTx USART1#define DEBUG_USART_CLKRCC_APB2Periph_USART1#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd#define DEBUG_USART_BAUDRATE 115200//USART GPIO 引脚宏定义#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd#define DEBUG_USART_TX_GPIO_PORT GPIOA #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9#define DEBUG_USART_RX_GPIO_PORT GPIOA#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10#define DEBUG_USART_IRQUSART1_IRQn#define DEBUG_USART_IRQHandler USART1_IRQHandler /**************************************************************/#elif DEBUG_USART2//串口2-USART2#define DEBUG_USARTx USART2#define DEBUG_USART_CLKRCC_APB1Periph_USART2#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd#define DEBUG_USART_BAUDRATE 115200//USART GPIO 引脚宏定义#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd#define DEBUG_USART_TX_GPIO_PORT GPIOA #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2#define DEBUG_USART_RX_GPIO_PORT GPIOA#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3#define DEBUG_USART_IRQUSART2_IRQn#define DEBUG_USART_IRQHandler USART2_IRQHandler/**************************************************************/#elif DEBUG_USART3//串口3-USART3#define DEBUG_USARTx USART3#define DEBUG_USART_CLKRCC_APB1Periph_USART3#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd#define DEBUG_USART_BAUDRATE 115200//USART GPIO 引脚宏定义#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd#define DEBUG_USART_TX_GPIO_PORT GPIOA  #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10#define DEBUG_USART_RX_GPIO_PORT GPIOA#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11#define DEBUG_USART_IRQUSART3_IRQn#define DEBUG_USART_IRQHandler USART3_IRQHandler/**************************************************************/#elif DEBUG_USART4//串口4-USART4#define DEBUG_USARTx USART4#define DEBUG_USART_CLKRCC_APB1Periph_USART4#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd#define DEBUG_USART_BAUDRATE 115200//USART GPIO 引脚宏定义#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd#define DEBUG_USART_TX_GPIO_PORT GPIOC #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10#define DEBUG_USART_RX_GPIO_PORT GPIOC#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11#define DEBUG_USART_IRQUSART4_IRQn#define DEBUG_USART_IRQHandler USART4_IRQHandler/**************************************************************/#elif DEBUG_USART5//串口5-USART5#define DEBUG_USARTx USART5#define DEBUG_USART_CLKRCC_APB1Periph_USART5#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd#define DEBUG_USART_BAUDRATE 115200 //USART GPIO 引脚宏定义#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd#define DEBUG_USART_TX_GPIO_PORT GPIOA #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12#define DEBUG_USART_RX_GPIO_PORT GPIOA#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2#define DEBUG_USART_IRQUSART5_IRQn#define DEBUG_USART_IRQHandler USART5_IRQHandler/**************************************************************/#endifvoid USART_Config(void);void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str);void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data);void Usart_SendHalfWorld(USART_TypeDef* pUSARTx, uint16_t data);void Usart_Sendarray(USART_TypeDef* pUSARTx, uint8_t *array, uint8_t num);#endif /*_BSP_USART_H*/

bsp_usart.c

#include "bsp_usart.h"static void USART_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStructure;//开启GPIO时钟 DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK,ENABLE);//将USART Tx的GPIO配置为推挽复用模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);//将USART Rx的GPIO配置为浮空输入模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);}NVIC_InitTypeDef NVIC_InitStruct;//配置NVIC的优先级分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置中断源:按键1NVIC_InitStruct.NVIC_IRQChannel = DEBUG_USART_IRQ;static void USART_NVIC_Config(void){//配置抢占优先级:1NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;//配置子优先级:1NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;//使能中断通道NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct);}void USART_Config(void){USART_GPIO_Config();USART_NVIC_Config();USART_InitTypeDef USART_InitStructure;//开启串口外设时钟DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);//配置波特率USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;//设置数据帧字长USART_InitStructure.USART_WordLength = USART_WordLength_8b;//配置停止位USART_InitStructure.USART_StopBits = USART_StopBits_1;//奇偶校验控制选择USART_InitStructure.USART_Parity = USART_Parity_No;//串口模式选择//使用或操作将串口模式配置为收发模式USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//硬件流控制选择USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//串口初始化USART_Init(DEBUG_USARTx, &USART_InitStructure);//使能串口接收中断USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);//使能串口USART_Cmd(DEBUG_USARTx, ENABLE);}void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data){//发送一个字节数据到USARTUSART_SendData(pUSARTx, data);//等待发送数据寄存器为空while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);}void Usart_SendHalfWorld(USART_TypeDef* pUSARTx, uint16_t data){uint8_t temp_h,temp_l;temp_h = (data & 0xff00) >> 8;temp_l = data & 0x00ff;//发送一个字节数据到USARTUSART_SendData(pUSARTx, temp_h);//等待发送数据寄存器为空while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);//发送一个字节数据到USARTUSART_SendData(pUSARTx, temp_l);//等待发送数据寄存器为空while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);}void Usart_Sendarray(USART_TypeDef* pUSARTx, uint8_t *array, uint8_t num){uint8_t i;for(i=0;i<num;i++){Usart_SendByte( pUSARTx, array[i]);}while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);}void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str){uint8_t i=0;do{Usart_SendByte(pUSARTx, *(str+i));i++;}while(*(str+i) != '\0');while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET);}int fputc(int ch, FILE *f){//发送一个字节数据到USART USART_SendData(DEBUG_USARTx, (uint8_t) ch);//等待发送数据寄存器为空while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);return (ch);}int fgetc(FILE *f){//等待发送数据寄存器为空while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);return (int)USART_ReceiveData(DEBUG_USARTx);}

中断服务函数

#include "stm32f10x_it.h"#include "bsp_usart.h"#include "bsp_AdvanceTim.h" uint16_t IC2Value = 0;uint16_t IC1Value = 0;float DutyCycle = 0;float Frequency = 0;/** 如果是第一个上升沿中断,计数器会被复位,锁存到CCR1寄存器的值是0,CCR2寄存器的值也是0* 无法计算频率和占空比。当第二次上升沿到来的时候,CCR1和CCR2捕获到的才是有效的值。其中 * CCR1对应的是周期,CCR2对应的是占空比。*/void ADVANCE_TIM_IRQHandler(void){//清除中断标志位TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);//获取输入捕获值IC1Value = TIM_GetCapture1(ADVANCE_TIM);IC2Value = TIM_GetCapture2(ADVANCE_TIM);// 注意:捕获寄存器CCR1和CCR2的值在计算占空比和频率的时候必须加1if (IC1Value != 0){// 占空比计算DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);// 频率计算 Frequency = (72000000/(ADVANCE_TIM_PSC+1))/(float)(IC1Value+1);printf("占空比:%0.2f%% 频率:%0.2fHz\n",DutyCycle,Frequency);}else{DutyCycle = 0;Frequency = 0;}}

main.c

#include "stm32f10x.h"#include "bsp_usart.h"#include "bsp_GeneralTim.h"#include "bsp_AdvanceTim.h"int main(void){//串口初始化USART_Config();//通用定时器初始化GENERAL_TIM_Init();//高级定时器初始化ADVANCE_TIM_Init();while(1){}}

14.6.3 下载验证

PA6和PA8连接时串口调试助手显示50%占空比,频率1KHz,PA7和PA8连接时串口调试助手显示40%占空比,频率1KHz,PB0和PA8连接时串口调试助手显示30%占空比,频率1KHz,PB1和PA8连接时串口调试助手显示20%占空比,频率1KHz。

如果觉得《第十五章 TIM高级定时器(下)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。