STM32的HAL库开发---高级定时器

news/2025/2/8 23:00:57 标签: stm32, 嵌入式硬件, 单片机

一、高级定时器简介

1、STM32F103有两个高级定时器,分别是TIM1和TIM8。

2、主要特性

  • 16位递增、递减、中心对齐计数器(计数值:0~65535)
  • 16位预分频器(分频系数:1~65536)
  • 可用于触发DAC、ADC
  • 在更新事件、触发事件、输入捕获、输出比较时,会产生中断/DMA请求4个独立通道,可用于:输入捕获、输出比较、输出PWM、单脉冲模式使用外部信号控制定时器且可实现多个定时器互连的同步电路支持编码器和霍尔传感器电路等
  • 重复计数器
    死区时间带可编程的互补输出
  • 断路输入,用于将定时器的输出信号置于用户可选的安全配置中

3、高级定时器框图

高级定时器的时钟源部分跟通用定时器是一样的,主要区别在重复计数器、互补输出部分、刹车输入。

 重复计数器:通用定时器在计数器溢出的时候,就会产生更新事件和更新中断。而高级定时器多了重复计数器,计数器溢出后,需要经过重复计数器才会产生更新事件或者更新中断。首先往RCR寄存器里边写入值REP,每当计数器值溢出的时候,重复计数器的值就减一,当重复计数器的值递减到0的时候,再次溢出就会产生更新事件或者更新中断。

互补输出部分:通用定时器只有CH1、CH2、CH3、CH4,而高级定时器除了这些通道以外,还有CH1N、CH2N、CH3N三个互补通道。通道4是没有互补通道的,DTG是用于设置死区时间的。

刹车输入:TIMx_BKIN引脚,信号BRK进来以后,首先经过一个极性选择,看是高电平有效还是低电平有效。经过一个或门,产生刹车中断(BI)。或门信号还可以来自时钟安全系统CSS。

二、高级定时器输出指定个数PWM实验原理

1、重复计数器特性

计数器每次上溢或下溢都能使重复计数器减1,减到0时,再发生一次溢出就会产生更新事件

当TIMx_RCR寄存器的值设置为0的时候,没,每当计数器溢出时,由于 重复计数器的值已经是0了,所以每次计数器溢出时,都会产生更新事件。

当TIMx_RCR寄存器的值设置为3的时候,当计数器的值溢出三次后,重复计数器的值递减到0了,当计数器的值再次溢出时,则产生更新事件。

再同步:由于RCR重复计数寄存器的存在影子寄存器,实际起作用的是影子寄存器,当软件产生更新事件以后,RCR寄存器里边的值会转移到影子寄存器里边,比如当影子寄存器里边已经递减到1了,软件更新事件产生后,影子寄存器的值会恢复为3,因此需要计数器再溢出4次才能产生更新事件或者更新中断。有点像影子寄存器复位的意思。

如果设置RCR为N,更新事件将在N+1次溢出时发生。

2、实验原理

  • 配置边沿对齐模式输出PWM
  • 指定输出N个PWM,则把N-1写入RCR
  • 在更新中断内,关闭计数器

注意:高级定时器通道输出必须把MOE位置1

三、高级定时器输出指定个数PWM实验配置步骤

1、HAL_TIM_PWM_Init()函数,配置定时器基础工作参数。这个函数与HAL_TIM_Base_init()函数功能是一样的。

2、HAL_TIM_PWM_MspInit(),配置NVIC、CLOCK、GPIO等。

3、HAL_TIM_PWM _Configchannel()函数,配置PWM模式/比较值。‘

4、HAL NVIC SetPriority()、HAL_NVIC_EnablelRQ()函数,设置优先级,使能中断

5、HAL_TIM_PWM _Start()函数,使能输出、主输出、启动计数器。

6、__HAL TIM ENABLE IT()宏定义,使能定时器更新中断

7、TIMx_IROHandler()等>HAL_TIM_IROHandler()函数,编写中断服务函数

8、HAL_TIM_PeriodElapsedCallback()函数,编写更新中断回调函数

四、高级定时器输出指定个数PWM实验配置步骤 

实验:通过定时器1通道1实现指定个数PWM输出,用于控制LED1的亮灭

PWM.h头文件程序

#ifndef __PWM_H
#define __PWM_H

#include "stm32f1xx.h"
void PWM_Init(void);
#endif

PWM.c源程序

#include "./BSP/TIMER/PWM.h"

TIM_HandleTypeDef htim;
void PWM_Init(void)
{
	htim.Instance = TIM1;
	
	htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
	htim.Init.CounterMode = TIM_COUNTERMODE_UP;
	htim.Init.Period = 72000000/20000 - 1;
	htim.Init.Prescaler = 9999;
	//设置重复计数器值
	htim.Init.RepetitionCounter = 9;
	
	HAL_TIM_PWM_Init(&htim);
		
	TIM_OC_InitTypeDef sConfig = {0};
	sConfig.OCMode = TIM_OCMODE_PWM1;
	sConfig.OCPolarity =TIM_OCPOLARITY_HIGH;
	sConfig.Pulse = 0.5 * (TIM1->ARR + 1);
	
	//设置PWM输出通道
	HAL_TIM_PWM_ConfigChannel(&htim,&sConfig,TIM_CHANNEL_1);
	
	//使能更新中断
	__HAL_TIM_ENABLE_IT(&htim, TIM_IT_UPDATE);
	
	///使能主输出和定时器
	HAL_TIM_PWM_Start(&htim,TIM_CHANNEL_1);
}

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM1)
	{
		//开启定时器1时钟
		__HAL_RCC_TIM1_CLK_ENABLE();
		
		//开启GPIOA时钟
		__HAL_RCC_GPIOA_CLK_ENABLE();
		
		GPIO_InitTypeDef GPIO_Init;
		
		GPIO_Init.Mode = GPIO_MODE_AF_PP;
		GPIO_Init.Pin = GPIO_PIN_8;
		//上下拉只有输入有用
		GPIO_Init.Pull = GPIO_NOPULL;
		GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;
		
		//设置PA8为复用推挽输出
		HAL_GPIO_Init(GPIOA, &GPIO_Init);
		
		HAL_NVIC_SetPriority(TIM1_UP_IRQn, 2, 2);
		HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
	}
}

void TIM1_UP_IRQHandler(void)
{
	HAL_TIM_IRQHandler(&htim);
	
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM1)
	{
		//关闭计数器
		TIM1->CR1 &= ~(1 << 0);
		
		//这个函数里边判断了输出通道和输出互补通道是否已经关闭了
		//没关闭 不可以关闭计数器
		//__HAL_TIM_DISABLE(htim);
	}
}

注意: __HAL_TIM_DISABLE(htim);宏定义的使用在程序里说明了

main.c主函数程序

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/PWM.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
	sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    //led_Init();                         /* LED初始化 */
	PWM_Init();
    while(1)
    { 
//		LED0(1);
//		LED1(0);
//		delay_ms(500);
//		
//		LED0(0);
//		LED1(1);
		delay_ms(500);
    }
}


http://www.niftyadmin.cn/n/5845365.html

相关文章

IDEA+DeepSeek让Java开发起飞

1.获取DeepSeek秘钥 登录DeepSeek官网 : https://www.deepseek.com/ 进入API开放平台&#xff0c;第一次需要注册一个账号 进去之后需要创建一个API KEY&#xff0c;然后把APIkey记录保存下来 接着我们获取DeepSeek的API对话接口地址&#xff0c;点击左边的&#xff1a;接口…

Ubuntu 20.04配置网络

1&#xff0c;检查自己网络是否配通。 网络配置成功显示的网络图标 不成功的网络图标 如果看不见网络图标&#xff0c;可以使用ping命令。连接一下百度网。 ping www.baidu.com ping失败的样子 ping成功的样子 2&#xff0c;接下来进入正题&#xff0c;我们开始配置网络。 这…

Android Studio 2024.2.2.13版本安装配置详细教程

Android Studio 是由 Google 官方开发和维护的集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为 Android 应用开发设计。它是基于 JetBrains 的 IntelliJ IDEA 平台构建的&#xff0c;集成了丰富的工具和功能&#xff0c;帮助开发者高效构建、调试、测试和发布 Androi…

【Day33 LeetCode】动态规划DP Ⅵ 背包问题

一、动态规划DP Ⅵ 背包问题 1、零钱兑换 322 本质是完全背包问题&#xff0c;以最终的金额数amount为背包容量&#xff0c;不同面额的硬币为物品&#xff0c;物品数量无数&#xff0c;求装满物品需要的最少物品数。直接套用完全背包模板。由于求最少物品数是在 装满物品的方…

数据库系统架构与DBMS功能探微:现代信息时代数据管理的关键

欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭&#xff5e; ??? 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua&#xff0c;在这里我会分享我的知识和经验。?? 希望在这里&#xff0c;我们能一起探…

《Kettle实操案例一(全量/增量更新与邮件发送)》

目录 一、场景描述:二、要求:三、思路四、整体作业五、各部分详细配置1、Start2、转换-获取执行开始时间3、获取目标表抽取前行数4、检验字段的值5、增量更新6、全量更新7、获取目标表抽取后行数8、获取执行结束时间9、日志写入数据库10、写日志11、发送数据抽取完成邮件 六、最…

c语言:取绝对值

假设我们有一个 long 类型的变量 l&#xff0c;我们希望恢复其绝对值。以下是两种方法的对比&#xff1a; 方法1&#xff1a;使用条件语句 这个很好理解&#xff0c;负数时取负运算 &#xff0c;用于数值的符号反转。 long abs_value(long l) {if (l < 0) {return -l;} e…

储能系统-系统架构

已更新系列文章包括104、61850、modbus 、单片机等&#xff0c;欢迎关注 IEC61850实现方案和测试-1-CSDN博客 快速了解104协议-CSDN博客 104调试工具2_104协议调试工具-CSDN博客 1 电池储能系统&#xff08;BESS&#xff09; 架构 电池储能系统主要包括、电池、pcs、本地控制…