STM32定时器&PWM应用编程

前言
实验前言:
本实验旨在深入了解STM32定时器的工作原理,并掌握使用定时器生成脉宽调制(PWM)信号的方法。STM32定时器是一种非常重要的外设,可用于实现定时、计数、捕获、比较和PWM等功能。
在本实验中,我们将使用STM32开发板和相关的开发环境,通过编程配置定时器和PWM输出,实现对LED灯的亮度控制。具体步骤如下:

首先,了解STM32定时器的基本概念和工作原理。定时器通常由一个或多个计数器、预分频器和控制寄存器组成。通过配置这些寄存器,我们可以实现不同的定时和计数功能。
掌握定时器的初始化和配置方法。在STM32开发环境中,我们可以使用相应的库函数和寄存器操作来初始化和配置定时器。例如,可以设置定时器的工作模式、预分频系数、计数周期等。
学习脉宽调制(PWM)的原理和应用。PWM是一种通过调整信号的脉冲宽度来控制电平平均值的技术。通过配置定时器的占空比,我们可以实现对输出信号的精确控制。
编写代码实现定时器的初始化和配置。根据实验要求,我们可以使用STM32提供的库函数或者直接操作寄存器来配置定时器。具体的代码编写过程需要参考相关的开发文档和示例代码。
配置PWM输出并进行实验验证。通过设置定时器的占空比,我们可以控制LED灯的亮度。在实验过程中,我们可以通过改变占空比的值来观察LED灯的亮度变化,从而验证PWM的应用效果。
通过完成本实验,读者能够更深入地理解STM32定时器的工作原理,并掌握使用定时器生成脉宽调制信号的方法。这将为后续的项目开发和应用提供良好的基础。

STM32定时器介绍
STM32定时器是一种重要的外设,可用于实现定时、计数、捕获、比较和脉宽调制(PWM)等功能。它由一个或多个计数器、预分频器和控制寄存器组成,通过配置这些寄存器来实现不同的定时和计数功能。
在这里插入图片描述
定时器类型
在STM32系列微控制器中,定时器分为两种类型:基本定时器和通用定时器。
在这里插入图片描述
基本定时器
基本定时器是一个简单的定时器,通常用于生成精确的时间延迟。它具有单个16位计数器,可以通过设置预分频系数实现不同的计数速度。基本定时器通常用于简单的定时任务。

通用定时器
通用定时器是一种更为复杂和功能强大的定时器,通常用于更复杂的定时和计数任务。STM32系列微控制器通常配备了多个通用定时器,如TIM1、TIM2等。通用定时器具有多个16位或32位计数器,可以通过设置预分频系数和计数周期来实现不同的计数速度和定时精度。

定时器应用
STM32定时器广泛应用于各种领域,包括工业控制、通信、嵌入式系统等。以下是一些常见的定时器应用场景:

定时中断:可以使用定时器生成周期性的中断信号,用于定时任务的触发和处理。
计时测量:可以使用定时器进行时间的测量和计算,如测量脉冲宽度、测量信号的频率等。
PWM输出:可以使用定时器生成精确的脉宽调制信号,用于控制电机速度、LED亮度等。
输入捕获:可以使用定时器进行外部信号的捕获,用于测量外部事件的时间戳。
定时器配置
为了配置和控制STM32定时器,我们可以使用相应的库函数或直接操作寄存器。以下是一些常用的配置参数:

预分频系数:用于设置定时器的计数速度,可以根据需要进行调整。
计数周期:用于设置定时器的计数周期,决定定时器溢出的时间间隔。
工作模式:定时器可以工作在不同的模式下,如定时器模式、计数器模式、PWM模式等。
中断使能:可以选择是否使能定时器的中断功能,用于触发中断任务。
定时器的数学公式
在定时器的配置和应用过程中,我们可以使用一些数学公式来计算和调整定时器的参数。以下是一些常用的数学公式:

计数频率:计数频率 = 主时钟频率 / (预分频系数 * 计数周期)
PWM占空比:PWM占空比 = (比较值 / 计数周期) * 100%
在这里插入图片描述
STM32-PWM介绍
STM32-PWM是STM32系列微控制器上的一种重要外设,用于生成脉宽调制(PWM)信号。脉宽调制技术在许多应用中都起着关键作用,如电机控制、LED亮度调节、音频处理等。STM32PWM模块提供了灵活的配置选项和高精度的PWM输出能力。

PWM工作原理
PWM是一种周期性的方波信号,通过调整方波的高电平时间(占空比)来控制输出信号的特性。PWM信号的频率和占空比可以根据应用需求进行配置。在STM32PWM模块中,通过设置定时器的计数周期和比较值,可以实现不同频率和占空比的PWM输出。
在这里插入图片描述
PWM比较
下表列出了STM32系列微控制器中一些常用定时器的PWM功能比较:

在这里插入图片描述
以上是一些常用的STM32定时器的PWM功能比较。根据实际需求,选择合适的定时器来实现所需的PWM功能。
示例程序
定时器的应用
实验要求
使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。
在这里插入图片描述
代码
led.c

#include "led.h"

void LED_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void LED_Toggle(void)
{
	GPIOB->ODR ^= GPIO_Pin_0;
}



led.h

#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"

void LED_Config(void);
void LED_Toggle(void);

#endif



tim_timebase.c

#include "tim_timebase.h"
#include "led.h"

int a = 0;

static void NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStruct;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitStruct.NVIC_IRQChannel=TIM3_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct);
}

void TIM3_Config(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	
	NVIC_Config();
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	
	TIM_TimeBaseInitStruct.TIM_Period=71;
	TIM_TimeBaseInitStruct.TIM_Prescaler=1000;//1ms
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
	
	TIM_ClearFlag(TIM3, TIM_FLAG_Update);
	
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
	
	TIM_Cmd(TIM3, ENABLE);
}

void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3, TIM_IT_Update)) a++;
	if(a == 1000)
	{
		LED_Toggle();
		a = 0;
	}
	TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}



以上代码是使用STM32的定时器TIM3和LED模块实现了一个每秒闪烁一次的LED灯效果。

在NVIC_Config函数中,我们进行了中断优先级的配置,将TIM3的中断通道使能,并设置了抢占优先级和子优先级。
在TIM3_Config函数中,我们首先使能了TIM3的时钟。然后,配置了TIM3的定时基础参数,设置了计数器的周期为71,预分频系数为1000(即每1ms计数器加1)。接着,清除了TIM3的更新标志位,并使能了TIM3的更新中断。最后,使能了TIM3定时器。
在TIM3_IRQHandler中,首先判断TIM3的更新中断是否发生,然后对计数器进行累加。当计数器累加到1000时,表示经过了1秒的时间,此时调用LED_Toggle函数切换LED的状态,然后将计数器清零,并清除TIM3的更新中断标志位。
通过以上代码,可以实现每秒闪烁一次的LED效果。在主函数中,需要调用TIM3_Config函数进行配置,然后进入主循环等待中断触发。当TIM3的更新中断发生时,会调用TIM3_IRQHandler函数进行LED状态的切换。
tim_timebase.h

#ifndef __TIM_TIMEBASE_H
#define __TIM_TIMEBASE_H

#include "stm32f10x.h"

void TIM3_Config(void);

#endif



main.c

#include "stm32f10x.h"
#include "led.h"
#include "tim_timebase.h"

int main(void)
{
	LED_Config();
	TIM3_Config();
	
	while(1)
	{
		
	}
}

在这里插入图片描述
PWM的应用
实验要求
接上,采用定时器PWM模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 PWM输出波形。

代码
PWM.c

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;		//PSC
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);
}

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);
}


main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"

uint8_t i;

int main(void)
{
	OLED_Init();
	PWM_Init();
	
	while (1)
	{
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(i);
			Delay_ms(5);
		}
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(100 - i);
			Delay_ms(5);
		}
	}
}


实验效果
接线:
在这里插入图片描述
烧录后的效果:
在这里插入图片描述
使用Keil虚拟示波器,观察 PWM输出波形
Keil虚拟示波器的配置见:
链接: https://blog.csdn.net/weixin_63019977/article/details/133749827
选择PA0号引脚:
在这里插入图片描述
标为bit显示,用绿色的线表示,得到的波形结果如下图所示:
在这里插入图片描述
总结
在了解STM32的定时器原理和脉宽调制(PWM)生成方法。定时器可以通过计数器和相关寄存器实现定时和计数功能,而PWM是一种通过不同占空比的脉冲信号来控制电路的方式。
在本实验中,我们使用STM32F103系列的Tim2~Tim5中的一个定时器通道,将LED连接到相应的GPIO管脚上。首先,使用定时器的计数方式,通过配置定时器的参数和中断处理函数,可以实现LED以2秒的频率周期性地亮-灭。
接着,采用定时器的PWM模式,通过配置定时器的参数和相关寄存器,可以实现LED以呼吸灯方式渐亮渐灭。调整周期为1~2秒,可以根据个人喜好来调整出满意的效果。通过Keil虚拟示波器,我们可以观察PWM输出波形,以验证PWM的正确性。
在实验过程中,我们需要仔细阅读相关的STM32定时器和PWM模式的文档,理解其寄存器的配置方法和中断处理函数的编写。同时,需要熟悉Keil虚拟示波器的使用方法,以便观察波形输出。
总的来说,通过本次实验获得了许多经验。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值