定时器&PWM应用编程

定时器
定时器本质上是一个以单位时间为准的计数器,计数值可从0开始累加,也可从一个设定数值递减。每隔一个固定时间计时器的值加1或减1,当加到(或减到)到头时,会产生一个溢出信号,并将计时值清0重新计时。
利用定时器溢出可产生总周期,利用PWM可以调制该周期的占空比。

对于我们的STM32F103定时器的计数方式如下:
在这里插入图片描述

STM32F103
通用定时器(TIM 2、3、4)
STM32F103xx增强型产品中,内置了多达3个可同步运行的标准定时器(TIM2、TIM3、TIM4)。每个定时器都有一个16位的自动加载递加/递减计数器、一个16位的预分频器和4个独立的通道,每个通道都可用于输入捕获、输出比较、PWM和单脉冲模式输出,在大的封装配置中可提供多12个输入捕获、输出比较或PWM通道。它们还能通过定时器链接功能与高级控制定时器共同工作,提供同步或事件链接功能。在调试模式下,计数器可以被冻结。任一标准定时器都能用于产生PWM输出。每个定时器都有独立的DMA请求机制。这些定时器还能够处理增量编码器的信号,也能处理1至3个霍尔传感器的数字输出。

高级定时器(TIM 1)
高级控制定时器(TIM1)可以被看成是分配到6个通道的三相PWM发生器,它具有带死区插入的互补PWM输出,还可以被当成完整的通用定时器。四个独立的通道可以用于:

输入捕获、输出比较、产生PWM(边缘或中心对齐模式)、单脉冲输出
配置为16位标准定时器时,它与TIMx定时器具有相同的功能。
配置为16位PWM发生器时,它具有全调制能力(0~100%)。
在调试模式下,计数器可以被冻结,同时PWM输出被禁止,从而切断由这些输出所控制的开关。
很多功能都与标准的TIM定时器相同,内部结构也相同,
因此高级控制定时器可以通过定时器链接功能与TIM定时器协同操作,提供同步或事件链接功能。

定时器的工作模式如下图:
在这里插入图片描述

本次我们具体了解定时器产生PWM的功能

PWM
PWM脉宽调制
脉冲宽度调制(PWM),是英文“Pulse Width Modulation’ 的缩写,简称脉宽调制。脉宽调制也叫占空比。
它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。

在我看来就是单片机通过相应定时器的设置,将某个IO端口设置成可以产生一定周期、一定占空比的方波。

利用定时器产生PWM的原理图如下:
在这里插入图片描述
在这里插入图片描述

通过设置计数值ARR的值,我们用来产生一定周期的波形(因为每过一个机器周期,计数值加1),通过设定CCRx的值,当计数值在CCRx之前的值,将IO端口设置成低电平,在CCRx和ARR值之间设置成高电平 ,如此即完成了相应的占空比。

STM32F103对应的定时器的通道与IO端口复用,同时也可以通过重映射,将对应的通道映射到其他的IO端口,只需要使用固件库函数即可。
由于本例我们利用了TIM3定时器产生PWM波,因此特将TIM3的重映射表列下:
在这里插入图片描述

由于TIM3的3通道和PB0复用,因此需要开启复用时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO时钟(定时器3通道3需要重映射到BP5引脚)

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO时钟(定时器3通道3需要重映射到BP5引脚)

又因为我们使用了48引脚封装,因此不可使用重映射。
新建工程,进行基本配置。通过点击“ACCESS TO MCU SELECTOR”来创建一个新的工程:

芯片选择“STM32F103C8”,开启工程。
在这里插入图片描述

打开外部时钟,点击“System Core”,选择RCC,在右侧弹出的菜单栏中选择“Crystal/Ceramic Resonator”。

在这里插入图片描述

选择调试接口,点击“System Core”,选择SYS。,在右侧弹出的菜单栏中选择“Serial Wire”。

在这里插入图片描述

配置定时器3和定时器4。如图,选中定时器3和定时器4;选择时钟源为“Internal Clock”,通道2选择“PWM Generation CH2”,设置分频系数为71,计数周期为500,其它默认。设置占空比初始值为10,其实这里不写也没影响。

在这里插入图片描述

在这里插入图片描述

时钟配置。这里,我们需要把它倍频到72MHZ。先点击“Clock Configuration”页面,按照下面红色框中的值,从左到右进行配置即可。
在这里插入图片描述

生成工程。在工程管理页面“Project Manager”,先点击“Project ”,选择如下配置:
在这里插入图片描述

再点击“Code Generator”,进行如下配置:
在这里插入图片描述

最后,点击右上角那个不像按钮的按钮“GENERATE CODE”,即可生成相应工程。工程生成之后,会弹出对话框,提示你是否需要打开。选择打开。
在这里插入图片描述

定时器的应用
实验要求
使用STM32F103的 Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。
#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;
}

#ifndef __LED_H
#define __LED_H

#include “stm32f10x.h”

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

#endif

#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灯效果。
在这里插入图片描述
在这里插入图片描述

PWM的应用
实验要求
接上,采用定时器PWM模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 PWM输出波形。
#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);
}

#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输出波形:
在这里插入图片描述
在这里插入图片描述
实验总结
通过这次实例演训,初步认识了STM32定时器的相关理论知识,以及在STM32F103C8T6核心开发板下,通过使用定时器Timer方式,来实现串口定时输出及LED灯周期闪烁的操作步骤。还学习到了PWM的相关理论知识,以及在STM32F103C8T6核心开发板下,通过TIM3和TIM4输出PWM波形实现2个 LED呼吸灯效果的操作步骤;

虽然中间过程有点曲折,但最终实验结果还是基本能符合预期。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值