超子物联网 HAL库学习 汇总入口:
写作不易,如果您觉得写的不错,欢迎给博主来一波点赞、收藏~让博主更有动力吧!
一、资源介绍:STM32F103C8T6定时器资源介绍
高级定时器(TIM1)
- 时基单元包含:
- 计数器寄存器(TIMx_CNT)
- 预分频器寄存器(TIMx_PSC)
- 自动装载寄存器(TIMx_ARR)
- 重复次数寄存器(TIMx_RCR)
通用定时器(TIM2、TIM3、TIM4)
- 时基单元包含:
- 计数器寄存器(TIMx_CNT)
- 预分频器寄存器(TIMx_PSC)
- 自动装载寄存器(TIMx_ARR)
定时器1 外部通道:
- 通道 1:PA8,DMA1_Channel2
- 通道 2:PA9,DMA1_Channel3
- 通道 ETR:PA12
定时器2 外部通道:
- 通道 1:PA0(重映射 PA15),DMA1_Channel5(如果重映射,需要内部上拉)
- 通道 2:PA1(重映射 PB3),DMA1_Channel7
- 通道 ETR:PA0(重映射 PA15)
定时器3 外部通道:
- 通道 1:PA6(重映射 PB4),DMA1_Channel6(如果重映射,需要内部上拉)
- 通道 2:PA7(重映射 PB5)
- 通道 ETR:无
定时器4 外部通道:
- 通道 1:PB6,DMA1_Channel1
- 通道 2:PB7,DMA1_Channel4
- 通道 ETR:无
来自江协的定时器基本结构图
二、HAL库:TIM1 外部时钟模式1 轮询方式 按键计数
1. 功能说明
- 按下按键,定时器计数
2. 注意事项*
-
引脚冲突问题
外部时钟模式1,定时器1:
通道1 PA8 DMA1_Channel2
通道2 PA9 DMA1_Channel3
而串口1的Tx也为PA9
所以要善用重映射功能(会重映射到PB6),避免引脚冲突
并且在切换不同的通道的时候,注意GPIO口的初始化与上下拉配置
-
ED双边沿检测,不过滤波器
-
外部时钟模式1 通往TRGI, TRGI会产生一个触发事件 会置位TIF为1,也就是HAL库的
TIM_FLAG_TRIGGER
标志位会置1,我们可以通过判断标志位来进行判断单次的触发事件。 -
通道1 、2 上的滤波器解释
3. 相关函数
-
重映射串口1
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_USART1_ENABLE();
-
TIM_ClockConfigTypeDef
时钟配置总控结构体 -
基础的定时器配置初始化(定时器1通道 2举例)
tim1.Instance = TIM1; // 实例 tim1.Init.Period = arr; // 重装载值 tim1.Init.Prescaler = psc; // 分频系数 tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式 tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子 tim1.Init.RepetitionCounter = rep; // 重复计数值 tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器) HAL_TIM_Base_Init(&tim1); //初始化定时器 __HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件 /* 通道1边沿检测 ED */ //tim1_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //边沿检测 另外仨(时钟过滤, 有效极性, 外部触发 预分频ETR)不用配置 //HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置 /* 通道2上升沿/下降沿检测 (Both不生效F103 ,只对下降沿生效) */ tim1_clock.ClockSource = TIM_CLOCKSOURCE_TI2; //通道2 //tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING; //上升沿检测 //tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING; //下降沿检测 tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波) HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置 HAL_TIM_Base_Start(&tim1); //打开定时器(轮询方式)
-
初始化硬件配置回调函数
if(htim->Instance == TIM1){ __HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitType; GPIO_InitType.Pin = GPIO_PIN_9; GPIO_InitType.Mode = GPIO_MODE_AF_INPUT; GPIO_InitType.Pull = GPIO_PULLUP; //上拉 GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM; HAL_GPIO_Init(GPIOA,&GPIO_InitType);
4. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //(高级)定时器1总控结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup;
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
TIM_ClockConfigTypeDef tim1_clock; //时钟配置结构体
uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
/* 通道1边沿检测 ED */
//tim1_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //边沿检测
另外仨(时钟过滤, 有效极性, 外部触发 预分频ETR)不用配置
//HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
/* 通道2上升沿/下降沿检测 (Both不生效F103 ,只对下降沿生效) */
tim1_clock.ClockSource = TIM_CLOCKSOURCE_TI2; //通道2
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING; //上升沿检测
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING; //下降沿检测
tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波)
HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
HAL_TIM_Base_Start(&tim1); //打开定时器(轮询方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim2, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim2, (uint32_t*)tim2_dmaBuff, 4);
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_UP;
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim3, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim3, (uint32_t*)tim3_dmaBuff, 4);
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim4, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim4, (uint32_t*)tim4_dmaBuff, 4);
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitType;
GPIO_InitType.Pin = GPIO_PIN_9;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //上拉
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
//
// HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
// HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
//
// /* DMA配置 */
// tim1_dmaup.Instance = DMA1_Channel5;
// tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
// tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
// tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
// tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
// tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim1_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
// HAL_DMA_Init(&tim1_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/* DMA配置 */
tim2_dmaup.Instance = DMA1_Channel2;
tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
HAL_DMA_Init(&tim2_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
/* DMA配置 */
tim3_dmaup.Instance = DMA1_Channel3;
tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim3_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
HAL_DMA_Init(&tim3_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
/* DMA配置 */
tim4_dmaup.Instance = DMA1_Channel7;
tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim4_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
HAL_DMA_Init(&tim4_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
/* 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 */
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA1 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);
}
}else if(htim->Instance == TIM2){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA2 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);
}
}else if(htim->Instance == TIM3){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA3 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);
}
}else if(htim->Instance == TIM4){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA4 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);
}
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/* 初始化函数 */
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
main.c
while(1){
/* 获取更新标志位 */
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); ///清除标志位
U1_Printf("定时器 1 更新事件\\r\\n");
}
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER); ///清除标志位
U1_Printf("定时器 1 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim1)); //输出当前计数值
}
}
三、HAL库:TIM1 外部模式1 ETR通道 轮询方式 按键计数
1. 注意事项*
-
ETR的通道有专门的预分频器,需要按需配置预分频器
TIM_CLOCKPRESCALER_DIV1/2/4/8
-
特别注意:当设置ETR的预分频器为2、4、8分频时,如果ETR的有效电平(取决于是否ETR反向)与IO的引脚默认电平不匹配,那么复位后首次按下会直接产生一次触发事件,后续正常。
- **解决办法:**匹配IO与ETR的有效电平 (例如IO下拉,ETR有效电平为低电平,也就是ETR反转。那么就能匹配默认电平与ETR,就不会出现上述错误)
-
特别注意:如果通道的 分频因子 加大(同时加大分频因子),会使得检测变慢,也就是频率和带宽就变低了,变得更严格。会导致复位之后立刻产生一次触发事件。
-
解决办法:在启动定时器之前,
先进行一段时间的延时操作,再清除TIm的Counter和TRIG触发事件标志位
这样就能保证在启动时不会有任何触发事件产生(添加延时的原因是因为程序运行太快了,得等段时间反映。)
-
2. 相关函数
-
TIM_ClockConfigTypeDef
时钟配置总控结构体 -
基础的定时器配置初始化(定时器1通道 2举例)
//定时器 1 void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep) { tim1.Instance = TIM1; // 实例 tim1.Init.Period = arr; // 重装载值 tim1.Init.Prescaler = psc; // 分频系数 tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式 tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子 tim1.Init.RepetitionCounter = rep; // 重复计数值 tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器) HAL_TIM_Base_Init(&tim1); //初始化定时器 __HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件 /* 外部模式1 ETR通道 */ tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETR tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED; //ETR反向 (低电平或下降沿有效) 为了匹配IO和ETR,防止复位后按一下就产生触发事件 //tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED; //ETR不反向 (高电平或上升沿有效) tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV4; //ETR的预分频器配置 tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波) HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置 /* 防止加大分频因子或滤波强度而导致的 复位后产生触发事件 */ HAL_Delay(50); __HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER); ///清除触发事件标志位 __HAL_TIM_SET_COUNTER(&tim1, 0); // 清除计数值 HAL_TIM_Base_Start(&tim1); //打开定时器(轮询方式) }
-
初始化硬件配置回调函数
if(htim->Instance == TIM1){ __HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitType; GPIO_InitType.Pin = GPIO_PIN_9; GPIO_InitType.Mode = GPIO_MODE_AF_INPUT; GPIO_InitType.Pull = GPIO_PULLUP; //上拉 GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM; HAL_GPIO_Init(GPIOA,&GPIO_InitType);
3. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //(高级)定时器1总控结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup;
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
TIM_ClockConfigTypeDef tim1_clock; //时钟配置结构体
uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
/* 外部模式1 ETR通道 */
tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETR
tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED; //ETR反向 (低电平或下降沿有效) 为了匹配IO和ETR,防止复位后按一下就产生触发事件
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED; //ETR不反向 (高电平或上升沿有效)
tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV4; //ETR的预分频器配置
tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波)
HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
/* 防止加大分频因子或滤波强度而导致的 复位后产生触发事件 */
HAL_Delay(50);
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER); ///清除触发事件标志位
__HAL_TIM_SET_COUNTER(&tim1, 0); // 清除计数值
HAL_TIM_Base_Start(&tim1); //打开定时器(轮询方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim2, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim2, (uint32_t*)tim2_dmaBuff, 4);
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_UP;
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim3, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim3, (uint32_t*)tim3_dmaBuff, 4);
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim4, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim4, (uint32_t*)tim4_dmaBuff, 4);
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitType;
GPIO_InitType.Pin = GPIO_PIN_12;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
//
// HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
// HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
//
// /* DMA配置 */
// tim1_dmaup.Instance = DMA1_Channel5;
// tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
// tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
// tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
// tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
// tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim1_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
// HAL_DMA_Init(&tim1_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/* DMA配置 */
tim2_dmaup.Instance = DMA1_Channel2;
tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
HAL_DMA_Init(&tim2_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
/* DMA配置 */
tim3_dmaup.Instance = DMA1_Channel3;
tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim3_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
HAL_DMA_Init(&tim3_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
/* DMA配置 */
tim4_dmaup.Instance = DMA1_Channel7;
tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim4_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
HAL_DMA_Init(&tim4_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
/* 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 */
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA1 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);
}
}else if(htim->Instance == TIM2){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA2 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);
}
}else if(htim->Instance == TIM3){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA3 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);
}
}else if(htim->Instance == TIM4){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA4 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);
}
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/* 初始化函数 */
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
main.c
while(1){
/* 获取更新标志位 */
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); ///清除标志位
U1_Printf("定时器 1 更新事件\\r\\n");
}
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER); ///清除标志位
U1_Printf("定时器 1 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim1)); //输出当前计数值
}
}
四、HAL库:TIM234 外部模式1 通道1 2 轮询方式 重映射通道 边沿检测 按键计数
1. 注意事项*
-
引脚冲突问题
要善用重映射功能,避免引脚冲突
并且在切换不同的通道的时候,注意GPIO口的初始化与上下拉配置
-
还是引脚冲突问题
单片机在默认状态佳,SW+JTAG仿真都是开启状态的。
当定时器2 的通道1 重映射会映射到 PA15,会与JTAG的引脚冲突。注意一下需要
-
如果映射TIM2时, 一旦设计仿真接口切换为普通接口,需要在初始化时保持一致
2. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //定时器结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup; //DMA通道配置结构体
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
TIM_ClockConfigTypeDef tim1_clock; //时钟配置结构体
TIM_ClockConfigTypeDef tim2_clock;
TIM_ClockConfigTypeDef tim3_clock;
TIM_ClockConfigTypeDef tim4_clock;
uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
/* 外部模式1 ETR通道 */
tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETR
tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED; //ETR反向 (低电平或下降沿有效)
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED; //ETR不反向 (高电平或上升沿有效)
tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; //ETR的预分频器配置
tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波)
HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
HAL_TIM_Base_Start(&tim1); //打开定时器(轮询方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
/* 外部模式1 通道1 双边沿检测 重映射*/
tim2_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //通道1 边沿检测
HAL_TIM_ConfigClockSource(&tim2, &tim2_clock); //初始化定时器时钟配置
HAL_TIM_Base_Start(&tim2); //打开定时器(轮询方式)
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; //中央对齐模式
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
/* 外部模式1 通道1 */
tim3_clock.ClockSource = TIM_CLOCKSOURCE_TI1; // 通道1
tim3_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING; // 上升沿
tim3_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim3, &tim3_clock); //初始化定时器时钟配置
HAL_TIM_Base_Start(&tim3); //打开定时器(轮询方式)
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
/* 外部模式1 通道2 */
tim4_clock.ClockSource = TIM_CLOCKSOURCE_TI2; // 通道2
tim4_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING; // 下降沿
tim4_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim4, &tim4_clock); //初始化定时器时钟配置
HAL_TIM_Base_Start(&tim4); //打开定时器(轮询方式)
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitType;
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
/* 定时器1 外部模式1 ETR通道IO */
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_12;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
//
// HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
// HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
//
// /* DMA配置 */
// tim1_dmaup.Instance = DMA1_Channel5;
// tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
// tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
// tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
// tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
// tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim1_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
// HAL_DMA_Init(&tim1_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM2_ENABLE();
//__HAL_AFIO_REMAP_TIM2_PARTIAL_1(); //(同样的功能)
__HAL_AFIO_REMAP_SWJ_NOJTAG();
/* 定时器2 外部模式1 通道1 重映射*/
//GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Pin = GPIO_PIN_15;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
// HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
// HAL_NVIC_EnableIRQ(TIM2_IRQn);
//
// /* DMA配置 */
// tim2_dmaup.Instance = DMA1_Channel2;
// tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
// HAL_DMA_Init(&tim2_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
//__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM3_PARTIAL(); //部分映射
__HAL_AFIO_REMAP_SWJ_NONJTRST(); //完全SW+JATG 但没有NJTRST
/* 定时器3 外部模式1 通道1 重映射*/
//GPIO_InitType.Pin = GPIO_PIN_6;
GPIO_InitType.Pin = GPIO_PIN_4;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
// HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
// HAL_NVIC_EnableIRQ(TIM3_IRQn);
//
// /* DMA配置 */
// tim3_dmaup.Instance = DMA1_Channel3;
// tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim3_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
// HAL_DMA_Init(&tim3_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
/* 定时器4 外部模式1 通道2 */
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_7;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
// HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
// HAL_NVIC_EnableIRQ(TIM4_IRQn);
//
// /* DMA配置 */
// tim4_dmaup.Instance = DMA1_Channel7;
// tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim4_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
// HAL_DMA_Init(&tim4_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
/* 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 */
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA1 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);
}
}else if(htim->Instance == TIM2){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA2 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);
}
}else if(htim->Instance == TIM3){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA3 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);
}
}else if(htim->Instance == TIM4){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA4 完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);
}
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/* 初始化函数 */
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
Timer1_Init(5 - 1, 0, 1 - 1); //5次有效边沿
Timer2_Init(5 - 1, 0); // 5次
Timer3_Init(5 - 1, 0); // 5次
Timer4_Init(5 - 1, 0); // 5次
// uint16_t time1 = 0;
// uint16_t time2 = 0;
// uint16_t time3 = 0;
// uint16_t time4 = 0;
while(1){
/* 获取更新标志位 */
/* TIM1 */
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); ///清除标志位
U1_Printf("定时器 1 更新事件\\r\\n");
}
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER); ///清除标志位
U1_Printf("定时器 1 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim1)); //输出当前计数值
}
/* TIM2 */
if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
U1_Printf("定时器 2 更新事件\\r\\n");
}
if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_TRIGGER);
U1_Printf("定时器 2 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim2));
}
/* TIM3 */
if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
U1_Printf("定时器 3 更新事件\\r\\n");
}
if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_TRIGGER);
U1_Printf("定时器 3 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim3));
}
/* TIM4 */
if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
U1_Printf("定时器 4 更新事件\\r\\n");
}
if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_TRIGGER);
U1_Printf("定时器 4 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(&tim4));
}
//
// if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
// U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);
// }
//
// if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
// U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);
// }
//
// if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
// U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);
// }
}
}
五、HAL库:TIM1234 外部模式1 中断方式 按键计数
1. 注意事项*
- HAL库只会打开Up中断,触发中断需要手动打开
- 注意定时器与别的外设 引脚冲突
2. 相关函数
__HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER);
手动打开触发中断HAL_TIM_Base_Start_IT(&tim4);
打开定时器(中断方式)
3. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //定时器结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup; //DMA通道配置结构体
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
TIM_ClockConfigTypeDef tim1_clock; //时钟配置结构体
TIM_ClockConfigTypeDef tim2_clock;
TIM_ClockConfigTypeDef tim3_clock;
TIM_ClockConfigTypeDef tim4_clock;
uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
/* 外部模式1 ETR通道 */ //PA12 下降沿 按下计数 上拉
tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETR
tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED; //ETR反向 (低电平或下降沿有效)
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED; //ETR不反向 (高电平或上升沿有效)
tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; //ETR的预分频器配置
tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波)
HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim1, TIM_IT_TRIGGER); //手动打开触发中断
HAL_TIM_Base_Start_IT(&tim1); //打开定时器(中断方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
/* 外部模式1 通道1 双边沿检测 重映射*/ //PA15 双边边沿 上拉
tim2_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //通道1 边沿检测
HAL_TIM_ConfigClockSource(&tim2, &tim2_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim2, TIM_IT_TRIGGER); //手动打开触发中断
HAL_TIM_Base_Start_IT(&tim2); //打开定时器(中断方式)
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; //中央对齐模式
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
/* 外部模式1 通道1 */ //PB4 上升沿 上拉 抬起计数
tim3_clock.ClockSource = TIM_CLOCKSOURCE_TI1; // 通道1
tim3_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING; // 上升沿
tim3_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim3, &tim3_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER); //手动打开触发中断
HAL_TIM_Base_Start_IT(&tim3); //打开定时器(中断方式)
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
/* 外部模式1 通道2 */ //PB7 下降沿 上拉 按下计数
tim4_clock.ClockSource = TIM_CLOCKSOURCE_TI2; // 通道2
tim4_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING; // 下降沿
tim4_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim4, &tim4_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim4, TIM_IT_TRIGGER); //手动打开触发中断
HAL_TIM_Base_Start_IT(&tim4); //打开定时器(中断方式)
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitType;
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
/* 定时器1 外部模式1 ETR通道IO */
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_12;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
//
HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
HAL_NVIC_SetPriority(TIM1_TRG_COM_IRQn, 3, 0); //配置、打开 触发中断
HAL_NVIC_EnableIRQ(TIM1_TRG_COM_IRQn);
//
// /* DMA配置 */
// tim1_dmaup.Instance = DMA1_Channel5;
// tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
// tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
// tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
// tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
// tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim1_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
// HAL_DMA_Init(&tim1_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM2_ENABLE();
//__HAL_AFIO_REMAP_TIM2_PARTIAL_1(); //(同样的功能)
__HAL_AFIO_REMAP_SWJ_NOJTAG();
/* 定时器2 外部模式1 通道1 重映射*/
//GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Pin = GPIO_PIN_15;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
//
// /* DMA配置 */
// tim2_dmaup.Instance = DMA1_Channel2;
// tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
// HAL_DMA_Init(&tim2_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
//__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM3_PARTIAL(); //部分映射
__HAL_AFIO_REMAP_SWJ_NONJTRST(); //完全SW+JATG 但没有NJTRST
/* 定时器3 外部模式1 通道1 重映射*/
//GPIO_InitType.Pin = GPIO_PIN_6;
GPIO_InitType.Pin = GPIO_PIN_4;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
//
// /* DMA配置 */
// tim3_dmaup.Instance = DMA1_Channel3;
// tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim3_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
// HAL_DMA_Init(&tim3_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
/* 定时器4 外部模式1 通道2 */
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_7;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
//
// /* DMA配置 */
// tim4_dmaup.Instance = DMA1_Channel7;
// tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim4_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
// HAL_DMA_Init(&tim4_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
// /* 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 */
// if(htim->State == HAL_DMA_STATE_READY){
// U1_Printf("DMA1 完成中断\\r\\n");
// htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
// }else{
// U1_Printf("定时器 1 定时时间:%d\\r\\n",time1++);
// }
U1_Printf("定时器 1 更新事件\\r\\n");
}else if(htim->Instance == TIM2){
// if(htim->State == HAL_DMA_STATE_READY){
// U1_Printf("DMA2 完成中断\\r\\n");
// htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
// }else{
// U1_Printf("定时器 2 定时时间:%d\\r\\n",time2++);
// }
U1_Printf("定时器 2 更新事件\\r\\n");
}else if(htim->Instance == TIM3){
// if(htim->State == HAL_DMA_STATE_READY){
// U1_Printf("DMA3 完成中断\\r\\n");
// htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
// }else{
// U1_Printf("定时器 3 定时时间:%d\\r\\n",time3++);
// }
U1_Printf("定时器 3 更新事件\\r\\n");
}else if(htim->Instance == TIM4){
// if(htim->State == HAL_DMA_STATE_READY){
// U1_Printf("DMA4 完成中断\\r\\n");
// htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
// }else{
// U1_Printf("定时器 4 定时时间:%d\\r\\n",time4++);
// }
U1_Printf("定时器 4 更新事件\\r\\n");
}
}
//触发中断 回调函数
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断\\r\\n");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/* 初始化函数 */
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
Timer1_Init(5 - 1, 0, 1 - 1); //5次有效边沿
Timer2_Init(5 - 1, 0); // 5次
Timer3_Init(5 - 1, 0); // 5次
Timer4_Init(5 - 1, 0); // 5次
U1_Printf("初始化完成\\r\\n");
while(1){
}
}
stm32f1xx_it.c
/*-------------------------------------------------*/
/* */
/* 实现各种中断服务函数的源文件 */
/* */
/*-------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
#include "time.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
HAL_UART_AbortReceive_IT(&uart2.uart);
}
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
HAL_UART_AbortReceive_IT(&uart3.uart);
}
}
void DMA1_Channel4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmatx);
}
//void DMA1_Channel5_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart1.dmarx);
//}
//void DMA1_Channel7_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart2.dmatx);
//}
void DMA1_Channel6_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmarx);
}
//void DMA1_Channel2_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmatx);
//}
//void DMA1_Channel3_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmarx);
//}
void DMA1_Channel5_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim1_dmaup);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim2_dmaup);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim3_dmaup);
}
void DMA1_Channel7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim4_dmaup);
}
void TIM1_UP_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim1);
}
void TIM1_TRG_COM_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim1);
}
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim2);
}
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim3);
}
void TIM4_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim4);
}
/*-------------------------------------------------*/
/*函数名:不可屏蔽中断处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void NMI_Handler(void)
{
}
/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{
}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void SVC_Handler(void)
{
}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{
}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{
HAL_IncTick();
}
六、HAL库:TIM1234 外部模式1 DMA单次/循环模式 中断方式 按键计数
1. 注意事项*
- DMA方式,HAL库不会开启任何中断,需要自己开启更新和触发中断
- 注意定时器与别的外设 引脚冲突
- 普通的更新中断与DMA完成中断共用一个回调函数
2. 简单介绍
DMA方式,会在每次更新时,传递新的值到ARR重载值,我们初始 化的时候设置ARR为5,然后启动DMA 4次传输分别传输6,7,8,9。
对于单次DMA向上计数,第一次5+1个有效边沿,第二次6+1个有效 边沿,第三次7+1个有效边沿,第四次8+1个有效边沿,第五次9+1 个有效边沿,之后一直都是9+1个有效边沿。
对于循环DMA向上计数,第一次5+1个有效边沿,第二次6+1个有效 边沿,第三次7+1个有效边沿,第四次8+1个有效边沿,第五次9+1 个有效边沿,第六次6+1个有效边沿,第七次7+1个有效边沿,第八 次8+1个有效边沿,第九次9+1个有效边沿,第十次6+1个有效边 沿.......往复循环
2. 相关函数
__HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER);
手动打开中断HAL_TIM_Base_Start_DMA(&tim4);
打开定时器(DMA方式)
3. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //定时器结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup; //DMA通道配置结构体
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
TIM_ClockConfigTypeDef tim1_clock; //时钟配置结构体
TIM_ClockConfigTypeDef tim2_clock;
TIM_ClockConfigTypeDef tim3_clock;
TIM_ClockConfigTypeDef tim4_clock;
uint16_t tim1_dmaBuff[4] = {6, 7, 8, 9};
uint16_t tim2_dmaBuff[4] = {6, 7, 8, 9};
uint16_t tim3_dmaBuff[4] = {6, 7, 8, 9};
uint16_t tim4_dmaBuff[4] = {6, 7, 8, 9};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
/* 外部模式1 ETR通道 */ //PA12 下降沿 按下计数 上拉
tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETR
tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED; //ETR反向 (低电平或下降沿有效)
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED; //ETR不反向 (高电平或上升沿有效)
tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; //ETR的预分频器配置
tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波)
HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim1, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断
HAL_TIM_Base_Start_DMA(&tim1, (uint32_t* )tim1_dmaBuff, 4); //打开定时器(DMA方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
/* 外部模式1 通道1 双边沿检测 重映射*/ //PA15 双边边沿 上拉
tim2_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //通道1 边沿检测
HAL_TIM_ConfigClockSource(&tim2, &tim2_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim2, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断
HAL_TIM_Base_Start_DMA(&tim2, (uint32_t* )tim2_dmaBuff, 4); //打开定时器(DMA方式)
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; //中央对齐模式
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
/* 外部模式1 通道1 */ //PB4 上升沿 上拉 抬起计数
tim3_clock.ClockSource = TIM_CLOCKSOURCE_TI1; // 通道1
tim3_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING; // 上升沿
tim3_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim3, &tim3_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断
HAL_TIM_Base_Start_DMA(&tim3, (uint32_t* )tim3_dmaBuff, 4); //打开定时器(DMA方式)
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
/* 外部模式1 通道2 */ //PB7 下降沿 上拉 按下计数
tim4_clock.ClockSource = TIM_CLOCKSOURCE_TI2; // 通道2
tim4_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING; // 下降沿
tim4_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim4, &tim4_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim4, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断
HAL_TIM_Base_Start_DMA(&tim4, (uint32_t* )tim4_dmaBuff, 4); //打开定时器(DMA方式)
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitType;
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
/* 定时器1 外部模式1 ETR通道IO */
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_12;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
HAL_NVIC_SetPriority(TIM1_TRG_COM_IRQn, 3, 0); //配置、打开 触发中断
HAL_NVIC_EnableIRQ(TIM1_TRG_COM_IRQn);
/* DMA配置 */
__HAL_RCC_DMA1_CLK_ENABLE();
tim1_dmaup.Instance = DMA1_Channel5;
tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim1_dmaup.Init.Mode = DMA_NORMAL; //单次模式
//tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
HAL_DMA_Init(&tim1_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM2_ENABLE();
//__HAL_AFIO_REMAP_TIM2_PARTIAL_1(); //(同样的功能)
__HAL_AFIO_REMAP_SWJ_NOJTAG();
/* 定时器2 外部模式1 通道1 重映射*/
//GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Pin = GPIO_PIN_15;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/* DMA配置 */
__HAL_RCC_DMA1_CLK_ENABLE();
tim2_dmaup.Instance = DMA1_Channel2;
tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim1_dmaup.Init.Mode = DMA_NORMAL; //单次模式
//tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
HAL_DMA_Init(&tim2_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
//__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM3_PARTIAL(); //部分映射
__HAL_AFIO_REMAP_SWJ_NONJTRST(); //完全SW+JATG 但没有NJTRST
/* 定时器3 外部模式1 通道1 重映射*/
//GPIO_InitType.Pin = GPIO_PIN_6;
GPIO_InitType.Pin = GPIO_PIN_4;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
/* DMA配置 */
__HAL_RCC_DMA1_CLK_ENABLE();
tim3_dmaup.Instance = DMA1_Channel3;
tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim1_dmaup.Init.Mode = DMA_NORMAL; //单次模式
//tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
HAL_DMA_Init(&tim3_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
/* 定时器4 外部模式1 通道2 */
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_7;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
/* DMA配置 */
__HAL_RCC_DMA1_CLK_ENABLE();
tim4_dmaup.Instance = DMA1_Channel7;
tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim1_dmaup.Init.Mode = DMA_NORMAL; //单次模式
//tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
HAL_DMA_Init(&tim4_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
/* 判断DMA的状态是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 */
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA1 完成中断\\r\\n");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 1 更新事件\\r\\n");
}
}else if(htim->Instance == TIM2){
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA2 完成中断\\r\\n");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 2 更新事件\\r\\n");
}
}else if(htim->Instance == TIM3){
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA3 完成中断\\r\\n");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 3 更新事件\\r\\n");
}
}else if(htim->Instance == TIM4){
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA4 完成中断\\r\\n");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 4 更新事件\\r\\n");
}
}
}
//触发中断 回调函数
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 触发事件:%d\\r\\n", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断\\r\\n");
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断\\r\\n");
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断\\r\\n");
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断\\r\\n");
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/* 对外声明总控结构体 */
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/* 初始化函数 */
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
Timer1_Init(5 - 1, 0, 1 - 1); //5次有效边沿
Timer2_Init(5 - 1, 0); // 5次
Timer3_Init(5 - 1, 0); // 5次
Timer4_Init(5 - 1, 0); // 5次
U1_Printf("初始化完成\\r\\n");
while(1){
}
}
stm32f1xx_it.c
/*-------------------------------------------------*/
/* */
/* 实现各种中断服务函数的源文件 */
/* */
/*-------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
#include "time.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
HAL_UART_AbortReceive_IT(&uart2.uart);
}
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
HAL_UART_AbortReceive_IT(&uart3.uart);
}
}
void DMA1_Channel4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmatx);
}
//void DMA1_Channel5_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart1.dmarx);
//}
//void DMA1_Channel7_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart2.dmatx);
//}
void DMA1_Channel6_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmarx);
}
//void DMA1_Channel2_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmatx);
//}
//void DMA1_Channel3_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmarx);
//}
void TIM1_UP_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim1);
}
void TIM1_TRG_COM_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim1);
}
void DMA1_Channel5_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim1_dmaup);
}
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim2);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim2_dmaup);
}
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim3);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim3_dmaup);
}
void TIM4_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim4);
}
void DMA1_Channel7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim4_dmaup);
}
/*-------------------------------------------------*/
/*函数名:不可屏蔽中断处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void NMI_Handler(void)
{
}
/*-------------------------------------------------*/
/*函数名:硬件出错后进入的中断处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void HardFault_Handler(void)
{
}
/*-------------------------------------------------*/
/*函数名:软中断,SWI 指令调用的处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void SVC_Handler(void)
{
}
/*-------------------------------------------------*/
/*函数名:可挂起的系统服务处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void PendSV_Handler(void)
{
}
/*-------------------------------------------------*/
/*函数名:SysTic系统嘀嗒定时器处理函数 */
/*参 数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void SysTick_Handler(void)
{
HAL_IncTick();
}
七、HAL库:TIM12 外部模式2 循环 中断 DMA方式 按键计数
具体方式与外模1类似,但是需要注意一下 两 点:
-
外部模式2并没有触发中断
可以看到外部模式1 有TIF触发事件的产生
但是外部模式2并没有
-
外部模式2仅支持ETR通道
- STMF103C8T6只有TIM 1 2 有ERT通道