龙空技术网

C语言之“编程超简单系列”:芯片的“手表”——定时器

美人派 894

前言:

今天各位老铁们对“c语言1秒延时程序怎么写”都比较注意,看官们都需要分析一些“c语言1秒延时程序怎么写”的相关资讯。那么小编在网络上搜集了一些关于“c语言1秒延时程序怎么写””的相关内容,希望你们能喜欢,大家一起来了解一下吧!

“时间”在这个世界中是很重要的,它的存在使得世界有秩序地运行着,我们每天都“按时”吃饭,上班,学习,睡觉,这都是参照时间而执行的事情。那么在C语言嵌入式世界中,设备能够正常地执行任务也需要来“按时”执行相应的过程。我们平常怎么查看时间呢?那当然是看钟表来获得当前的时间,当然了现在也可以通过手机或者一些电子设备来看时间了。而嵌入式设备是通过什么来计算时间的呢?那就是它内部的定时器。

时间

定时器,顾名思义就是来设定时间的,C语言程序中的延时,定时,时钟等等有关时间的都是通过它控制的。有了它,系统才能稳定正常地工作,你可以想想假如你无法知道当前的时间,你的生活会变成什么样?这个我还真是无法想象。

那么这个定时器是怎么工作的呢?今天就来和各位好好探讨一下。在前几章就和大家讲过了,“晶振”是MCU的心脏,就是“晶振”推动着程序的运行,晶振是有频率的,它不是随便振的,一般都是n(MHz),也就是每秒振(n * 1000 * 1000)次,可是晶振的频率有时还不能满足系统或者外设的要求,所以就必须通过倍频器或者分频器来获得相应的“时钟源”,如果频率高了就用分频器,如果频率低了就用倍频器,当然了分频和倍频都有一些固定的系数,也不是你想多少就是多少。

定时器系统

由上图可知定时器的时钟源是由外部提供的,我们在使用定时器之前一定要先配置好晶振、倍频器和分频器,否则时间肯定就不准啦(这些都是在系统的启动函数中配置的)。一般在STM32中有很多个定时器,我们选择不同的定时器,那么对应的频率也不相同,所以我们在使用前一定要先看好。在配置好时钟源之后就要来配置“定时器”了。

和前面一样,你要配置什么设备,就要先创建这个设备所对应的的“结构体”,这个结构体中包含的就是需要配置的参数,在STM32中配置其实都是这个套路,你要用什么设备就创建对应的结构体进行初始化,只要初始化成功了,那用起来就和玩一样!

所以在这里我们就要创建定时器对应的结构体,TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;这样就创建了一个定时器,只是还没有对它进行初始化。接下来就让我们来看看它有哪些参数需要配置。

TIM_Period (自动重装载值):每个周期定时器需要计数的次数

TIM_Prescaler (定时器分频):其实也就是分频器,将给定时器的时钟源分频,得到计数的频率

TIM_CounterMode(计数模式):有向上计数,向下计数和中间计数,向上计数也就是从0开始不断加1直到加到自动重装载值

TIM_ClockDivision(时钟分频因子):老实说我也不太清楚这个,不过一般都用TIM_CKD_DIV1;

将这些配置好就OK啦!,具体配置如下:

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); ///使能TIM3时钟

TIM_TimeBaseInitStructure.TIM_Period = arr; //自动重装载值

TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //定时器分频

TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式

TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;

TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM3

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器3更新中断

TIM_Cmd(TIM3,ENABLE); //使能定时器3

定时器就是定时,那么是怎么定时的呢?定时器,每执行一个周期就会中断一次!前面配置了“自动重装载值”和“定时器分频”,那么一个周期的时间就是Tout= ((arr+1)*(psc+1))/Tclk;其中Tclk就是输入给定时器的的时钟频率。简单理解就是先将定时器的时钟频率分频,分频系数为(psc+1),也就是计数频率为,Tclk/(psc+1),那么计一个数的时间为频率的倒数也就是(psc+1)/Tclk,一个周期需要计(arr+1)个数,所以最终一个周期的时间就是Tout= ((arr+1)*(psc+1))/Tclk;你要问为什么psc和arr要加1,这个是STM32的机制,例如你要分频n,那么psc就等于n-1,你要计数m,那么arr就等于m-1,stm32会自动为他们加1,是为了防止分频和计数为0的情况出现。

刚才提到了“中断”,定时器设置了中断之后,每个周期完成时都会产生一个中断,那么就要配置一下中断并且写一个中断函数了。

配置中断:

NVIC_InitTypeDef NVIC_InitStructure; //创建中断

NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级3

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//允许中断

NVIC_Init(&NVIC_InitStructure); //初始化中断

中断函数:我们设置每产生一个中断time就加1,到时候我们就可以通过判断time的值来判断当前的时间了

void TIM3_IRQHandler(void)

{

if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断

{

time++;

}

TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位

}

延时函数:

int time;

void TIM3_Int_Init(u16 arr,u16 psc)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); ///使能TIM3时钟

TIM_TimeBaseInitStructure.TIM_Period = arr; //自动重装载值

TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //定时器分频

TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式

TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;

TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM3

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器3更新中断

TIM_Cmd(TIM3,ENABLE); //使能定时器3

NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级3

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

NVIC_Init(&NVIC_InitStructure);

}

void delay(int timer) //延时函数,延时之前将time清零,延时的长短由timer设置

{

time = 0;

while(time < timer);

}

//定时器3中断服务函数

void TIM3_IRQHandler(void)

{

if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断

{

time++;

}

TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位

}

使用步骤:使用初始化函数配置好自动重装值和分频系数之后,就可以使用延时函数了。

这其实是定时器的基础功能了,当然如何灵活使用就要看大家自己的能力了。还是那句话“学海无涯苦作舟”,大家要学习更要活学活用,这样你才不一般。好今天的C语言分享就到这里。

C语言

喜欢的话就点个赞吧!

标签: #c语言1秒延时程序怎么写