前言
? ? ? ? 在我们编代码的时候,往往需要固定一程序心跳包去进行一个保活,或者给一个程序运行一个固定的时候,再或者是PWM的使用,都离不开定时器的使用,不仅方便我们处理数据,还给我们节约了MCU的内存,让我们的程序可以更加高效的执行起来
🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎
一.定时器的配置
1.timer.c
把TIM配置进行了封装处理,更加方便我们的配置和修改
#include "timer.h"
#include "led.h"
/*********************************************************************************
* @Function : 通用定时器的选择(TIM2-TIM5)
* @Author : HR
* @Date : 2022-08-30
**********************************************************************************/
#if GENERAL_TIM2
U16 Usart3_Time = 0; // ms 计时变量
U16 Usart4_Time = 0; // ms 计时变量
U16 Usart5_Time = 0; // ms 计时变量
#endif
#if GENERAL_TIM3
U32 time = 0; // ms 计时变量
#endif
#if GENERAL_TIM4
U16 time_4 = 0; // ms 计时变量
#endif
#if GENERAL_TIM5
U16 time_5 = 0; // ms 计时变量
#endif
/*********************************************************************************
* @Function : TIM定时器选择
* @Input : time,TIM定时器(TIM_2-TIM_5)
* @Output : TIM模块
* @Return : None
* @Others : None
* @Date : 2022-08-30
**********************************************************************************/
static TIM_TypeDef * TimeModule_get( TimeModule time )
{
TIM_TypeDef * timeTemp;
switch( ( U8 )time )//UART模块选择
{
#if GENERAL_TIM2
case TIM_2:
timeTemp = TIM2;
break;
#endif
#if GENERAL_TIM3
case TIM_3:
timeTemp = TIM3;
break;
#endif
#if GENERAL_TIM4
case TIM_4:
timeTemp = TIM4;
break;
#endif
#if GENERAL_TIM5
case TIM_5:
timeTemp = TIM5;
break;
#endif
}
return timeTemp;
}
/*********************************************************************************
* @Function : TIM定时器中断初始化
* @Input : time,TIM定时器(TIM_2-TIM_5)
* PreemptionPriority,抢占优先级
* SubPriority,子优先级
* @Output : None
* @Return : None
* @Others : None
* @Date : 2022-08-30
**********************************************************************************/
static void GENERAL_TIM_NVIC_Config( TimeModule time, U8 PreemptionPriority, U8 SubPriority)
{
NVIC_InitTypeDef NVIC_InitStructure;
// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断组为0
//Usart NVIC 配置
switch( ( U8 )time )//中断通道配置
{
case TIM_2: NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;break; //TIM2中断
case TIM_3: NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;break;
case TIM_4: NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;break;
case TIM_5: NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;break;
}
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= PreemptionPriority ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = SubPriority; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}
/*********************************************************************************
* @Function : TIM时钟使能
* @Input : time,time时钟(TIM_1-TIM_5)
* @Output : None
* @Return : None
* @Others : None
* @Date : 2022-08-30
**********************************************************************************/
static void GENERAL_TIMClock_Enable( TimeModule time)
{
switch( (U8)time )
{
case TIM_2: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); break;//通用定时器2时钟使能
case TIM_3: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); break;//通用定时器2时钟使能
case TIM_4: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); break;//通用定时器2时钟使能
case TIM_5: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); break;//通用定时器2时钟使能
}
}
/*
* 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有
* TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,
* 另外三个成员是通用定时器和高级定时器才有.
*-----------------------------------------------------------------------------
*typedef struct
*{ TIM_Prescaler 都有
* TIM_CounterMode TIMx,x[6,7]没有,其他都有
* TIM_Period 都有
* TIM_ClockDivision TIMx,x[6,7]没有,其他都有
* TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有
*}TIM_TimeBaseInitTypeDef;
*-----------------------------------------------------------------------------
*/
static void GENERAL_TIM_Mode_Config(TimeModule time)
{
TIM_TypeDef * timeTemp;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
timeTemp = TimeModule_get( time );//TIME时钟选择
// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_Period;
// 时钟预分频数
TIM_TimeBaseStructure.TIM_Prescaler= GENERAL_TIM_Prescaler;
// 时钟分频因子 ,没用到不用管
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
// 计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
// 重复计数器的值,没用到不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
// 初始化定时器
TIM_TimeBaseInit(timeTemp, &TIM_TimeBaseStructure);
// 清除计数器中断标志位
TIM_ClearFlag(timeTemp, TIM_FLAG_Update);
// 开启计数器中断
TIM_ITConfig(timeTemp,TIM_IT_Update,ENABLE);
// 使能计数器
TIM_Cmd(timeTemp, DISABLE); //关闭定时器
}
/*********************************************************************************
* @Function : TIM2-5 初始化
* @Input : time,TIM定时器(TIM_2-TIM_5)
* PreemptionPriority,抢占优先级
* SubPriority,子优先级
* @Output : None
* @Return : None
* @Others : None
* @Date : 2022-08-30
**********************************************************************************/
void GENERAL_TIM_Init(TimeModule time,U8 PreemptionPriority, U8 SubPriority)
{
GENERAL_TIMClock_Enable(time); //TIM使能化
GENERAL_TIM_NVIC_Config(time,PreemptionPriority,SubPriority); //TIM中断优先级配置
GENERAL_TIM_Mode_Config(time); //TIM初始化
}
/*********************************************************************************
* @Function : TIMER2定时器中断服务
* @Input : None
* @Output : None
* @Return : None
* @Others : None
* @Date : 2022-08-30
**********************************************************************************/
#if GENERAL_TIM2
void TIM2_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
if(Usart5_Time>0){
Usart5_Time++;//串口五接收间隔判断
}else if(Usart4_Time>0){
Usart4_Time++;//串口四接收间隔判断
}else if(Usart3_Time>0){
Usart3_Time++;//串口三接收间隔判断
}
//满足条件关定时器
if(Usart5_Time==10||Usart3_Time==10||Usart4_Time==10){
TIM_Cmd(TIM2, DISABLE); //关闭定时器
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIMx更新中断标志
}
}
#endif
/*********************************************************************************
* @Function : TIMER3定时器中断服务
* @Input : None
* @Output : None
* @Return : None
* @Others : None
* @Date : 2022-08-30
**********************************************************************************/
#if GENERAL_TIM3
void TIM3_IRQHandler(void) //TIM3中断
{
U8 i;
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
if(time>0){
time++;//串口五接收间隔判断
}
//满足条件关定时器
if(time==10000){
LED2_OFF;
time=0;
TIM_Cmd(TIM3, DISABLE); //关闭定时器
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
}
}
#endif
2.timer.h
在主函数只需要选择我们需要配置的通用定时器即可
例如?
GENERAL_TIM_Init(TIM_2,0,3);?? ??? ?//初始化定时器2,抢占优先级,子优先级(防止掉帧)
#ifndef __TIMER_H
#define __TIMER_H
#include "tool.h"
#include "stm32f10x_tim.h"
/**************通用定时器TIM参数定义,只限TIM2、3、4、5************/
// 当需要哪个定时器的时候,只需要把下面的宏定义改成1即可
#define GENERAL_TIM2 1
#define GENERAL_TIM3 1
#define GENERAL_TIM4 0
#define GENERAL_TIM5 0
/*********************************************************************************
* @Function : TIME实例
**********************************************************************************/
typedef enum
{
TIM_2,
TIM_3,
TIM_4,
TIM_5,
TIME_NUM
}TimeModule;
/*********************************************************************************
* @Function : 固定分频率
**********************************************************************************/
#define GENERAL_TIM_Period (1000-1)
#define GENERAL_TIM_Prescaler 71 //时钟预分频数
/*********************************************************************************
* @Function : TIM2-5 初始化
* @Input : time,TIM定时器(TIM_2-TIM_5)
* PreemptionPriority,抢占优先级
* SubPriority,子优先级
* @Output : None
* @Return : None
* @Others : None
* @Date : 2022-08-30
**********************************************************************************/
void GENERAL_TIM_Init(TimeModule time,U8 PreemptionPriority, U8 SubPriority);
#endif
🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎
二.定时器的使用
1.PWM输出使用
使用TIM的分频率去控制PWM的输出,做到控制端口电压的输出,可实现呼吸灯,电机转速等控制效果
2.软件定时器的使用
例如我们执行一个开关的的程序,当我们固定一个动作打开灯后,在这个打开灯的时候就开启我们的定时器,在定时器里面做一个固定时间再关闭我们的灯
例如下列代码
在主函数首先进行TIM3的配置
GENERAL_TIM_Init(TIM_3,0,2); //初始化定时器3,抢占优先级,子优先级(LED定时器)
?对TIM3的中断进行一个配置即可
/*********************************************************************************
* @Function : TIMER3定时器中断服务
* @Input : None
* @Output : None
* @Return : None
* @Others : None
* @Date : 2022-08-30
**********************************************************************************/
#if GENERAL_TIM3
void TIM3_IRQHandler(void) //TIM3中断
{
U8 i;
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
if(time>0){
time++;//串口五接收间隔判断
}
//满足条件关定时器
if(time==10000){
LED2_OFF;
time=0;
TIM_Cmd(TIM3, DISABLE); //关闭定时器
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
}
}
#endif
3.串口防止掉帧使用等
道理相同,我们主要是防止串口出现丢包情况。所以配置一个定时器检测他的接收情况 ,如果串口在我们规定的时间内没有再有数据的输出,则说明我们的串口数据接收完成
/*********************************************************************************
* @Function : TIMER2定时器中断服务
* @Input : None
* @Output : None
* @Return : None
* @Others : None
* @Date : 2022-08-30
**********************************************************************************/
#if GENERAL_TIM2
void TIM2_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
if(Usart5_Time>0){
Usart5_Time++;//串口五接收间隔判断
}else if(Usart4_Time>0){
Usart4_Time++;//串口四接收间隔判断
}else if(Usart3_Time>0){
Usart3_Time++;//串口三接收间隔判断
}
//满足条件关定时器
if(Usart5_Time==10||Usart3_Time==10||Usart4_Time==10){
TIM_Cmd(TIM2, DISABLE); //关闭定时器
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIMx更新中断标志
}
}
#endif
🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎🚎
|