基于STM32定时器实现毫秒延时函数

发布者:京玩儿最新更新时间:2020-05-23 来源: eefocus关键字:STM32  定时器  毫秒延时函数 手机看文章 扫描二维码
随时随地手机看文章

STM32定时器包含基本定时器、通用定时器和高级定时器,其中TIM6和TIM7是STM32当中的基本定时器,作为初学者,先从最基本的学起最容易,下面我们用这个定时器实现毫秒延时函数来入门STM32定时器的应用。


学习单片机,就是学习使用它的寄存器。即便你用库函数,寄存器也是必须要学习的。


TIM6 TIM7的寄存器如下所示:

基于STM32定时器实现毫秒延时函数
 

先略览一下寄存器,CR1和CR1是控制寄存器,SR是状态寄存器,ARR就是溢出值寄存器,CNT就是计数器的当前值,PSC是预分频寄存器。预分频寄存器?听的傻眼了吧,前面几个个寄存器听的还能理解,一听到预分频寄存器,好像不知道是干嘛用的。瑞生来给你解释一下吧,你可以给预分频寄存器里面写一个从0~65535的值,这个值+1,就是定时器运行的时钟。举个例子,比如单片机工作在主频72MHz,预分频寄存器写0,预分频系数就是0+1=1,定时器的时钟就是72MHz/1=72MHz;再举个例子,比如单片机还是工作在主频72MHz,预分频寄存器写71,预分频系数就是71+1=72,定时器的时钟就是72MHz/72=1MHz。知道定时器的时钟有什么用?相信很多初学者不清楚,定时器的时钟关乎定时器计数器CNT递增的时间间隔,根据频率和周期的公式f=1/T,定时器计数器递增的时间间隔就是1/定时器的时钟,例如当定时器时钟为1MHz时,定时器计数器递增的时间间隔就是1/1MHz=1微秒,这时,如果你把溢出值设置为1000,就是1000*1us=1ms溢出。


1.直接操作寄存器

下面,我们先用直接操作寄存器的方式,写一个毫秒延时函数:

voiddelay_ms(uint16_tms){TIM6->PSC=35999;TIM6->ARR=ms*2;TIM6->CR1|=(1<<3);TIM6->CR1|=0x1;while((TIM6->SR&0X1)==0);TIM6->SR=0;}

第一条语句,设置预分频系数为35999+1=36000,所以定时器的时钟为72000000/36000=2000Hz,那么定时时间间隔就是1/2000=0.0005秒,即0.5毫秒。

第二条语句,设置溢出值为ms乘以2,假如要延时1秒,函数的参数ms就是1000,溢出值就是1000*2=2000,2000*0.5毫秒=1000毫秒,即1秒。这时候,有人会说,为什么不干脆把预分频值PSC设置为71999,即预分频系数为72000,定时器的时钟就是72000000/72000=1000Hz,定时时间就是1毫秒,那么直接把函数的参数ms给了溢出值寄存器ARR就可以了,就不必乘以2了。想法是可以,但是你得知道,定时器都是16位的,所以PSC的值最大到65535,到不了71999。这下你明白了吧?


第三条语句,CR1寄存器bit3写1,由寄存器定义得知,这是把定时器设置为一旦发生溢出,就停止定时器,因为我们做的是延时函数,延时到了以后,就没有必要让定时器再不断递增了,所以要这样设置。

基于STM32定时器实现毫秒延时函数

第四条语句,CR1寄存器bit0写1,打开定时器,定时器计数器开始从0递增。

基于STM32定时器实现毫秒延时函数

第五条语句,检测状态寄存器SR中的bit0UIF是否置1,置1的时候,定时值就达到溢出值了,说明定时时间到了。


第六条语句,清除状态寄存器SR中刚才溢出造成的UIF位。


2.使用库函数

下面,我们看看怎么使用库函数实现毫秒延时函数:

voidTIM6_Delay_ms(uint16_tms){/*定义一个定时器基本定时初始化结构体变量*/TIM_TimeBaseInitTypeDefTIM_TimeBaseInitStruct;/*时钟预分频数为36000,在主频72M时,计数器每500us加1*/TIM_TimeBaseInitStruct.TIM_Prescaler=35999;/*自动重装载寄存器值*/TIM_TimeBaseInitStruct.TIM_Period=ms*2;/*把上面的值配置到寄存器*/TIM_TimeBaseInit(TIM6,&TIM_TimeBaseInitStruct);/*设置定时时间到了以后停止定时器计数*/TIM_SelectOnePulseMode(TIM6,TIM_OPMode_Single);/*清除SR中的UIF标志*/TIM_ClearFlag(TIM6,TIM_IT_Update);/*打开定时器6*/TIM_Cmd(TIM6,ENABLE);/*检测定时时间是否到来*/while(TIM_GetFlagStatus(TIM6,TIM_IT_Update)==RESET);/*软件清除更新标志*/TIM_ClearFlag(TIM6,TIM_IT_Update);}

你可以细细观察一下上面的库函数,实际上,和直接操作寄存器是一样的。比如说,我们看打开定时器的库函数TIM_Cmd(TIM6,ENABLE),我们打开这个函数,如下所示:

voidTIM_Cmd(TIM_TypeDef*TIMx,FunctionalStateNewState){/*Checktheparameters*/assert_param(IS_TIM_ALL_PERIPH(TIMx));assert_param(IS_FUNCTIONAL_STATE(NewState));if(NewState!=DISABLE){/*EnabletheTIMCounter*/TIMx->CR1|=TIM_CR1_CEN;}else{/*DisabletheTIMCounter*/TIMx->CR1&=(uint16_t)(~((uint16_t)TIM_CR1_CEN));}}

把参数TIM6和ENABLE带进去,你会发现,实际上,就是我们直接操作寄存器的TIM6->CR1|=0X1。


其它的库函数,你可以自己打开研究一下。


另外,库函数和我们直接操作寄存器有个不同的地方,就是TIM_TimeBaseInit()这个函数中的最后一条语句,它给TIMx->EGR寄存器的bit0写了1,使得SR中的bit0UIF置1,所以在执行完TIM_TimeBaseInit()这个函数之后,我们后面用TIM_ClearFlag(TIM6, TIM_IT_Update);函数把UIF清0,要不然的话,你在后面会直接检测到UIF置1,但是,这个置1不是溢出产生的,而是刚才给EGR写1产生的,就达不到延时的效果了。


总结,在使用以上两个延时函数的时候,记得先允许TIM6外设,即给APB1ENR寄存器的bit4写1。或者直接用库函数RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6 , ENABLE)。从上面库函数和直接操作寄存器的延时函数,你可以看出,使用库函数,即使不用注释,也可以看出来你是在干嘛,而直接操作寄存器,就看不出来了。在实际使用中,没必要纠结库函数和直接操作寄存器的选择,我就喜欢一会用库函数,一会儿直接操作寄存器,你想咋地?不过,公司的老板肯定是希望使用库函数,因为如果你辞职了,接替你的人看到一堆操作寄存器的代码,让他情何以堪?

关键字:STM32  定时器  毫秒延时函数 引用地址:基于STM32定时器实现毫秒延时函数

上一篇:基于STM32单片机低功耗模式机制详细解析
下一篇:基于STM32单片机的64Mbit单对单通信

推荐阅读最新更新时间:2024-11-12 23:52

STM32按键程序
u8 KEY_Scan(u8 mode) { static u8 key_up=1;//按键按松开标志 if(mode)key_up=1; //支持连按 if(key_up&&(KEY0==0||KEY1==0||KEY2==0||KEY3==1)) { delay_ms(10);//去抖动 key_up=0; if(KEY0==0)return 1; else if(KEY1==0)return 2; else if(KEY2==0)return 3; else if(KEY3==1)return 4; }else if(KEY0==1&&KEY1==1&&KEY2==1&&KEY3==0)key_up=1;
[单片机]
使用STM32微控制器系列中的DAC生成音频和波形之DAC特性
《前言》 本应用笔记举例介绍了使用数模转换器 (DAC) 外设生成音频输出信号的过程,该 DAC 外设内嵌在 STM32F10xx 微控制器系列产品中。 数模转换器 (DAC) 是一种与模数转换器功能相反的器件,可以将数字形式的数据转换为相应的模拟电压信号。 STM32 DAC 模块是 12 位字转换器,带有两个支持立体声音频的输出通道。 DAC 可用于多种音频应用中,例如:安全警报、蓝牙耳机、发声玩具、答录机、人机接口以及低成本的音乐播放器STM32 DAC 还可实现许多其他模拟用途,如模拟波形产生和控制工程。 《DAC主要特性》 1、数据格式 DAC 可以使用以下三种整型格式的数据:8 位右对齐、12 位右对齐以及
[单片机]
使用<font color='red'>STM32</font>微控制器系列中的DAC生成音频和波形之DAC特性
stm32 HAL 重映射
以定时器重映射为例 部分重映射:只改变CH1、CH2管脚 完全重映射:CH1~CH4管脚全部改变 在stm32f1xx_hal_gpio_ex.h找到重映射语句 添加到管脚定义语句前 完成
[单片机]
STM32按键的检测
STM32的按键检测相对比较简单,首先按部就班的初始化连接的到的i/o,然后写一个按键扫描函数,这个和51单片机的差不多。 以下是一个比较典型的例子: 利用按键控制LED: key.h文件 #ifndef__KEY_H #define__KEY_H #include sys.h“ #defineKEY0 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)//读取按键0 #defineKEY1 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)//读取按键1 #defineKEY2 GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)//读取
[单片机]
STM32数模转换器(DAC)简析
STM32F4xx系列提供的DAC模块是12 位电压输出数模转换器。DAC可以按 8 位或 12 位模式进行配置,并且可与DMA控制器配合使用。在 12 位模式下,数据可以采用左对齐或右对齐。DAC有两个输出通道,每个通道各有一个转换器。在DAC双通道模式下,每个通道可以单独进行转换;当两个通道组合在一起同步执行更新操作时,也可以同时进行转换。可通过一个输入参考电压引脚VREF+(与ADC共享)来提高分辨率。 DAC通道框图 DAC引脚 DAC通道使能 将 DAC_CR 寄存器中的相应 ENx 位置 1,即可接通对应 DAC 通道。经过一段启动时间tWAKEUP 后,DAC 通道被真正使能。 注意:ENx 位只会使能模
[单片机]
<font color='red'>STM32</font>数模转换器(DAC)简析
关于STM32驱动DS1302的一点思考
之前用51驱动过DS1302,没用多久就输出了正确的时间。当时以为这块芯片其实没啥,很简单。但是现在用STM32做项目,用到同样的芯片,以为这有何难,只要把那个程序拿过来复制黏贴改一下IO设置不就行了?但是事情远没有想想的那么简单。 经过3天的挣扎,现在才知道当时自己是多么天真。 关于DS1302的基本操作可以看这里:http://www.cnblogs.com/qsyll0916/p/7712695.html 好了,废话少说了,进入正题。 首先DS1302读写方式属于3线SPI。CE、SCK、IO。其中IO口属于双向IO口,我们读写都要经过这个IO口。在用51开发的时候,因外他是准双向IO,不需要我
[单片机]
STM32时钟设置
3.5的库中什么也不用做。已经在启动文件中设置好了时钟。 大家都知道在使用单片机时,时钟速度决定于外部晶振或内部RC振荡电路的频率,是不可以改变的。而ARM的出现打破了这一传统的法则,可以通过软件随意改变时钟速度。这一出现让我们的设计更加灵活,但是也给我们的设计增加了复杂性。为了让用户能够更简单的使用这一功能,STM32的库函数已经为我们设计的更加简单方便。 在比较靠前的版本中,我们需要向下面那样设置时钟: ErrorStatus HSEStartUpStatus; void RCC_Configuration(void) { RCC_DeInit(); // RCC system reset
[单片机]
STM32之PVD电压检测
如果VDD或者VDDA电压高于或低于PVD设定阈值都产生中断,表现为每中断一次,LED1就亮变灭或者灭变亮。 /******************************************************************************** * @file PWR/PVD/main.c * @author MCD Application Team * @version V3.4.0 * @date 10/15/2010 * @brief Main program body. *********************************************
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved