STM32F407ZGT6使用Systic定时器实现延时

发布者:明石轩最新更新时间:2018-07-20 来源: eefocus关键字:STM32F407ZGT6  Systic  定时器  延时 手机看文章 扫描二维码
随时随地手机看文章

预备知识

        STM32F4的系统滴答计时器的介绍及其说明。时间有限,这里点到为止,详情自行百度。

        延时的原理:

                        因为在 ucos 下 systick 不能再被随意更改,如果我们还想利用 systick 来做 delay_us 或者
                delay_ms 的延时,就必须想点办法了,这里我们利用的是时钟摘取法。

                                ---这里摘自正点原子探索者F4,详细原理请自行百度。

实验目标

        使用Systic计时器实现精准延时,且不占用OS中断

        延时系统具有通用性,可适用多种系统频率

重点分析

        本程序流程如下:

                初始化其它相关硬件->获取HCLK时钟频率->用HCLK时钟频率初始化Systic计时器->其它操作实现延时

问题诊断

       刚开始测试的时候发现了一个问题,如下描述:

                由于该程序修改自正点原子的源码,源码中系统时钟是预先定义好的,使用起来没有问题,但这里系统频率是调用库函数实现的,虽然具有通用信,但却存在问题。

                库函数中获取时钟频率的函数RCC_GetClocksFreq正确使用有一个条件,就是外部时钟25MHz

                我们看一看该 函数的部分说明:

                        HSE_VALUE is a constant defined in stm32f4xx.h file (default value

                        25 MHz), user has to ensure that HSE_VALUE is same as the real
                      frequency of the crystal used. Otherwise, this function may

                      have wrong result.

                意思就是外部晶振不为25MHz时算出的频率会出错。

                表现在该工程中就是延时的时间是标准时间的三倍左右,即25/8

        那么如何解决这个问题?很简单

            stm32f4xx.h做以下修改

                源代码:
123行:   #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */

改为: 123行:   #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */

                这里是指默认的外部高速时钟25Mhz,实际为8MHz,这里为了使库函数获取的时钟更准确

        修改后,测试基本符合。

工程源码:

Delay.h

/**

  ******************************************************************************

  * @file    Delay.h

  * @author  李航兵

  * @version V1.2

  * @date    18-June-2018

  * @brief   这个头文件包含了STM32F407ZGT6开发板的延时相关的函数. 

  ******************************************************************************

  * @attention

  * 官方库文件里有参考代码

  * 为保证延时系统的精准,要求系统主频率越高越好

  * 为保证延时系统的完整支持,系统主频率至少8MHz

  * 使用CM4系统定时器,中断优先级最低

  *

  * @更新说明

  * 支持us、ms级延时,且精度大大提高

  * 支持OS,基本不影响OS的使用(下个版本添加)

  *

  ******************************************************************************

  */

 

/* Define to prevent recursive inclusion -------------------------------------*/

#ifndef __DELAY_H

#define __DELAY_H

 

 

/* Includes ------------------------------------------------------------------*/

#include "stm32f4xx_rcc.h"

#include "core_cm4.h"

#include "stm32f4xx_it.h"

#include "misc.h"

 

 

 

/* Exported types ------------------------------------------------------------*/

/* Exported constants --------------------------------------------------------*/

/* Exported macro ------------------------------------------------------------*/

/* Exported functions ------------------------------------------------------- */

 

void Delay_Init(void); //延时系统初始化

void Delay_Us(u16 us); //微秒延时

void Delay_Ms(u16 ms); //毫秒延时

void Delay_Us_2(u32 us); //微秒延时,范围更大

 

 

 

 

#endif /* __DELAY_H */

/************************ (C) COPYRIGHT 李航兵 *****END OF FILE****/

Led.h


/**

  ******************************************************************************

  * @file    Led.h

  * @author  李航兵

  * @version V1.0

  * @date    14-June-2018

  * @brief   这个头文件包含了STM32F407ZGT6开发板的Led相关的函数. 

  ******************************************************************************

  * @attention

  *硬件连接:

  * Led1:PC0-VCC

  * Led1:PD3-VCC

  *

  ******************************************************************************

  */

 

/* Define to prevent recursive inclusion -------------------------------------*/

#ifndef __LED_H

#define __LED_H

 

 

/* Includes ------------------------------------------------------------------*/

#include "stm32f4xx_gpio.h"

#include "stm32f4xx_rcc.h"

 

 

/* Exported types ------------------------------------------------------------*/

/* Exported constants --------------------------------------------------------*/

/* Exported macro ------------------------------------------------------------*/

/* Exported functions ------------------------------------------------------- */

 

 

void Led_Init(void);              //Led初始化

void Led_On(u8 led);           //开灯

void Led_Off(u8 led);           //关灯

 

 

#endif /* __LED_H */

/************************ (C) COPYRIGHT 李航兵 *****END OF FILE****/

Delay.c


/**

  ******************************************************************************

  * @file    Delay.c

  * @author  李航兵

  * @version V1.2

  * @date    18-June-2018

  * @brief   这个文件包含以下函数用于操作STM32F407ZGT6开发板的延时功能

  *           + 延时系统初始化

  *           + 微秒延时

  *           + 毫秒延时

  *

  *  @verbatim

  *

  *

    ===========================================================================

                         ##### How to use this driver #####

    ===========================================================================

      [..]

      (#) 初始化延时系统,调用Delay_Init()

      (#) 延时

         (++) 毫秒: Delay_Ms()

         (++) 微秒: Delay_Init()

    @endverbatim

  ******************************************************************************

  * @attention

  * 官方库文件里有参考代码

  * 为保证延时系统的精准,要求系统主频率越高越好

  * 为保证延时系统的完整支持,系统主频率至少8MHz

  * 使用CM4系统定时器,中断优先级最低

  * 使用此文件后,禁止再修改SysTick计时器及其设置

  *

  *

  *

  *

  *

  *

  *

© COPYRIGHT 2018 李航兵

  * @更新说明

  * 支持us、ms级延时,且精度大大提高

  * 支持OS,基本不影响OS的使用(下个版本添加)

  *

  *

  *

  *

  *

  *

  ******************************************************************************

  */

  

  /* Includes ------------------------------------------------------------------*/

#include "Delay.h"

 

 

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

 

 

u8 per_us; //每1us定时器节拍

u32 per_ms; //每1ms节拍,注意168MHz下值为168000,需要32位,移植自STM32F0,此处谨慎

 

 

 

/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/

 

 

/**

  * @brief  延时系统初始化.

  * @param  None.

  * @retval None

  */

void Delay_Init()

{

RCC_ClocksTypeDef RCC_Clocks;

RCC_GetClocksFreq(&RCC_Clocks);

//这里有个问题,本想自动化获取时钟频率的,不料在该函数中有如下声明

/*

HSE_VALUE is a constant defined in stm32f4xx.h file (default value

  *                25 MHz), user has to ensure that HSE_VALUE is same as the real

  *                frequency of the crystal used. Otherwise, this function may

  *                have wrong result.

*/

//也就是后来测试时发现延时总是为输入的3倍左右

//后修改了库文件,可参看对应目录的readme文件获取修改记录

if(SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000)) //1ms一次中断

while(1);

per_ms=SysTick->LOAD; //每1ms节拍,亦即重载值

per_us=per_ms/1000; //每1us定时器节拍

 

}

 

 

 

/**

  * @brief  微秒延时.

  * @param  延时的微秒数,约定范围1~390,“禁止其他值”.

  * @note   存在一定误差,主要是函数调用+部分计算.

  * @retval None

  */

void Delay_Us(u16 us) //微秒延时

{

u32 ticks_old=SysTick->VAL; //前一个计数值

u32 ticks_new; //后一个计数值

u16 ticks_sum=0; //已经经过的节拍

u16 ticks_delta=us*per_us; //需要经过的节拍

if(us>390) return; //计时不允许超过390us,超过390us请使用Delay_Us_2

while(1)

{

ticks_new=SysTick->VAL;

if(ticks_new!=ticks_old)

{

if(ticks_new

else ticks_sum+=per_ms-ticks_new+ticks_old;    

ticks_old=ticks_new;

if(ticks_sum>=ticks_delta)break; //时间超过/等于要延迟的时间,则退出.

}  

}

}

 

 

 

 

 

 

 

 

/**

  * @brief  毫秒延时.

  * @param  延时的毫秒数,约定范围1~25000,“禁止其他值”.

  * @note   存在一定误差,主要是函数调用+部分计算.

  * @retval None

  */

void Delay_Ms(u16 ms) //毫秒延时

{

u32 ticks_old=SysTick->VAL; //前一个计数值

u32 ticks_new; //后一个计数值

u32 ticks_sum=0; //已经经过的节拍

u32 ticks_delta=ms*per_ms; //需要经过的节拍

if(ms>25000) return; //计时不允许超过25000ms,超过25000ms请多次使用

while(1)

{

ticks_new=SysTick->VAL;

if(ticks_new!=ticks_old)

{

if(ticks_new

else ticks_sum+=per_ms-ticks_new+ticks_old;    

ticks_old=ticks_new;

if(ticks_sum>=ticks_delta)break; //时间超过/等于要延迟的时间,则退出.

}

}

}

 

 

 

 

/**

  * @brief  微秒延时,范围更大.

  * @param  延时的微秒数,约定范围1~25000000,“禁止其他值”.

  * @note   存在一定误差,主要是函数调用+部分计算.

  * @retval None

  */

void Delay_Us_2(u32 us) //微秒延时,范围更大

{

u32 ticks_old=SysTick->VAL; //前一个计数值

u32 ticks_new; //后一个计数值

u32 ticks_sum=0; //已经经过的节拍

u32 ticks_delta=us*per_us; //需要经过的节拍

if(us>25000000) return; //计时不允许超过25000000us

while(1)

{

ticks_new=SysTick->VAL;

if(ticks_new!=ticks_old)

{

if(ticks_new

else ticks_sum+=per_ms-ticks_new+ticks_old;    

ticks_old=ticks_new;

if(ticks_sum>=ticks_delta)break; //时间超过/等于要延迟的时间,则退出.

}  

}

}

 

 

 

/**

  * @brief  系统定时器中断.

  * @param  None.

  * @note   一般给OS用.

  * @retval None

  */

void SysTick_Handler(void) //系统定时器中断

{

}

 

 

Led.c


/**

  ******************************************************************************

  * @file    Led.c

  * @author  李航兵

  * @version V1.0

  * @date    14-June-2018

  * @brief   这个文档包含了Led功能相关的函数.

  ******************************************************************************

  * @brief   这个文件包含以下函数用于操作STM32F407ZGT6开发板的Led灯

  *           + 初始化Led

  *           + 开灯

  *           + 关灯

  *

  *  @verbatim

  *

  *

    ===========================================================================

                         ##### How to use this driver #####

    ===========================================================================

      [..]

      (#) 初始化Led,调用Led_Init()

      (#) 控制灯的亮灭

         (++) 开灯: Led_On

         (++) 关灯: Led_Off

    @endverbatim

  ******************************************************************************

  * @attention

  *

  *

© COPYRIGHT 2018 李航兵

  *硬件连接:

  * Led1:PC0-VCC

  * Led1:PD3-VCC

  *使用该文件后,PC0和PD3将会被占用

  *

  ******************************************************************************

  */

 

 

/* Includes ------------------------------------------------------------------*/

#include "Led.h"

 

 

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/

 

 

 

/**

  * @brief  Led初始化.

  * @note   PC0和PD3将会被占用

  * @note   调用此函数会开启GPIOC和启GPIOD时钟.    

  * @param  None

  * @retval None

  */

void Led_Init()              //Led初始化

{

    GPIO_InitTypeDef GPIO_Led;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);

GPIO_Led.GPIO_Mode=GPIO_Mode_OUT;

GPIO_Led.GPIO_OType=GPIO_OType_PP;

GPIO_Led.GPIO_Pin=GPIO_Pin_0;

GPIO_Led.GPIO_PuPd=GPIO_PuPd_NOPULL;

GPIO_Led.GPIO_Speed=GPIO_High_Speed;

GPIO_Init(GPIOC,&GPIO_Led);

GPIO_Led.GPIO_Pin=GPIO_Pin_3;

GPIO_Init(GPIOD,&GPIO_Led);

Led_Off(1);

Led_Off(2);

}

 

 

 

 

/**

  * @brief  开灯.

  * @note   

  * @param  led:Led的编号,可取1、2

  * @retval None

  */

void Led_On(u8 led)           //开灯

{

    switch(led)

    {

    case 1:

  GPIO_ResetBits(GPIOC,GPIO_Pin_0);

break;

    case 2:

  GPIO_ResetBits(GPIOD,GPIO_Pin_3);

break;

    }

}

 

 

 

/**

  * @brief  关灯.

  * @note   

  * @param  led:Led的编号,可取1、2

  * @retval None

  */

void Led_Off(u8 led)           //关灯

{

  switch(led)

    {

    case 1:

  GPIO_SetBits(GPIOC,GPIO_Pin_0);

break;

    case 2:

  GPIO_SetBits(GPIOD,GPIO_Pin_3);

break;

    }

}

 

 

/************************ (C) COPYRIGHT 李航兵 *****END OF FILE****/

Delay_Test.c


 

 

#include "Delay.h"

#include "Led.h"

 

 

 

 

 

 

 

 

 

 

 

 

void main()

{

int i;

Led_Init();

Delay_Init();

while(1)

{

Led_On(1);

for(i=0;i<1000;i++)

Delay_Us(300);

Led_Off(1);

Delay_Ms(1000);

Led_On(2);

Delay_Us_2(1000000);

Led_Off(2);

Delay_Ms(1000);

}

}

 

 

 

//void main()

//{

// int i;

// Led_Init();

// Delay_Init();

// while(1)

// {

// Led_Off(1);

// for(i=0;i<1000;i++)

// {

// Delay_Us(300);

// Delay_Us(300);

// Delay_Us(300);

// Delay_Us(100);

// }

// Led_On(1);

//

// for(i=0;i<1000;i++)

// {

// Delay_Us(300);

// Delay_Us(300);

// Delay_Us(300);

// Delay_Us(100);

// }

// }

//}

 

 

 

 

 

//void main()

//{

// int i;

// Led_Init();

// Delay_Init();

// while(1)

// {

// Led_Off(1);

// Delay_Ms(1000);

// Led_On(1);

//

// Delay_Ms(1000);

// }

//}

stm32f4xx.h

    这里修改的地方前面已经说明

结果分析


        经过测试,延时1s的时间基本准确



关键字:STM32F407ZGT6  Systic  定时器  延时 引用地址:STM32F407ZGT6使用Systic定时器实现延时

上一篇:STM32F072在8M下的软件延时
下一篇:STM32菜鸟之初始化函数以及延时函数

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

51单片机入门经验分享9-定时器模拟实现PWM呼吸灯效果
众所周知,PWM的应用是及其广泛的,现在很多高速的单片机内部都集成了硬件PWM,使用起来也很简单,配置好频率和装入计数值就可以工作了,但是在一些低成本的场合,我们选择的单片机没有硬件PWM功能模块,但是我们还存在这个需求怎么办呢?这个时候,我们需要用PWM来模拟实现他,但实现PWM必须要了解PWM的原理,这里我们先了解下。 PWM全称是脉冲宽度调制解调,比如1个小灯,按照500MS亮一次,500MS灭一次,周期是1S,频率是1HZ,在这里,1个周期说明白了就是2个方波,有高电平和低电平组成,在周期固定的情况下,我们通过不断的调整高电平所占的整个周期比例,即所谓的占空比,就可以实现小灯”不是那么亮“的效果,如果连续起来,就可以实
[单片机]
51单片机入门经验分享9-<font color='red'>定时器</font>模拟实现PWM呼吸灯效果
IAR FOR STM8精确延时函数
用的是IAR FOR STM8,有个项目想精确的知道下delay行数的延时时间是多少,上网搜了下竟然没有,而且发现好些人提问怎么又这样的函数,我就用示波器测量做了个精确延时函数,分享给各位朋友吧。(16M晶振)用的时钟启动函数是 void ClkInit(void) { CLK_ECKR |=0x1; //开启外部时钟 while(!(CLK_ECKR&0x2)); //等待外部时钟rdy CLK_CKDIVR &= 0xF8; //CPU无分频 16M CLK_SWR = 0xB4; //选择外部时钟 while(!(CLK_SWCR&0x8));
[单片机]
S3C2440 的定时器的设置
在前面的几篇文章中,每当程序需要延时时,我们是利用循环语句来实现。这种方法的延时简单,但不是很精确,就是说不能得到确切的一段时间的延时。因此当需要精确延时时,就不能采用这种方法了。一般是利用定时器来实现。在这里,我们就介绍一下s3c2440定时器的使用方法。 在讲解之前,先介绍一下s3c2440时钟系统。一般来说,MCU的主时钟源主要是外部晶振或外部时钟,而用的最多的是外部晶振。在正确情况下,系统内所使用的时钟都是外部时钟源经过一定的处理得到的。由于外部时钟源的频率一般不能满足系统所需要的高频条件,所以往往需要PLL(锁相环)进行倍频处理。在s3c2440中,有2个不同的PLL,一个是MPLL,另一个是UPLL。UPLL是给U
[单片机]
C语言使用定时器的方法控制LED灯以1S的速度闪亮
最近因为赶不上提高班的进度,老师给的教程总是断断续续的,所以我打算跟11月1号通过考试的网友们一起学习,呵呵,这也是我一教训来着,在三维里学习要坚持一步一个脚印,坚持必有奇迹,但也要跟得上大家,以后再忙也要努力实现计划了,不能再像这次一样,因为所谓的考试落下了好几堂课,不过也没有关系,能够吸取点教训总是好的。我可以先给自己点时间多学些其它的基础知识。 今天开始学单片机的计数器了,呵呵,可能是一直因为用C语言编程序我定时老是定不准的原因,当得知学会定时/计数器后可以让单片机C语言定时准确后,我感觉学它真的很有动力,虽然编一个简单的程序也花了我好长时间,但编出来的感觉却是那么的爽快,我觉得要学会定时/计数器,关键是要学会编程控制 TCO
[单片机]
51单片机内部定时器/计数器实验
一、实验内容 使用MCS-51内部定时/计数器,定时1秒钟,CPU运用定时中断方式,实现每1秒钟输出状态发生一次反转,即发光管每隔1秒钟亮一次(P1.7接LED)。 根据实验内容编写一个程序,并在实验仪器上调试和验证。 二、仿真图 三、代码 C语言实现: # include reg52.h # include intrins.h # define uint unsigned int # define uchar unsigned char sbit LED=P1^0; uchar t,temp; void init(); void main() { t=0; init(); whil
[单片机]
51单片机内部<font color='red'>定时器</font>/计数器实验
PIC16F877A初学之定时器中断篇
程序功能:让RC口的八个灯亮65MS灭65MS采用定时器0中断来完成 程序如下: tmr0 equ 01h pcl equ 02h status equ 03h option_reg equ 81h i NTC on equ 0bh portc equ 07h trisc equ 87h tmr0_b equ 0 w equ 0 f equ 1 rp0 equ 5 t0if equ 2 w_temp equ 7fh portc_b equ 23h flag equ 24h
[单片机]
MSP430G2553 WDT的定时器模式例子
#include MSP430G2553.h int main( void ) { WDTCTL = WDT_ADLY_1000; //定时周期为1000ms IE1 |= WDTIE; //使能WDT中断 P1DIR |= 0x01; // P1.0输出 _EINT(); //等同_EINT(), 系统总中断允许 while(1) //循环等待定时器溢出中断 { LPM3; //进入 LPM3 _NOP(); } } //===========看门狗中断服务子程
[单片机]
基础定时器实验
7.1 STM32定时器概述 STM32内部共有8个定时器,其中Timer1和Timer8属于高级定时器,Timer2~Timer5属于通用定时器,8个定时器的资源独立,互不影响。 STM32的通用定时器是一个通过可编程预分频器(PSC)驱动的16位自动装载计数器(CNT)构成。STM32的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32的每个通用定时器都是完全独立的,没有互相共享的任何资源。 通用定时器的内部结构如下图所示。 7.2 相关 寄存器 要使用通用定时器
[单片机]
基础<font color='red'>定时器</font>实验
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

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

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

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