STM32CubeMX学习笔记(4)——系统延时使用

发布者:TranquilDreams最新更新时间:2025-02-21 来源: jianshu关键字:STM32CubeMX  系统延时  SysTick 手机看文章 扫描二维码
随时随地手机看文章

一、SysTick简介

SysTick —系统定时器是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。系统定时器是一个 24bit 的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK 等于 72M。当重装载数值寄存器的值递减到 0 的时候,系统定时器就产生一次中断,以此循环往复。

因为 SysTick 是属于 CM3 内核的外设,所以所有基于 CM3 内核的单片机都具有这个系统定时器,使得软件在 CM3 单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。

二、新建工程

1. 打开 STM32CubeMX 软件,点击“新建工程”


2. 选择 MCU 和封装


3. 配置时钟
RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)


选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz
修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置


4. 配置调试模式
非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器
SYS 设置,选择 Debug 为 Serial Wire


5. 配置GPIO
GPIO 设置,在右边图中找到 LED 灯对应引脚,选择 GPIO_Output,输出低电平点亮,可以添加自定义标签



6. 生成代码
输入项目名和项目路径


选择应用的 IDE 开发环境 MDK-ARM V5


每个外设生成独立的 ’.c/.h’ 文件
不勾:所有初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。


点击 GENERATE CODE 生成代码

三、普通延时

3.1 修改main函数,实现流水灯

在 while() 循环中加入引脚输出置反函数 HAL_GPIO_TogglePin() 和延时函数 HAL_Delay()。

/**

  * @brief  The application entry point.

  * @retval int

  */

int main(void)

{

  /* USER CODE BEGIN 1 */


  /* USER CODE END 1 */


  /* MCU Configuration--------------------------------------------------------*/


  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

  HAL_Init();


  /* USER CODE BEGIN Init */


  /* USER CODE END Init */


  /* Configure the system clock */

  SystemClock_Config();


  /* USER CODE BEGIN SysInit */


  /* USER CODE END SysInit */


  /* Initialize all configured peripherals */

  MX_GPIO_Init();

  /* USER CODE BEGIN 2 */


  /* USER CODE END 2 */


  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

    /* USER CODE END WHILE */

    HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);

    HAL_Delay(500);

    HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);


    HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);

    HAL_Delay(500);

    HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);

    /* USER CODE BEGIN 3 */

  }

  /* USER CODE END 3 */

}

3.2 HAL库与标准库代码比较

STM32CubeMX 使用 HAL 库生成的代码:

/**

  * @brief  The application entry point.

  * @retval int

  */

int main(void)

{

  /* USER CODE BEGIN 1 */


  /* USER CODE END 1 */


  /* MCU Configuration--------------------------------------------------------*/


  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

  HAL_Init();


  /* USER CODE BEGIN Init */


  /* USER CODE END Init */


  /* Configure the system clock */

  SystemClock_Config();


  /* USER CODE BEGIN SysInit */


  /* USER CODE END SysInit */


  /* Initialize all configured peripherals */

  MX_GPIO_Init();

  /* USER CODE BEGIN 2 */


  /* USER CODE END 2 */


  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

    /* USER CODE END WHILE */

    HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);

    HAL_Delay(500);

    HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);


    HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);

    HAL_Delay(500);

    HAL_GPIO_TogglePin(LED_B_GPIO_Port,LED_B_Pin);

    /* USER CODE BEGIN 3 */

  }

  /* USER CODE END 3 */

}


HAL_StatusTypeDef HAL_Init(void)

{

  /* Configure Flash prefetch */

#if (PREFETCH_ENABLE != 0)

#if defined(STM32F101x6) || defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) ||

    defined(STM32F102x6) || defined(STM32F102xB) ||

    defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) ||

    defined(STM32F105xC) || defined(STM32F107xC)


  /* Prefetch buffer is not available on value line devices */

  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();

#endif

#endif /* PREFETCH_ENABLE */


  /* Set Interrupt Group Priority */

  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);


  /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */

  HAL_InitTick(TICK_INT_PRIORITY);


  /* Init the low level hardware */

  HAL_MspInit();


  /* Return function status */

  return HAL_OK;

}


__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)

{

  /* Configure the SysTick to have interrupt in 1ms time basis*/

  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)

  {

    return HAL_ERROR;

  }


  /* Configure the SysTick IRQ priority */

  if (TickPriority < (1UL << __NVIC_PRIO_BITS))

  {

    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);

    uwTickPrio = TickPriority;

  }

  else

  {

    return HAL_ERROR;

  }


  /* Return function status */

  return HAL_OK;

}


/**

  * @brief This function handles System tick timer.

  */

void SysTick_Handler(void)

{

  /* USER CODE BEGIN SysTick_IRQn 0 */


  /* USER CODE END SysTick_IRQn 0 */

  HAL_IncTick();

  /* USER CODE BEGIN SysTick_IRQn 1 */


  /* USER CODE END SysTick_IRQn 1 */

}


使用 STM32 标准库的代码:

/**

  * @brief  主函数

  * @param  无  

  * @retval 无

  */

int main(void)

{   

    /* LED 端口初始化 */

    LED_GPIO_Config();


    /* 配置SysTick 为10us中断一次 */

    SysTick_Init();


    for(;;)

    {


        LED1( ON ); 

        SysTick_Delay_Ms( 1000 );

        LED1( OFF );

      

        LED2( ON );

        SysTick_Delay_Ms( 1000 );

        LED2( OFF );

    }   

}


/**

  * @brief  启动系统滴答定时器 SysTick

  * @param  无

  * @retval 无

  */

void SysTick_Init(void)

{

    /* SystemFrequency / 1000    1ms中断一次

     * SystemFrequency / 100000  10us中断一次

     * SystemFrequency / 1000000 1us中断一次

     */

//  if (SysTick_Config(SystemFrequency / 100000))   // ST3.0.0库版本

    if (SysTick_Config(SystemCoreClock / 100000))   // ST3.5.0库版本

    { 

        /* Capture error */ 

        while (1);

    }

}


// couter 减1的时间 等于 1/systick_clk

// 当counter 从 reload 的值减小到0的时候,为一个循环,如果开启了中断则执行中断服务程序,

// 同时 CTRL 的 countflag 位会置1

// 这一个循环的时间为 reload * (1/systick_clk)


void SysTick_Delay_Us( __IO uint32_t us)

{

    uint32_t i;

    SysTick_Config(SystemCoreClock/1000000);

    

    for(i=0;i    {

        // 当计数器的值减小到0的时候,CRTL寄存器的位16会置1 

        while( !((SysTick->CTRL)&(1<<16)) );

    }

    // 关闭SysTick定时器

    SysTick->CTRL &=~SysTick_CTRL_ENABLE_Msk;

}


void SysTick_Delay_Ms( __IO uint32_t ms)

{

    uint32_t i; 

    SysTick_Config(SystemCoreClock/1000);

    

    for(i=0;i    {

        // 当计数器的值减小到0的时候,CRTL寄存器的位16会置1

        // 当置1时,读取该位会清0

        while( !((SysTick->CTRL)&(1<<16)) );

    }

    // 关闭SysTick定时器

    SysTick->CTRL &=~ SysTick_CTRL_ENABLE_Msk;

}


HAL_InitTick(TICK_INT_PRIORITY); 对应 SysTick_Init();
HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) 对应 SysTick_Config(SystemCoreClock/1000000)
HAL_Delay(500); 对应 SysTick_Delay_Ms(500);


四、中断中延时

在 STM32CubeMX学习笔记(3)——EXTI(外部中断)接口使用 的 HAL_GPIO_EXTI_Callback 中加入按键消抖

/* USER CODE BEGIN 1 */

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

    if(GPIO_Pin==KEY1_Pin)

    {

        HAL_Delay(100);

        if(HAL_GPIO_ReadPin(KEY1_Pin_Port,KEY1_Pin)==1)

        {

            HAL_GPIO_TogglePin(LED_G_GPIO_Port,LED_G_Pin);

        }

    }

}

/* USER CODE END 1 */


现在下载进单片机只会让它在按键按下后没有任何反应,这又是为什么呢,其实问题出在HAL_Delay() 上。


在进入回调函数之后就一直在 HAL_Delay 陷入了死循环中,原因是 Systick 优先级太低造成的。


Systick 中断的抢占优先级和外部中断的抢占优先级是一样的,那么在外部中断触发时肯定不能接着触发 Systick 中断了,问题已经找到,只需要简单地将外部中断的抢占优先级改低即可。

  • 抢占优先级,数字越小,优先级越高

  • 若抢占优先级相同,判断子优先级,同样,数字越小,优先级越高

五、注意事项

用户代码要加在 USER CODE BEGIN N 和 USER CODE END N 之间,否则下次使用 STM32CubeMX 重新生成代码后,会被删除。

关键字:STM32CubeMX  系统延时  SysTick 引用地址:STM32CubeMX学习笔记(4)——系统延时使用

上一篇:STM32CubeMX学习笔记(5)——基本定时器接口使用
下一篇:STM32CubeMX学习笔记(3)——EXTI(外部中断)接口使用

推荐阅读最新更新时间:2026-03-23 21:45

基于Systick系统时钟延时的LED闪烁灯
1、回顾我们的51 单片机编程,当我们需要做系统延迟的时候,最常采用的一 种方式就是使用for 循环的空语句等待来实现。 当然,在STM32 里面也可以这么实现。但是在STM32 的Cortex 内核里面,有个比其更加精准的定时器专业用于 系统定时,我们称之为Cortex 系统定时器(SysTick,系统滴答)。 Systick 就是一个定时器而已,只是它放在了NVIC(中断事件)中, 主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。 这样,只要设置好其中断的时间,就可以每隔一定时间跳入其处理程序, 通过这种方式,我们可以做一些分时的任务处理。 然而,由于我们刚刚接触STM32,因此我们
[单片机]
基于<font color='red'>Systick</font><font color='red'>系统</font>时钟<font color='red'>延时</font>的LED闪烁灯
基于stm32的精确延时利用系统滴答systick
利用系统滴答定时器来实现精确延时,需要以下五步: 1、设置滴答定时器的时钟,通过设置其控制寄存器,选择外部时钟,即为系统时钟的八分之一,若系统时钟为72M,则滴答定时器时钟为9M。即定时一秒需要9M个时钟周期。 2、设置滴答定时器的重装载寄存器的数值,即需要延时的时钟周期数。如:若需要延时20微秒,则重装载值为20*9.若要延时20毫秒,则设置重装载值为20*9000. 3、清空滴答定时器当前值寄存器的值,使之为零,以便使能计数时能够从设定值开始倒数计时。 4、设置滴答定时器的控制寄存器,开始倒计数。 5、查询滴答定时器的状态位,定时时间到,关闭定时器,清空定时器当前值。 void delay_init(u8 SYSC
[单片机]
STM32CubeMX自动生成SYSTICK配置
1.SYSTICK原理及其寄存器 1.1 SYSTICK原理 SysTick 是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值并继续计数,且同时触发中断。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。 SysTick 的最大使命,就是定期地产生异常请求,作为系统的时基,产生一个周期性的中断。 1.2SYSTICK寄存器   CTRL: Systick控制和状态寄存器   LOAD: Systick重装载寄存器   VAL: Systick当前值寄存器   CALIB: Systick校准值寄存器     CLKCOURCE-时钟源  
[单片机]
<font color='red'>STM32CubeMX</font>自动生成<font color='red'>SYSTICK</font>配置
STM32F0_SYSTICKSTM32CUBEMX中的设置
用过STM32CUBEMX的童鞋们都知道,代码生成的时候默认HAL_Delay延时单位为ms,当程序中要用到us延时的时候该怎么办呢! 最终评估下来,感觉原子的思路比较靠谱,不带OS的设计理念是搞清楚SYSTICK的RELOAD寄存器的数值代表什么,代码生成时默认为47999,也就是说 定时器从47999减1减到0的时候,时间过了1000us,换算后得出数值从47减到1的时候时间过了1us. void HAL_Delay_us(__IO uint32_t delay_us) { uint32_t first_value = 0; uint32_t current_value = 0;
[单片机]
STM32L151中RTC_WakeUpCmd()函数带来了系统延时
ErrorStatus RTC_WakeUpCmd(FunctionalState NewState) { __IO uint32_t wutcounter = 0x00; uint32_t wutwfstatus = 0x00; ErrorStatus status = ERROR; assert_param(IS_FUNCTIONAL_STATE(NewState)); RTC- WPR = 0xCA; RTC- WPR = 0x53; if (NewState != DISABLE) { RTC- CR |= (uint32_t)RTC_CR_WUTE; status = SUCCE
[单片机]
上电时实现延时系统复位的IC
通过给晶体管增加一些电容、二极管和电阻,使用保持时间可调的复位IC,将纯手动复位转换为自动复位。   在大多数应用中, (手动复位)引脚通常与开关相连,为管理芯片制造手动复位信号。随后,在预先设定的有效延时时间后,其从低电平有效复位回到高电平状态。手动复位适用于大多数应用;然而,它需要人为干涉产生复位信号。在一些应用中,手动复位存在争议,因为系统每次上电时都要执行。   更进一步,包括嵌入式处理器在内的应用需要复位输出为保持高电平——也就是说,非有效——在应用复位或低有效之前的某个时期。如图1电路在设备上电时无需按下复位键的情况下,被证实是有效的,因为在复位的低信号到来之前,复位自动以预先设定的保持时间发生。   电路使
[模拟电子]
上电时实现<font color='red'>延时</font><font color='red'>系统</font>复位的IC
小型单片机系统延时关机电路
    很多 电子 产品具有延时自动关机功能。下面介绍一个小型系统中的延时关机功能。 设计思路很简单.就是先按轻触 开关 给系统供电,系统上电正常工作后通过一个引脚 控制 一个电子 开关 ,代替轻触开关为系统供电,在 单片机 程序设计时定义一个变量,每次使用系统时清零该变量.没有使用系统时利用 单片机 的定时器自动累加此变量。到达一定值后该引脚输出翻转, 控制 电子开关关闭,系统自动断电。 相关 电路 如附图所示。系统采用 9V 电池 供电。所以要先用 7805 稳压。 Q1 为电子开关, Q2 及其周边元件为控制 电路 。 R1 和 R3 的阻值可以根据实际电路加以选择。电子开关受单片机的④脚控制。复位电路分为上电复位及按键复
[电源管理]
stm32的systick原理与应用
/* SysTick滴答定时器 一、功能 SysTick定时器是一个简单的定时器,CM3CM4内核芯片都具备此定时器。SysTick定时器常用来做延时,采用实时系统时则用来做系统时钟。无论用作延时还是用作系统心跳时钟,不需要太复杂的功能,SysTick即可胜任。 二、实现原理 SysTick定时器是一个24位的倒计数,当倒计数为0时,将从RELOAD寄存器中取值作为定时器的初始值,同时可以选择在这个时候产生中断(异常号:15)。 例如从RELOAD的值为999,那么当倒计数为0时,就会从复位为999继续倒计数。 只要不把它在SysTick控制及状态寄存器中的使能位清楚,就永不停息,即使在睡眠模式下也能继续工作。 三、Sys
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

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