STM32基本定时器延时函数

发布者:bobojrt最新更新时间:2016-12-08 来源: eefocus关键字:STM32  基本定时器  延时函数 手机看文章 扫描二维码
随时随地手机看文章

注:本文实践用到的芯片是cortex-m3系列的STM32F103VET6,文中涉及内容覆盖整个STM32F1系列M3单片机。

本文适合学习STM32的初学者阅读。

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

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

TIM6 TIM7的寄存器如下所示:

基本定时器寄存器一览表

先略览一下寄存器,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.直接操作寄存器

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

void delay_ms(uint16_t ms)
{
 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,由寄存器定义得知,这是把定时器设置为一旦发生溢出,就停止定时器,因为我们做的是延时函数,延时到了以后,就没有必要让定时器再不断递增了,所以要这样设置。

CR1中的OPM位

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

CR1中的CEN

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

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

2.使用库函数

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

void TIM6_Delay_ms(uint16_t ms)
{
 /* 定义一个定时器基本定时初始化结构体变量 */
 TIM_TimeBaseInitTypeDef TIM_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),我们打开这个函数,如下所示:

void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
{
 /* Check the parameters */
 assert_param(IS_TIM_ALL_PERIPH(TIMx));
 assert_param(IS_FUNCTIONAL_STATE(NewState));
 
 if (NewState != DISABLE)
 {
 /* Enable the TIM Counter */
 TIMx->CR1 |= TIM_CR1_CEN;
 }
 else
 {
 /* Disable the TIM Counter */
 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如何产生PWM信号
下一篇:STM32使用printf丢失第一个字母的问

推荐阅读最新更新时间:2024-03-16 15:24

关于STM32 DMA的使用
1.DMA的使用范围: DMA(直接存储器存取)提供在外设与存储器之间或者存储器和存储器之间的高速数据传输使用。注意这里的外设指的是32的外设,比如spi、usart、iic、adc等基于APB1 、APB2或AHB时钟的外设,而这里的存储器包括32自身的闪存(flash)或者内存(SRAM)以及外设的存储设备都可以作为访问的源或者目的、 注意外部存储设备其自身在这就是外设了,配置时属于外设,不要与配置寄存器的存储设备混淆 2.以目前嵌入式为例,DMA和CPU两者怎么实现分时使用内存: 通常采用以下三种方法:(1)停止CPU访内存;(2)周期挪用;(3)DMA与CPU交替访问内存. 停止CPU访问内存 当外围设备要求传送一批
[单片机]
关于<font color='red'>STM32</font> DMA的使用
如何构建STM32单片机keil的开发环境
新建工程 工程名设为stm32_demo,选择芯片型号为STM32F103B,如图, 因为下载的STM32库中有启动代码,所以这里选择“否”,不拷贝启动代码。 在工程文件下,新建Startup、Headers、User、Libraries、CMSIS、Lists、Output文件夹。 文件夹 用途 Startup 启动文件,Flash在16~32Kb小容量,64~128Kb中容量,256~512Kb大容量 CMSIS Cortex微控制器软件接口标准文件,该目录下文件适用所有Cortex系列 Libraries 存放STM32的驱动库文件 Headers 自定义的全局头文件 User 用户文件,我们把main.c放在该目录
[单片机]
如何构建<font color='red'>STM32</font>单片机keil的开发环境
STM32 串口采用DMA方式接收数据
环境: 主机:WINXP 开发环境:MDK4.23 MCU:STM32F103CBT6 说明: 串口可以配置成用DMA的方式接收数据,不过DMA需要定长才能产生接收中断,如何接收可变长度的数据呢? 方法有以下3种: 1.将RX脚与一路时钟外部引脚相连,当串口一帧发完,即可利用此定时器产生超时中断.这个实时性较高,可以做到1个字节实时监测. 2.不改变硬件,开启一个定时器监控DMA接收,如果超时则产生中断.这个实时性不高,因为超时时间必须要大于需要接收帧的时间,精度不好控制. 3.STM32单片机有的串口可以监测总线是否处于空闲,如果空闲则产生中断.可以用它来监测DMA接收是否完毕.这种方式实时性很高. 本文采用第3种方式.在波
[单片机]
<font color='red'>STM32</font> 串口采用DMA方式接收数据
STM32函数中GPIO_Init的理解
STM32中GPIO的配置风格和以往研究的MCU有很大的不同,研究了好一段时间才搞通。 typedef enum { GPIO_Mode_AIN = 0x0, GPIO_Mode_IN_FLOATING = 0x04, GPIO_Mode_IPD = 0x28, GPIO_Mode_IPU = 0x48, GPIO_Mode_Out_OD = 0x14, GPIO_Mode_Out_PP = 0x10, GPIO_Mode_AF_OD = 0x1C, GPIO_Mode_AF_PP = 0x18 }GPIOMode_TypeDef; 配置一个引脚只需要4位寄存器,而上面却定义了8位,仔细研究GPIO_Init()
[单片机]
STM32 嵌入式学习入门(0)——C语言基础复习
摘要 主要介绍了嵌入式编程中几个常用,但软件编程中用得不是很多的C语言知识。包括位操作、条件编译、结构体和结构体指针、typedef声明类型、以及extern变量声明、static关键字等内容。 本文并没有将相关C语言知识点介绍地很详细,毕竟这么多知识点要想掌握绝对不是看几篇文档就能掌握的。因此博主建议,如果上述的C语言知识掌握得还不是很好的话,找一本C语言的书好好研究研究。尤其是结构体和结构体指针、还有函数的知识(本文没提到),一定要很熟练。 本文除了简要介绍C语言知识,也结合博主自己的感受简单谈了各个知识点用在了嵌入式编程的什么地方,有不详细和描述不准确的地方欢迎大家留言讨论。 要想学习STM32
[单片机]
stm32 TIM输出pwm有些通道不能输出的问题
今天晚上在玩舵机,看了一下例程的代码,于是想换个通道实践一下,于是想把TIM1的通道由ch1换到ch2,于是就把搞了PA8换成了PA9(数据手册上有),把TIM_OC1PreloadConfig换成了TIM_OC2PreloadConfig,试了一下不行,后来又找哪里的OC1没换成OC2,发现TIM_OC1Init没换,于是换成TIM_OC2Init,试了一下还是不行,又在pwm.c里找了好久找不到,网上找答案,以为ch2是默认关闭的,发现不是,后来终于发现主函数里的TIM_SetCompare1没换成TIM_SetCompare2,这种粗心花了我一个小时找答案。。。
[单片机]
STM32 LL库为什么比HAL库高效呢?
概 述 有些应用要求MCU能高效处理,特别是跑一些算法时,对CPU执行效率要求较高。 网上有很多文章说STM32Cube HAL执行效率不高,代码量大等问题 ,导致很多还没有入门,或初学的读者就产生各种各样的疑惑。 说实话,HAL相对标准外设库来说确实存在代码效率不高、代码量大灯这些问题,那么与之对应的STM32Cube LL恰好避免了这样的问题。 LL能高效的原因 简单总结一下原因: 巧妙运用C语言静态、内联函数直接操作寄存器 。 当然,这是其中重要的原因,还有一些其它原因,这里暂不描述。 你会在LL库.h文件中发现大量类似,静态、内联函数直接读写寄存器的函数。 比如读写IO口: __STATIC_
[单片机]
<font color='red'>STM32</font> LL库为什么比HAL库高效呢?
基于STM32的便携式人机界面系统
摘要:设计应用于全站仪测量计算的基于STM32处理器的便携式人机界面系统。采用了处理器IO口模拟总线时序和外挂SPI接口Flash存储字库的方法,将字库存储在外部的SPI接口Flash中,在使用时再从字库中查询调出,有效地减少了内部存储器的消耗。完成了基于ARM最新Cortex—M3处理器汉字显示系统的硬件电路设计和软件程序设计。实现了可以自定义汉字字库的人机界面系统。 关键词:全站仪;ARM微控制器;STM32;TFT液晶;人机界面 在全站仪应用于飞机的测量过程中,常会涉及到计算,以满足不同的应用环境与测量要求,以往的方式是测量后期编辑软件在计算机上实现,现代测量迫切需要一种便携式手持计算系统,来完成实时的测量要求,而这一系
[工业控制]
基于<font color='red'>STM32</font>的便携式人机界面系统
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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