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

   日期:2021-01-14     浏览:142    评论:0    
核心提示:一、SysTick简介SysTick —系统定时器是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。系统定时器是一个 24bit 的向下递减的计数器,计数器每计数一次的时间为 1/SYSCLK,一般我们设置系统时钟 SYSCLK 等于 72M。当重装载数值寄存器的值递减到 0 的时候,系统定时器就产生一次中断,以此循环往复。因为 SysTick 是属于 CM3 内核的外设,所以所有基于 CM3 内核的单片机都具有这个系统定时器,使得软件在 CM3 单片机中可以很容易的移植。系统定时器一般用于操作

一、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

点击 GENERATE CODE 生成代码

三、普通延时

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

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


int main(void)
{ 
  

  

  

  
  HAL_Init();

  

  

  
  SystemClock_Config();

  

  

  
  MX_GPIO_Init();
  

  

  
  
  while (1)
  { 
    
    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);
    
  }
  
}

3.2 HAL库与标准库代码比较

STM32CubeMX 使用 HAL 库生成的代码:


int main(void)
{ 
  

  

  

  
  HAL_Init();

  

  

  
  SystemClock_Config();

  

  

  
  MX_GPIO_Init();
  

  

  
  
  while (1)
  { 
    
    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);
    
  }
  
}

HAL_StatusTypeDef HAL_Init(void)
{ 
  
#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)

  
  __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif
#endif 

  
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

  
  HAL_InitTick(TICK_INT_PRIORITY);

  
  HAL_MspInit();

  
  return HAL_OK;
}

__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{ 
  
  if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  { 
    return HAL_ERROR;
  }

  
  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  { 
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  { 
    return HAL_ERROR;
  }

  
  return HAL_OK;
}


void SysTick_Handler(void)
{ 
  

  
  HAL_IncTick();
  

  
}

使用 STM32 标准库的代码:


int main(void)
{ 	
	
	LED_GPIO_Config();

	
	SysTick_Init();

	for(;;)
	{ 

		LED1( ON ); 
		SysTick_Delay_Ms( 1000 );
		LED1( OFF );
	  
		LED2( ON );
		SysTick_Delay_Ms( 1000 );
		LED2( OFF );
	} 	
}


void SysTick_Init(void)
{ 
	
// if (SysTick_Config(SystemFrequency / 100000)) // ST3.0.0库版本
	if (SysTick_Config(SystemCoreClock / 100000))	// ST3.5.0库版本
	{  
		 
		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<us;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<ms;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);

四、中断中延时

在 ESP8266学习笔记(3)——GPIO接口使用 的 HAL_GPIO_EXTI_Callback 中加入按键消抖


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);
        }
	}
}

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

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

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

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

五、注意事项

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

• 由 Leung 写于 2021 年 1 月 13 日

• 参考:《嵌入式-STM32开发指南》第二部分 基础篇 - 第2章 Systick系统定时器(HAL库)
    STM32CubeMX实战教程(三)——外部中断(中断及HAL_Delay函数避坑)

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服