这个想法还是来自于PLC,学过PLC的都知道,在PLC中定时器是用很多的,西门子S7-1200中定时器是这样的
想用更多的定时器可以这样
而且这么多定时器同时或者不同时工作都不会相互影响,原因就是相当于在生成定时器时也同时为这个定时器分配了储存其数据的内存,也就是背景数据块。我们看一下定时器的输入输出参数
两输入两输出,输入分别是定时器使能以及定时给定时间,输出分别是定时器定时时间到的标志位和当前时间值,是不是用起来很方便呢
在C语言中我定义了一个结构体变量用来存放这四个参数,同时定义三个结构体数组分别对应三个时间单位为1ms、10ms和100ms的定时器数量。
#define Timer_1ms_Quantity 10
#define Timer_10ms_Quantity 10
#define Timer_100ms_Quantity 10
typedef struct{
u8 IN;
u8 Q;
u16 PT;
u16 ET;
}IEC_TIMER;
extern IEC_TIMER TIMER_TON_1MS[Timer_1ms_Quantity],TIMER_TON_10MS[Timer_10ms_Quantity],TIMER_TON_100MS[Timer_100ms_Quantity];
这样定时器的大致轮廓就有了,下面用三个定时器分别定时1ms、10ms和100ms来得到定时时间单位
void TIM2_Int_Init(u16 arr,u16 psc);
void TIM3_Int_Init(u16 arr,u16 psc);
void TIM4_Int_Init(u16 arr,u16 psc);
void IEC_TIMER_Init(void);
void TIM2_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_TimeBaseInitStructure.TIM_Period=arr;
TIM_TimeBaseInitStructure.TIM_Prescaler=psc;
TIM_TimeBaseInitStructure.TIM_ClockDivision=0;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2,ENABLE);
}
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_TimeBaseInitStructure.TIM_Period=arr;
TIM_TimeBaseInitStructure.TIM_Prescaler=psc;
TIM_TimeBaseInitStructure.TIM_ClockDivision=0;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM3,ENABLE);
}
void TIM4_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
TIM_TimeBaseInitStructure.TIM_Period=arr;
TIM_TimeBaseInitStructure.TIM_Prescaler=psc;
TIM_TimeBaseInitStructure.TIM_ClockDivision=0;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM4,ENABLE);
}
void IEC_TIMER_Init(void)
{
TIM2_Int_Init(9,7199);//1ms
TIM3_Int_Init(99,7199);//10ms
TIM4_Int_Init(999,7199);//100ms
}
对定时器进行配置
下面编写定时器中断函数
void TIM2_IRQHandler() //TIM2中断
{
u8 i=0;
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
for(i=0;i<Timer_1ms_Quantity;i++)
{
if( TIMER_TON_1MS[i].IN&&TIMER_TON_1MS[i].ET < TIMER_TON_1MS[i].PT)
{
TIMER_TON_1MS[i].ET++;
}
if(TIMER_TON_1MS[i].IN && TIMER_TON_1MS[i].ET >= TIMER_TON_1MS[i].PT)
TIMER_TON_1MS[i].Q = 1;
else
TIMER_TON_1MS[i].Q = 0;
if(TIMER_TON_1MS[i].IN == 0)
{
TIMER_TON_1MS[i].Q = 0;
TIMER_TON_1MS[i].ET = 0;
}
}
}
}
void TIM3_IRQHandler() //TIM3中断
{
u8 i;
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
for(i=0;i<Timer_10ms_Quantity;i++)
{
if(TIMER_TON_10MS[i].IN && TIMER_TON_10MS[i].ET < TIMER_TON_10MS[i].PT)
TIMER_TON_10MS[i].ET ++;
if(TIMER_TON_10MS[i].IN && TIMER_TON_10MS[i].ET >= TIMER_TON_10MS[i].PT)
TIMER_TON_10MS[i].Q = 1;
else
TIMER_TON_10MS[i].Q = 0;
if(TIMER_TON_10MS[i].IN == 0)
{
TIMER_TON_10MS[i].Q = 0;
TIMER_TON_10MS[i].ET = 0;
}
}
}
}
void TIM4_IRQHandler() //TIM4中断
{
u8 i;
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
for(i=0;i<Timer_100ms_Quantity;i++)
{
if(TIMER_TON_100MS[i].IN && TIMER_TON_100MS[i].ET < TIMER_TON_100MS[i].PT)
TIMER_TON_100MS[i].ET++;
if(TIMER_TON_100MS[i].IN && TIMER_TON_100MS[i].ET >= TIMER_TON_100MS[i].PT)
TIMER_TON_100MS[i].Q = 1;
else
TIMER_TON_100MS[i].Q = 0;
if(TIMER_TON_100MS[i].IN == 0)
{
TIMER_TON_100MS[i].Q =0 ;
TIMER_TON_100MS[i].ET = 0;
}
}
}
}
好了,大功告成。这样在我们工程中如果需要大量定时器就可以通过这种方法去实现。比如要定时50ms时间,我们可以选择时间单位为10ms的定时器,在程序中我定义10ms单位的定时器数量为10个
#define Timer_10ms_Quantity 10
通过修改这个值就可以改变定时器数量,就是用多少定义为多少就行了,不要多哪怕一个。
如果我们要用第三个定时器,首先设置定时时间
TIMER_TON_10MS[2].PT = 5; //5*10=50ms
则打开定时器为
TIMER_TON_10MS[2].IN = 1;
定时时间到则可以使用if语句来判断
if(TIMER_TON_10MS[2].Q == 1)
{
}
好了,这次就写到这里,另外这里面TON的意思是向上计数,向下计数TOF也是同理,如果有时间我会写出来分享给大家的
资源附件搜索:STM32的一个通用定时器理论上可以当做N个来用