HAL库STM32常用外设分享(四)—— 定时器 基本定时

STM32CubeMX学习--(2)定时器 定时器定时中断功能 定时器配置 在Timers中选中TIM6,勾选Activated。 设置参数: Prescaler = 83, 分频系数,计数频率 = APB1/psc。 Counter Mode = UP, Counter Period = 499,自动重装载值。 auto-reload preload = Enable, Trigger Event Selection = Reset。 ... 阅读详情
AI摘要

本文深入解析STM32F407的基础定时器(TIM6/TIM7)原理与HAL库应用,涵盖其16位计数结构、预分频与自动重载机制、影子寄存器行为、UEV更新事件及单次/连续定时模式;重点介绍HAL_TIM_Base_Start_IT等核心API、CubeMX配置要点(PSC/ARR/ARPE/OPM)、中断回调函数HAL_TIM_PeriodElapsedCallback实现,并通过LED翻转与按键消抖实例验证定时功能。

HAL库STM32常用外设教程(四)—— 定时器 基本定时



前言

1、STM32F407ZGT6
2、STM32CubeMx软件
3、keil5
内容简述:
通篇文章将涉及以下内容,如有错误,欢迎指出:
1、基础定时器特性
2、基础定时器的结构和功能
3、基础定时器HAL库驱动程序
(1)CubeMx配置
(2)TIM驱动程序


一、定时器特性概述

  STM32F407有2个高级控制定时器(TIM1、TIM8)、8个通用定时器和2个基本定时器。基本定时器功能比较简单,只能用于定时,通用定时器和高级定时器还具有输入捕获、输出比较、PWM输出等功能。
              表1-1 STM32F407所有定时器的特性

定时器类型定时器计数器长度计数类型DMA请求捕获/比较通道数所在总线
基本定时器TIM6、TIM7 16位 递增 有 0 APB1
通用定时器 TIM2、TIM5 32位 递增、递减、递减/递增 有 4 APB1
通用定时器TIM3、TIM416位 递增、递减、递减/递增有4 APB1
通用定时器TIM9 16位递增 无 2 APB2
通用定时器 TIM1216位 递增 无 2 APB1
通用定时器 TIM10、TIM11 16位 递增无 1 APB2
通用定时器 TIM13、TIM14 16位 递增无 1 APB1
高级定时器 TIM1、TIM8 16位 递增、递减、递减/递增 有 4 APB2

STM32F407还有一个独立看门狗(IWDG)和1个窗口看门狗(WWDG),看门狗实际上也是一个定时器。

二、基础定时器的结构和功能

1、基本特征

TIM6和TIM7两个基础定时器,都在APB1总线上,它们的功能相同,有以下基本特征。
(1)只能使用内部时钟信号CK_INT,这个时钟信号频率为APB1总线频率的2倍,所以这两个定时器输入时钟频率最高为84Mhz。
(2)只有16位自动重装载寄存器(auto-reload register),用于设计计数周期。
(3)有16位可编程预分频器,设置范围为0-65535,分频系数范围为1-65536.
(4)可以输出触发信号(TRGO),用于触发DAC的同步电路。
(5)只有一种事件引起中断或DMA请求,即计数器上溢时产生的更新中断(Updata Event,UEV)。

2、基础定时器相关寄存器

  基础定时器有3个十六位寄存器,计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR) ,这3个寄存器的值都可以读写,组成一个时基单元。基本定时器的这三个寄存器都是 16 位有效数字,即可设置值范围是 0~65535。其中,预分频寄存器和自动重装载寄存器有影子寄存器用于底层工作。
  (1)预分频寄存器(TIMx_PSC),它存储的一个值用于对输入时钟信号CK_PSC进行分频,得到输出时钟信号CK_CNT。实际分频系数是预分频寄存器的值加1。
  (2)计数寄存器(TIMx_CNT),计数器使用时钟信号CK_CNT进行计数,当计数器的值等于自动重装载寄存器的值时产生计数溢出(counter overflow),同时可以产生更新事件(UEV)中断或DMA请求。
  (3)自动重载寄存器(TIMx_ARR),存储的值用于与计数器的值进行比较。

在这里插入图片描述
图2-1 基础定时器功能结构图

3、基础定时器工作流程

  基础定时器只有定时功能,使用基础定时器进行定时的工作流程如下(可对照图2-1进行分析):
  (1)控制器除了控制定时器复位、使能、计数等功能之外,还可以用于触发 DAC 转换。
内部时钟信号CK_INT经过控制器后成为CK_PSC进入预分频器,CK_INT和CK_PSC在频率上相等,假设CK_INT频率为50MHz。
  (2)预分频器对CK_PSC时钟信号进行分频,输出 CK_CNT是分频后的时钟,它是计数器实际的计数时钟,通过设置预分频器寄存器(TIMx_PSC)的值可以得到不同频率 CK_CNT,假设预分频寄存器设置的值为49999,则实际分频系数为50000,那么分频器的输出时钟信号CK_CNT的频率就是

      50MHz /(49999 + 1) = 50 000 000 / 50 000 = 1000Hz
      定时器时钟频率  /(预分频寄存器的值+1)= 计数器频率

  另外:预分频器寄存器(TIMx_PSC)可以在运行过程中修改它的数值,新的预分频数值将在下一个更新事件时起作用。因为更新事件发生时,会把 TIMx_PSC 寄存器值更新到其影子寄存器中,这才会起作用。
什么是影子寄存器?
  ①从框图上看,可以看到图2-1中的预分频器PSC后面有一个影子,自动重载寄存器也有个影子,这就表示这些寄存器有影子寄存器。 影子寄存器是一个实际起作用的寄存器, 不可直接访问。举个例子:我们可以把预分频系数写入预分频器寄存器(TIMx_PSC),但是预分频器寄存器只是起到缓存数据的作用,只有等到更新事件发生时,预分频器寄存器的值才会被自动写入其影子寄存器中,这时才真正起作用。
  ②自动重载寄存器及其影子寄存器的作用和上述同理。不同点在于自动重载寄存器是否具有缓冲作用还受到 ARPE 位的控制,当该位置 0 时, ARR 寄存器不进行缓冲,我们写入新的 ARR值时,该值会马上被写入 ARR 影子寄存器中,从而直接生效;当该位置 1 时, ARR 寄存器进行缓冲,我们写入新的 ARR 值时,该值不会马上被写入 ARR 影子寄存器中,而是要等到更新事件发生才会被写入 ARR 影子寄存器,这时才生效。预分频器寄存器则没有这样相关的控制位,这就是它们不同点。值得注意的是,ARPE位对应下图2-2中CubeMx里面的auto-reload preload相对应,当ARPE位被设置为1时,auto-reload preload功能使能;当ARPE位被置零时,该功能禁用。
在这里插入图片描述                        图2-2 自动重装载值

  (3)计数器对时钟信号CK_CNT从0开始计数,自动重装载寄存器存储一个值,如999。当计数器的值达到999时(此时计时时间为1000ms)就产生UEV事件,然后计数器归零又重新开始计数。
  (4)开启定时器全局中断和UEV事件中断后,在发生计数溢出时产生UEV事件中断,利用中断进行定时处理。
  (5)定时器的控制器产生一些控制信号,例如,控制定时器的复位、使能等。

4、基础定时器时序图

  图2-3 是基础定时工作的时序图,其在TIMx_PSC红写入的预分频系数是2,所以后面基础器的时钟CK_CNT的频率是输入时钟CK_PSC的1/2,计数周期如果设置成FC,每来一个CK_CNT的脉冲,计数值加1,当计数值达到FC时,产生计数器上溢信号和UEV时间,如果开启了定时器UEV事件中断,在发生UEV事件时就会置位相应的中断挂起标志位。
再次强调,基础定时器TIM6和TIM7各有一个中断号,且只有一个中断事件源,就是定时器计数溢出的UEV事件。

在这里插入图片描述
                       图2-3 基础定时器工作时序图

三、基础定时器HAL驱动程序

1、基础定时器两种定时模式

  基础定时器只有定时这一个功能,根据控制寄存器TIMx_CR1中的OPM(One-pulse mode)位设置值不同,基础定时器有两种模式:连续定时模式和单次定时模式。
  (1)当 OPM位是0时,定时器是连续定时模式,也就是计数器在发生UEV事件时不停止计数。所以在连续定时模式下,可以产生连续的UEV事件,也就是产生连续、周期性的定时中断,这就是定时器默认的工作模式。
  (2)当OPM位是1时,定时器是单次定时模式,也就是计数器在发生下一次UEV事件时会停止计数。所以在单词定时模式下,如果启用了UEV时间中断,在产生一次定时中断后,定时器就停止计数了。
  图3-1 CubeMX中的One Pulse Mode(单次触发模式)对应于定时器控制寄存器(TIMx_CR1)中的OPM位。
在这里插入图片描述                           图3-1 单次触发模式

2、基础定时器主要函数

(1)定时器通用HAL库驱动函数

  表3-1 是基础定时器的一些主要的HAL驱动函数,所有定时器具有定时功能,所以这些函数对于通用定时器、高级定时器也是适用的。
                 表3-1 基础定时器的一些主要的HAL库驱动函数

分组函数名功能描述
初始化HAL_TIM_Base_Init()定时器初始化,设置各种参数和连续定时模式
初始化HAL_TIM_OnePulse_Init()将定时器配置为单次定时模式,需要先执行HAL_TIM_Base_Init()
初始化HAL_TIM_Base_MspInit()MSP弱函数,在HAL_TIM_Base_Init() 里面被调用,重新实现的这个函数一般用于时钟器时钟使能和中断设置
启动HAL_TIM_Base_Start()以轮训方式启动定时器,不会产生中断
停止HAL_TIM_Base_Stop()停止轮询工作方式的定时器
启动HAL_TIM_Base_Start_IT()以中断工作方式启动定时器,发生UEV事件时产生中断
停止HAL_TIM_Base_Stop_IT()停止中断工作方式的定时器
启动HAL_TIM_Base_Start_DMA()以DMA工作方式启动定时器
停止HAL_TIM_Base_Stop_DMA()停止DMA工作方式的定时器
获取状态HAL_TIM_Base_GetState()获取基础定时器的当前状态

(2)启动和停止定时器的三种方式

  • 轮询方式。以函数HAL_TIM_Base_Start()启动定时器后,定时器会开始计数,计数溢出会产生UEV事件标志,但是不会触发中断。用户程序需要不断的查询计数值或者UEV事件标志来判断是否发生了计数溢出。
  • 中断方式。以函数HAL_TIM_Base_Start_IT()启动定时器后,定时器会开始计数,计数溢出时会产生UEV事件,并触发中断。用户在中断服务例程(Interruput Service Routine,ISR,在stm32f4xx_it.c里面)里进行处理即可,这是定时器最常用的处理方式。
  • DMA方式。以函数HAL_TIM_Base_Start_DMA()启动定时器后,定时器会进行计数,计数溢出时会产生UEV事件,并产生DMA请求。DMA一般用于需要进行高速数据传输的场合,定时器一般用不着DMA功能。

3、定时器其他通用操作函数

文件stm32f4xx_hal_tim.h还定义了定时器操作的一些通用函数,这些函数都是宏定义,直接操作寄存器,所以主要用于在定时器运行时直接读取或者修改某些寄存器的值,如修改定时周期,重新设置预分频系数等,如表3-2所示。表中寄存器名称用了前缀“TIMx_”,其中“x”可以用具体的定时器编号替换,例如,TIMx_CR1表TIM6_CR1、TIM7_CR1或TIM9_CR1等。

函数名功能描述
HAL_TIM_ENABLE()启动某个定时器,就是将定时器控制寄存器TIMx_CR1的CEN位 置1
HAL_TIM_DISABLE()禁用某个定时器
HAL_TIM_GET_COUNTER()在运行时读取定时器的当前计数值,就是读取TIMx_CNT寄存器的值
HAL_TIM_SET_COUNTER()在运行时设置定时器的计数值,就是设置TIMx_CNT寄存器的值
HAL_TIM_GET_AUTORELOAD()在运行时读取自重载寄存器TIMx_ARR的值
HAL_TIM_SET_AUTORELOAD()在运行时设置自重载寄存器TIMx_ARR的值,并改变定时的周期
HAL_TIM_SET_PRESCALER()在运行时设置预分频系数,就是设置预分频寄存器TIMx_PSC的值

                    表3-2 定时器操作部分通用函数

注: HAL_TIM_GET_COUNTER()其返回值就是寄存器TIMx_CNT的值,有的定时器是32位的,有的定时器是16位的,实际使用时用uint32_t类型的变量来存储函数返回值即可。

4、定时器有关的中断处理

函数名功能描述
HAL_TIM_ENABLE_IT()启用某个定时器的中断,就是将中断使能寄存器TIMx_DIER中相应事件位置1
HAL_TIM_DISABLE_IT()禁用某个定时器的中断,就是将中断使能寄存器TIMx_DIER中相应事件位置0
HAL_TIM_GET_FLAG()判断某个中断事件源的中断挂起标志位是否被置位,就是读取状态寄存器TIMx_SR中相应的中断标志位是否置1,返回值为TURE或FALSE
HAL_TIM_CLEAR_FLAG()清除某个中断事件源的中断挂起标志位,就是将状态寄存器TIMx_SR中相应的中断事件位清零
HAL_TIM_CLEAR_IT()与HAL_TIM_CLEAR_FLAG()的代码和功能完全相同
HAL_TIM_GET_IT_SOURCE()查询是否允许某个中断事件源产生中断,就是检查中断使能寄存器TIMx_DIER中相应位置位是否置1,返回值为SET或RESET
HAL_TIM_IRQHandler()定时器中断的ISR里面调用的定时器中断通用处理函数
HAL_TIM_PeriodElapsedCallback()弱函数,UEV事件中断的回调函数。当定时器的计数器达到自动重装载值并重新开始计数时,会触发一个定时周期结束的事件。在HAL库中,可以通过编写HAL_TIM_PeriodElapsedCallback()函数来处理这个事件。

                    表3-3 定时器中断处理相关函数

每个定时器都只有一个中断号,也就是只有一个ISR。基础定时器只有一个中断事件源,即UEV事件,但是通用定时器和高级定时器有多个中断事件源。在定时器的HAL库驱动中,每一个中断事件对应一个回调函数,HAL驱动程序会自动判断中断事件源,清楚中断事件挂起标志,然后调用相应的回调函数。

四、 应用实例

  • TIM6设置为连续定时模式,定时周期为500ms,以中断方式启动TIM6,在UEV事件中断回调函数里面使LED1输出翻转。
  • TIM7设置为单次定时模式,定时周期为2000ms,按下KEY1(PE3引脚)键后使LED2点亮,并以中断方式启动TIM7,在UEV事件中断回调函数里使LED2输出翻转。
  • 按键需要进行消抖,此处用定时器2定时10ms去完成消抖工作。

1、CuebMx配置

在这里插入图片描述                  图4-1 定时器TIM6的模式和参数配置

(1)定时器TIM6的模式和参数设置结果如图4-1所示,在模式设置部分,勾选Activated复选框,已启动TIM6。启用后,会出现One Pulse Mode复选框,这是用于设置单脉冲模式的,对于基础定时器就是单次定时模式。TIM6工作于连续定时模式,不勾选此项。参数里面设置如下几个参数。

  • Prescalar,预分频器值,设置范围为0 ~ 65535,对应的分频系数为1 ~ 65536。这里设置为4200-1,所以实际分频系数是4200。
  • Counter Mode,计数模式,基础定时器只有递增模式(Up)。
  • Counter Period,计数周期,也就是自重载寄存器(AutoReload Register,ARR)的值,这里设置为10000-1,那么产生UEV事件时,共计时10000个时钟周期。
  • auto-reload preload,是否启用自动重装寄存器TIM6_ARR的预装载功能,实际上就是设置控制寄存器TIM6_CR1的ARPE位(上文有解释)。如果不是动态修改寄存器TIM6_ARR的值,这个设置对寄存器工作没什么影响。
  • Trigger Event Selection,主模式下触发输出信号(TRGO)信号源选择,就是设置寄存器TIM6_CR2的MMS[2:0]位。有3个选项:Reset,使用定时器的复位信号作为TRGO输出;Enable,使用计数器的是能信号作为TRGO输出;Updata Event,使用定时器的UEV事件作为TRGO输出。

(2)定时器7采用单次定时模式,定时周期为2000ms,其他参数与TIM6一样。TIM7的模式和参数设置结果如图4-2 所示,在模式设置部分勾选现One Pulse Mode复选框,使TIM7工作于单次定时模式。
在这里插入图片描述
                    图4-2 定时器TIM7的模式和参数配置

(3)定时器TIM2的模式和参数设置结果如图4-3所示,定时周期设置为10ms。
时钟源时钟频率 = 84MHZ
PSC 预分频器值 = 840-1
ARR自动自动重装载值 = 1000-1
定时器时钟频率 = 时钟源时钟频率 / [ (PSC+1)(ARR+1) ]
注:之所以要加1是因为计数从0开始的,不是从1开始计数的。
即 84000000 / [ (840-1 +1) x (1000-1 +1) ] = 84000000/[840*1000] = 100
计时周期 = 频率的倒数 = 0.01s =10 ms,即每10ms进入一次TIM2中断在这里插入图片描述
                    图4-3 定时器TIM2的模式和参数配置

(4)还需要开启TIM6、TIM7、TIM2的中断,在定时器配置界面的NVIC Setting页面里,可以开启定时器中断,但是不能设置中断优先级。TIM6、TIM7和TIM2的中断优先级需要在NVIC组件的配置界面设置,如图。两个定时器的抢占优先级都设置成1,其实设置成0也没有影响,因为本示例在定时器的ISR里不会直接或间接调用延时函数HAL_Delay()。
注:HAL_Delay()延时函数会用到Systick定时器中断,而这个中断的抢占优先级是0.如果某个外部中断的抢占优先级为0,执行外部中断的ISR时调用HAL_Delay(),则Systick中断无法抢占,函数HAL_Delay()的执行就会陷入死循环。如果将所有中断外部回调的抢占优先级设置为1或2,在外部中断的ISR里调用HAL_Delay()时,Systick中断就可以抢占外部中断,正常执行。

在这里插入图片描述                  图4-4 设置TIM6、TIM7、TIM2的中断优先级
(5)按键外部触发模式设置
  ①如图4-5,按键KEY1时外端接地,按键按下时,输入低电平,所以需要设置成下降沿外部触发中断(External lnterrupt Mode with Falling edge trigger detection),使用输入上拉(Pull-up)。
  ②按照图4-6的步骤 设置CubeMx里面的按键触发模式。
在这里插入图片描述
                         图4-5 按键原理图
在这里插入图片描述                     图4-6 按键 外部触发模式CubeMx设置

2、程序功能实现

(1)在定时器2的中断服务例程里面进行消抖,消抖成功即表明按键按下后开启定时器7,同时将定时器2关闭,为下一次按键按下做准备。
在这里插入图片描述

	static uint8_t key_ticks = 0;								    						/* 用于按键计数 */
	if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3) == GPIO_PIN_RESET){     						    /* 确认按键是否正常按下 */
			key_ticks++;																	/* 消抖 */
			if (key_ticks == 2){    														/* 20ms */        
				HAL_TIM_Base_Start_IT(&htim7);												/* 开启定时器7 */
				HAL_TIM_Base_Stop_IT(&htim2);												/* 及时关闭定时器2,已完成消抖任务 */
                key_ticks = 0;																/* 按键计数清零,为下一次按键触发做准备 */
		}
	}

(2)开启定时器6中断
在这里插入图片描述

	HAL_TIM_Base_Start_IT(&htim6); /* 开启定时器6定时中断 */

(3)
①重新定义外部触发中断回调函数,当按键按下时,触发中断,在中断里调用对应的回调函数,在回调函数里面开启定时器2。
②在文件stm32f4xx_it.c中,CubeMx自动生成了定时器TIM6和TIM7的应交中断ISR的代码框架,代码如下(该处系统已自动生成,张贴出来只为进行说明)

/**
  * @brief This function handles TIM6 global interrupt, DAC1 and DAC2 underrun error interrupts.
  */
void TIM6_DAC_IRQHandler(void)
{
  /* USER CODE BEGIN TIM6_DAC_IRQn 0 */

  /* USER CODE END TIM6_DAC_IRQn 0 */
  HAL_TIM_IRQHandler(&htim6);
  /* USER CODE BEGIN TIM6_DAC_IRQn 1 */

  /* USER CODE END TIM6_DAC_IRQn 1 */
}
/**
  * @brief This function handles TIM7 global interrupt.
  */
void TIM7_IRQHandler(void)
{
  /* USER CODE BEGIN TIM7_IRQn 0 */

  /* USER CODE END TIM7_IRQn 0 */
  HAL_TIM_IRQHandler(&htim7);
  /* USER CODE BEGIN TIM7_IRQn 1 */

  /* USER CODE END TIM7_IRQn 1 */
}

③这两个ISR都调用用了定时器中断通用处理函数 HAL_TIM_IRQHandler(),在这个通用处理函数里,程序会判断产生定时器硬件中断的事件源然后调用对应的会调函数进行处理。
④基础定时器的中断事件源只有一个,就是计数器溢出时产生的UEV事件,对应的回调函数是HAL_TIM_PerioElapsedCallback(),用户需要重新实现这个函数进行中断处理。为此,我们将定时器回调函数与HAL_GPIO_EXTI_Callback()函数 在mian.c中重新实现,代码如下:
在这里插入图片描述

	/**
 * @brief   外部触发中断(EXTI)的回调函数
 *          
 * @param
 * @return
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)  
{
	HAL_TIM_Base_Start_IT(&htim2);   /* 开启定时器2 */
}

/**
 * @brief   定时器(TIM)中断的回调函数
 *          
 * @param
 * @return
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM6){                   						/* 判断是否是定时器6 */
			HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10);    						/* 将灯的引脚电平进行翻转--PF10 */
	}
	if(htim->Instance == TIM7){																/* 判断是否是定时器7 */
			HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_9);									/* 将灯的引脚电平进行翻转--PF9 */
	}
}

中断响应的ISR是可重入的,事件中断响应的回调函数也可是重入的,计时TIM6和TIM7的中断同时发生,它们的中断响应代码也会被执行。

五、总结

本文主要讲解基础定时器的使用,其中还涉及了按键处理和点灯的操作。其中对CubeMx自动生成的代码部分(例如 定时器初始化)没有做过多的解释,但我们不应该忽视了这部分,应该熟悉基础定时器从配置到实现功能的整个流程。


项目源码:HAL库STM32常用外设分享(四)—— 定时器 基本定时

参考书籍:
《STM32Cube高效开发教程(基础篇)》王维波
《STM32F4xx中文参考手册》
《STM32F407 探索者开发指南》


只要今天比昨天好,这不就是希望吗?

-----------《士兵突击》

cubemx配置stm32(四)__STM32定时器中断TIMER cubemx配置stm32(四)__STM32定时器中断TIMER 1.建立工程并进行核心配置 根据文章2.使用cubemx配置stm32(二)__核心配置 进行如下配置: CubeMX新建工程 CubeMX图形配置调试时钟信号 CubeMX图形配置时钟树 CubeMX图形配置调试接口 (这里之前那个水星版的板子坏了,使用的是stm32F103c8核心板) 检查配置: 配置详解 1.配置TIM1 (1). 上图第三步中任意选择一个定时器 (2). Clock Source (时钟源):一般就直接选内部 阅读详情

相关推荐

尝试使用CubeMX做stm32开发之十一:Timers配置

参考《STM32中文参考手册_V10》,研究CubeMX中有关定时器(Timers)的配置。

Forster-C的博客 3538

STM32CubeMX----基本定时器(TIM6、TIM7)

激活TIM6,把前面的方框选中局表示激活了TIM6STM32F103定时器的One Pulse Mode是一种特殊的计数模式,它只产生一个脉冲输出信号,而不是周期性的信号输出。在这种模式下,计数器只进行一次计数,当计数器计数到预设的值时,就会产生一个脉冲信号,然后计数器会停止计数。这种模式通常用于需要生成单个脉冲信号的应用场景,例如PWM控制、测量脉冲宽度等。在STM32F103系列中,定时器的One Pulse Mode可以通过设置TIM_CR1寄存器中的OPM位来实现。计数设置。

m0_49968063的博客 8219

【春节歌曲回味 | STM32小音乐盒 】PWM+定时器驱动无源蜂鸣器(STM32 HAL库)

l STM32通过PWM与定时器方式控制无源蜂鸣器鸣响 l STM32小音乐盒,歌曲进度条图形显示与百分比显示,歌曲切换 l 编程使用STM32 HAL库 l IIC OLED界面编程,动画实现 PWM+TIME驱动无源蜂鸣器,最大的好处就是可以释放主循环,不让程序卡主去播放音乐,这类型操作系统的线程一样,音乐在后台播放,主循环可以随时切换或者关闭音乐或者其它功能操作 视频演示:https://www.bilibili.com/video/BV1M54y1Y72G 一、...

东小东博客 4795

stm32定时器级联 TIM级联 组成32位定时器

某些低成本版stm32芯片(比如F1系列)不具有32位计时器,自带的TIM均为16位。当你需要进行某些同时需要精度与时长的计时内容时,16位计时器并不够用(72M频率不分频直接计数,那么计满16位定时器只需要910us,如果是32位呢,需要59.6s,对于某些毫秒级高精度计时来说,使用32位定时器还是很有必要的。 甚至,你还可以继续级联,用3个计时器组成48位计时器,当然我只测试到了48位,只用到32位,更多级联有待测试。 测试效果: TIM1由72M系统时钟直接驱动,TIM2由TIM1计满产生的信号驱

fox0815的博客 8902

STM32F429第十九篇之基本定时器实验详解

前言 本次博客更新了HAL库的版本。以后的博客都会采用此HAL库版本。 HAL库版本: STM32Cube_FW_F4_V1.25.0 本篇博客主要介绍基本定时器中的源码解析,会涉及以下三个部分: 以整点原子定时器中断实验的程序为蓝本的程序解析 重点的结构体介绍 个人根据解析结果,最后分享自己的写的源代码 需要注意的是:本文介绍的源代码使用的并非基本定时器TIM6或者TIM7,而是通用定时器TIM3。但是,他们程序上是兼容的,只需将TIM3当做基本定时器即可。在最后的自我分享代码中,会严格的使用TI

我想想的博客 4577

【STM32 HAL库】定时器PWM精准驱动舵机角度控制

本文详细介绍了如何使用STM32 HAL库的定时器PWM功能精准控制舵机角度。通过解析PWM控制原理、CubeMX配置步骤及角度控制算法实现,为机器人项目和嵌入式开发提供实战指南,确保舵机驱动的高精度和稳定性。

pear55的博客 1156

HAL库STM32常用外分享(五)—— 定时器 输出比较

定时器输出比较模式

That_Assassin的博客 9657

STM32 HAL库学习系列第5篇 定时器TIM---编码器接口模式配置

学习交流加(可免费帮忙下载优快云资源): 个人微信:coderAllen 学习交流资源分享①群:736386324 cube基本配置,外设开启编码器,串口2 ------------------------------------------------------------------------------------------------------------...

CodeAllen嵌入式 4万+

HAL库STM32常用外设分享(一)—— 定时器 输出PWM

本篇文章为个人参考总结所用,如果错误还望指出。涉及的知识:1、STM32CubeMx的部分使用2、PWM原理及常用概念3、用单片机生成一定频率的PWM用到的软件及单片机:2、IDE: MDK-Keil软件3、芯片:STM32F407ZGT64、开发板:正点原子探索者注:不同型号的单片机实现的原理基本相似,F1实现过程同理(1)出现的问题CubeMxz生成的代码时钟频率是25MHZ,在此频率下观察到的方波如下:此时虽然可以生成PWM,但是生成的PWM频率和周期不正确。

That_Assassin的博客 1万+

PPL文档——Excel制作的甘特图加上动态今日线

当很多项目需要跟踪进度时,我们介绍一种在Excel中创建甘特图。

qq_34777858的博客 7063

AI编码的“黑箱危机”终结者:OpenSpec如何让你的代码从“猜谜”变“契约”?

OpenSpec的真正价值,在于它将AI编码从"经验驱动"推向"契约驱动"——当人类与AI对"目标是什么"达成显式共识,编码就从"猜谜游戏"变成了"工程实现"。这种转变不仅提升效率,更重塑了开发者与AI的关系:AI从"替代者"回归"协作者",而人类则聚焦于"定义正确的事"而非"正确地做事"。对于开发者,OpenSpec提供了驾驭AI的缰绳;对于团队,它构建了协作的基石;对于行业,它预示着AI编码工业化的开端。

haolove527的专栏 1347

【STM32】Hal库学习——PWM驱动电机

51我觉得我学得差不多了,虽然有一些通讯协议还没学,但是由于忙着团队的考核于是要开始弄四旋翼无人机,我打算用stm32的hal库来写。在此留下我的学习印记。 一。配置Hal库 这部分参考【STM32】HAL库 PWM控制电机转速与编码器读取(超详解)HAL库的学习 —— PWM的配置及控制 1.芯片选择 这里根据自己所用的芯片来进行选择,我用的是stm32f103c8t6 2.设置RCC(系统时钟) 设置高速外部时钟HSE 选择外部时钟源 3.串口配置 这里我配置的是USART1..

weever7的博客 3万+

螺丝锁付系统软件设计 C# Winform

视觉螺丝锁付系统软件设计 C# Winform ,这是其中通信子模块设计

weixin_42522973的博客 340

STM32CubeMX学习四 之定时器配置

讲解STM32CubeMX如何设置定时器,同时记录一下STM32CubeMX的学习笔记,同时分享给初学的小白,希望一起进步。

weixin_42648781的博客 1万+

基于Ollama本地大模型的Python自动化翻译工具开发实践

本文详细介绍了如何利用Ollama本地大模型和Python开发自动化批量翻译工具。通过部署本地开源模型、设计精准提示词、处理长文本分割及多种文档格式,构建了一个兼顾隐私安全、可控性与成本效益的翻译流水线,有效解决了文档批量翻译的痛点。

yhn45678901的博客 560

生信分析服务MR孟德尔随机化单细胞测序转录组数据分析网络药理学

通过上述技术整合,可实现从基因-环境-疾病关联到药物机制解析的全链条研究,为疾病机制解析和药物研发提供新思路。结合,是当前生物信息学领域的前沿方法,尤其在疾病机制解析、靶点发现和药物研发中展现出巨大潜力。

matlabgoodboy的博客 1519

STM32 HAL库 配置基本步骤

从51到32,感觉自己真是什么也不会,除了配置还是配置,感觉一直处于低水平,也不知道怎么突破,今天写一写HAL库吧,初学32的时候用的是标准库,现在尝试着用HAL库来写感觉刚开始很痛苦,有的你以为配置好了,其实并没有配置好,有的你以为配置了,其实并没有配置,很尴尬,慢慢的熟悉以后感觉还不错,单片机要学的这些概念,中断,定时器,ADC等等,我们只要找到和标准库的区别,需要加什么,配置什么,其实还是比...

Ti_tian_3的博客 1万+

【backtrader保姆级教学】投资组合回测

method1:探索投资组合的最有方案,使用蒙特卡洛模拟Markowitz模型。# 提取最小波动组合对应的权重, 并转换成Numpy数组。# 绘制收益-标准差的散点图,并用颜色描绘夏普比率。# 在收益-风险散点图中突出风险最小的点。:param any_day: 任意日期。# 将该点坐标显示在图中并保留四位小数。password = “替换密码”# 找到标准差最小数据的索引值。user = “替换账号”# 计算GMV投资组合收益。# 计算每项资产的夏普比率。# 设置无风险回报率为0。

weixin_38132951的博客 2314

【HAL库】STM32 Timer定时器开机立即进入中断问题

学习过程中发现配置号Timer定时器功能之后,原本应该定时到指定的时间再进入中断,结果MCU开机就会进入一次中断,不符合逻辑,所以尝试解决这个问题。 拜读各大佬的博客后发现没有HAL库的解决办法,于是转身向Google走去,找到了解决办法,分享给大家。 解决办法 在TIM初始化函数 HAL_TIM_Base_Init() 与 HAL_TIM_Base_Start_IT(); 之间...

2hi9uo的博客 7633

RK3568驱动 SPI主/从 配置

RK3568 SPI 配置指南 内核配置:启用用户空间驱动(主)和从模式协议支持。 主模式:设备树设置status="okay"、max-freq及引脚复用,子节点compatible="rockchip,spidev"。 从模式:需添加spi-slave属性,子节点命名以slave@X开头。 编译烧写:修改设备树后编译内核或全量镜像,验证/dev/spidevX.Y节点。 测试:使用spidev_test工具,主模式可环回测试,从模式需与主设备通信。 (关键:从模式强制spi-slave和命名规则,频率匹

文石_2009的博客 1142

焊缝缺陷智能检测:基于 YOLO 的工业质检系统实战

从焊缝缺陷数据集的构建到模型训练,从桌面检测界面到缺陷统计输出,本文覆盖了一套工业焊缝质检系统的完整路线。这个场景的核心难点在数据层面——气孔和裂纹这类小目标的标注质量直接决定了模型的最终表现。建议先在开源数据集上跑通全链路,确认 mAP 达到可接受的水平后,再通过补充特定类型的小目标数据和提升输入分辨率来做精度优化。工业场景中,漏检一个气孔的成本和误报一个假阳性的成本不一样——根据对两类成本的承受力,调整置信度阈值来找到业务上的最佳平衡点。

m0_71589036的博客 201

STM32 定时器从理论到实战:实现多任务并发

本文围绕 STM32“LED 定时闪烁 + 串口定时发送” 的多周期性任务需求,对比了硬件定时器中断与软件轮询两种核心实现方案,梳理了落地要点与选型逻辑。硬件定时器中断方案以 “高实时性” 为核心,通过 CubeMX 配置 TIM2/TIM3(1 秒中断周期)、使能 NVIC 中断并设置优先级,在回调函数中通过计数逻辑(TIM2 累计 2 次翻转 LED、TIM3 累计 5 次触发串口发送)实现任务并发。

m20050212的博客 2520

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

STM32CubeMX-HAL库开发笔记(常用语句)-基于Proteus仿真

STM32CubeMX-HAL库开发笔记 前言 使用Proteus 8可以仿真STM32F103系列T4、T6、C4、C6、R4、R6单片机,可以帮助项目前期少走一点弯路,学习者前期可以少花点钱去学习STM32。 使用STM32CubeMX配置基础工程的部分不做讲解,因为图形化真的很简单。本文章主要记录在配置工程后,HAL库函数的使用。 1、GPIO 读取IO: HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); HAL_GPIO_Read

weixin_43985745的博客 4533

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

彻底搞懂STM32定时器:PSC、ARR、CNT详解,附精确延时代码---STM32 HAL库专栏

本期博客从定时器的基础结构讲起,逐步深入到实际代码实现,帮助读者建立起完整的定时器应用知识体系,为后续学习PWM、输入捕获等高级功能打下坚实基础。

博主发布的博客主要分布在:​ 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》《linux裸机开发专栏》 《freertos专栏》《STM32 HAL库专栏》 《ROS开发专栏》 ​《产品测评专栏》《Ai智能体专栏》 1259

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

【转载】STM32 Timer定时器开机立即进入中断问题(HAL库)

细心的朋友会发现TIM_SR_UIF其实是SR(定时器状态寄存器)的最低位,初始化时若TIM_SR_UIF为1则SR也为1,若TIM_SR_UIF为0则SR也为0,因此存在另一种解决办法:将__HAL_TIM_CLEAR_FLAG(&htim7, TIM_SR_UIF);原因就是HAL库中定时器初始化后没有更新中断标志位,__HAL_TIM_CLEAR_FLAG(&htim7, TIM_SR_UIF)后清除了更新中断标志位,此时TIM_SR_UIF为0,中断产生后TIM_SR_UIF为1。

宁静致远的博客 3798

【STM32学习笔记】第二章:STM32的定时器中断配置

  第一章我给大家讲解了关于STM32最基本的GPIO知识,这一章我给大家讲接一下定时器的知识。   什么是定时器?,它是类似于秒表样的东西,它是一个单片机用来计时的工具。   什么是中断?,中断好比你在做一件事情突然被另外一件事情打断,然后去做另外一件事情。等另外一件事情做完了以后,又回来做之前做的事情。比如我在炒菜突然开水壶开了,那么我就去先把火关了以后再回来炒菜。   我们可以通过定时器中断...

Carry_王的博客 7211
上一篇: HAL库STM32常用外设分享(二)—— GPIO输入\输出
下一篇: HAL库STM32常用外分享(五)—— 定时器 输出比较
泰然码事
博客等级 码龄5年 427粉丝 15原创
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值