STM32单片机的延时原理和延时函数方法

发布时间:2023-09-05  

当涉及到单片机编程时,延时是一项常见但关键的任务。在许多应用中,我们需要控制程序暂停一段时间,以实现精确的时间控制或协调不同设备之间的操作。本文将以STM32为例,介绍关于单片机的延时原理以及常用的延时函数方法。


延时的原理

单片机的延时是通过控制处理器执行一系列指令来实现的。每条指令需要一定的时间来执行,而延时就是利用这些指令的执行时间来达到暂停程序执行的目的。延时的精确性和稳定性受到处理器的时钟频率、编译器优化等因素的影响。


延时方法


1. 软件延时

软件延时是最常见的延时方法之一,适用于大多数STM32单片机。基本思路是通过循环执行空操作或简单指令来消耗时间,从而实现延时。


#include "stm32f4xx.h"



void softwareDelay(uint32_t delay_ms) {

    uint32_t i, j;

    for(i = 0; i < delay_ms; i++) {

        for(j = 0; j < 1000; j++) {

            __NOP(); // 空操作,消耗时间

        }

    }

}


这种方法的缺点是延时时间精度不高,且不适用于需要较精确延时的场景。


2. 硬件定时器

STM32单片机内置了多个高精度的硬件定时器,可以精确地实现延时。通过配置定时器的参数,可以生成精确的时间间隔来进行延时。  


#include "stm32f4xx.h"

void timerDelay(uint32_t delay_ms) {

    // 配置定时器

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    TIM_TimeBaseInitTypeDef TIM_InitStruct;

    TIM_InitStruct.TIM_Prescaler = SystemCoreClock / 1000000 - 1; // 1us计数一次

    TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_InitStruct.TIM_Period = delay_ms * 1000; // 延时的微秒数

    TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;

    TIM_InitStruct.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM2, &TIM_InitStruct);



    // 启动定时器

    TIM_Cmd(TIM2, ENABLE);



    // 等待定时器计数完成

    while (TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) == RESET) {

    }



    // 清除标志位

    TIM_ClearFlag(TIM2, TIM_FLAG_Update);

}


硬件定时器方法具有高精度和稳定性,适用于需要精确时间控制的场景。


3. 阻塞延时与非阻塞延时

上述的软件延时和硬件定时器延时都是阻塞延时,即在延时期间,程序会一直等待,无法执行其他任务。如果需要同时处理其他任务,可以采用非阻塞延时,结合中断或操作系统的任务调度来实现。  


#include "stm32f4xx.h"



volatile uint32_t millisecond = 0;



void SysTick_Handler(void) {

    millisecond++; // SysTick中断每毫秒触发一次

}



void nonBlockingDelay(uint32_t delay_ms) {

    uint32_t start = millisecond;

    while (millisecond - start < delay_ms) {

        // 等待延时结束,期间可以处理其他任务

    }

}


在上述代码中,我们使用了STM32的SysTick定时器,每毫秒触发一次中断。通过记录开始时间和当前时间的差值,可以实现非阻塞的延时效果。


延时函数的设计


为了方便使用延时,我们可以封装一个延时函数,根据不同的延时方法选择合适的实现。


#include "stm32f4xx.h"


void delay(uint32_t delay_ms) {

    // 根据选择的延时方法调用对应的函数

    // 如:softwareDelay(delay_ms);

    // 或:timerDelay(delay_ms);

    // 或:nonBlockingDelay(delay_ms);

}


通过封装延时函数,我们可以根据需要灵活地选择合 适的延时方法,并在不同的场景中使用。这样的设计使得单片机程序的开发更加方便和可维护。


阻塞延时与非阻塞延时的选择

在实际应用中,选择阻塞延时还是非阻塞延时取决于你的项目需求。阻塞延时在简单的应用中使用较为普遍,因为它易于实现和理解。但是,如果你的应用需要同时处理多个任务或需要更高的性能,非阻塞延时可能更为适合。非阻塞延时能够让处理器在延时期间继续执行其他任务,提高了系统的并发性能。


示例代码


下面是一个使用STM32的SysTick定时器实现非阻塞延时的示例代码:  

#include "stm32f4xx.h"


volatile uint32_t millisecond = 0;



void SysTick_Handler(void) {

    millisecond++; // SysTick中断每毫秒触发一次

}



void nonBlockingDelay(uint32_t delay_ms) {

    uint32_t start = millisecond;

    while (millisecond - start < delay_ms) {

        // 等待延时结束,期间可以处理其他任务

    }

}



int main(void) {

    // 初始化SysTick定时器

    SystemCoreClockUpdate();

    SysTick_Config(SystemCoreClock / 1000); // 配置成每毫秒触发一次中断



    // 初始化其他硬件和外设



    while (1) {

        // 执行主要任务



        // 进行非阻塞延时

        nonBlockingDelay(1000); // 延时1秒

    }

}


在上述代码中,我们首先初始化了SysTick定时器,使其每毫秒触发一次中断。然后,在主循环中,我们通过调用nonBlockingDelay函数来实现非阻塞延时。该函数会记录开始时间并不断检查当前时间与开始时间的差值,直到达到设定的延时时间为止。这期间,程序可以继续执行其他任务。


总结

在STM32单片机编程中,实现延时是一项常见但重要的任务。通过软件延时、硬件定时器以及非阻塞延时等方法,可以根据项目需求选择合适的延时方案。阻塞延时适用于简单的应用场景,而非阻塞延时能够提高系统并发性能。通过封装延时函数,你可以在项目开发中灵活选择延时方法,并根据需求进行调整,从而实现精确的时间控制和任务调度。

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>