前面介绍了IAP15W413AS这款控制板的基本输入和输出控制,这一帖主要跟大家介绍一下怎么使用定时器来精确定时控制输出,还是用最简单的流水灯为例来介绍。
既然要使用定时器,那么首先肯定要配置好定时器的工作模式、定时时间长等参数:
/**************** 定时器配置 ******************/
void Timer_config(void)
{
TIM_InitTypeDef TIM_InitStructure; //结构定义
TIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
TIM_InitStructure.TIM_Polity = PolityLow; //指定中断优先级, PolityHigh,PolityLow
TIM_InitStructure.TIM_Interrupt = ENABLE; //中断是否允许, ENABLE或DISABLE
TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
TIM_InitStructure.TIM_ClkOut = DISABLE; //是否输出高速脉冲, ENABLE或DISABLE
TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / 1000); //初值,1000HZ中断率,500HZ方波(1ms定时)
TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE
Timer_Inilize(Timer0,&TIM_InitStructure); //初始化Timer0 Timer0,Timer1,Timer2,Timer3,Timer44
}
在上面定时器的配置中,我们可以看到,使用的是定时器0,定时器的工作模式为“16位自动重装模式”,定时时长为“1毫秒”。如果要修改定时时长,值需要修改TIM_InitStructure.TIM_Value的值就好了,也即将后面的1000改成我们需要的数,至于具体计算方式,还请看芯片手册上的定时器这一章节,在这里就不再赘述。
定时器的参数配置好之后,我们就可以来使用定时器了,首先,我们定义两个变量OUT_CTR和Time_Cnt,其中OUT_CTR是用来控制输出的标志位,Time_Cnt是用来计时的:
bit OUT_CTR; //定义一个标志控制输出
u16 Time_Cnt; //定义一个变量用来计时
我们以定时500毫秒为例,定时器是每1毫秒中断一次,那么我们需要定时500毫秒的话,就可以让一个变量在定时器每次中断的时候自动加1,那么当这个变量加到500的时候,自然就是500毫秒了。
/********************* Timer0中断函数************************/
void timer0_int (void) interrupt TIMER0_VECTOR //1ms
{
if(++Time_Cnt>=500)
{
OUT_CTR = 1;
Time_Cnt= 0;
}
}
同时,我们在每定时到500毫秒的时候,将输出标志位OUT_CTR置1,用来控制后面的输出,同时也需要将Time_Cnt清零以便下次又从0开始计数。
由于变量OUT_CTR和Time_Cnt是在Timer.c里面定义的,那么我们在main.c里面也要用这两个变量怎么办?很明显,我需要对外部变量进行声明,声明之后我们就可以使用外部变量了:
extern bit OUT_CTR; //定义一个标志控制输出
extern u16 Time_Cnt; //定义一个变量用来计时
同时为了方便控制输出口的顺序输出,我们还定义了一个变量:
u8 Num; //定义一个变量来控制输出顺序
还有,为了方便让输出状态更容易理解,笔者宏定义了两个参数,在后面需要赋值1的地方便可以直接用ON来替代,需要赋值0的地方,可以直接用OFF来替代,这样会使得程序看起来更加容易理解:
#define ON 1
#define OFF 0
好了,准备工作都做好了,接下来就要来写我们要实现的动作了:
void main(void)
{
OUT00 = OFF;
OUT01 = OFF;
OUT02 = OFF;
OUT03 = OFF;
OUT04 = OFF;
OUT05 = OFF;
delay_ms(1000); //延时大约1秒,等待电源稳定
Timer_config(); //定时器配置
GPIO_config(); //GPIO配置
EA = 1; //开启总中断
Time_Cnt = 0;
OUT_CTR = 0;
Num = 0;
while(1)
{
if(OUT_CTR)
{
OUT_CTR = 0;
if(Num==0)
{
OUT05 = OFF;
OUT00 = ON;
}
if(Num==1)
{
OUT00 = OFF;
OUT01 = ON;
}
if(Num==2)
{
OUT01 = OFF;
OUT02 = ON;
}
if(Num==3)
{
OUT02 = OFF;
OUT03 = ON;
}
if(Num==4)
{
OUT03 = OFF;
OUT04 = ON;
}
if(Num==5)
{
OUT04 = OFF;
OUT05 = ON;
}
Num ++;
if(Num>5) //因为只有5个输出,所以这里控制最大输出序号不能超过5
{
Num = 0;
}
}
}
}
思路是这样的:每500毫秒OUT_CTR会被自动置1,那么我们便在每次OUT_CTR置1的时候,控制一个输出口ON,当然我们也需要关闭前面一个输出口,不然就会所有输出口全部都依次亮了,而不是顺序亮的流水灯效果了。在每次操作一个输出口后,我们需要将Num加1,以便控制下一个输出口动作,同时,我们需要将OUT_CTR软件清零。另外需要注意的是,因为我们只有6个IO口,而Num是从0开始计数的,所以,当Num超过5后,我们需要将Num清零,否则就不能循环亮灯了。
至于演示效果就不再帖上来了,因为跟之前的延时函数流水灯的效果是一致的,源代码见附件!
源代码: