基于STM32103ZET6实现定时器输出PWM

我们使用 TIM3 的通道 2,把通道 2 重映射到 PB5,产生 PWM 来控制 DS0 的亮度!
这是数字电路控制模拟电路的一个典型例子

原理讲解:就一句话

PWM是脉冲宽度调制,通过定时器产生固定频率的脉冲波形,通过配置寄存器TIM3_CCR2值,改变(输出比较)这一固定频率的输出占空比,实现改变PWM占空比目的,实现led点亮。
问题
那么问题就到了怎们配置定时器定时器产生固定频率波形,需要使能什么功能,用到了哪些外设。。。
概述
STM32开发板定时器都可以用来产生PWM,且可同时产生多路PWM,具体多少路大家可以深入了解,反正就是按照多少定时器计算,我们这个实验,只需要TIM3的通道二(CH2),除了在上一讲博客中提到的定时器的寄存器初始化外,还有几个重要的定时器配置需要讲解:
捕获/比较模式寄存器(TIMx_CCMR1/2)
在这里插入图片描述
这个0-15是控制CH1和CH2的,该寄存器总共有 2 个,TIMx_CCMR1和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和2,而 TIMx_CCMR2 控制 CH3 和 4。
在OC1M(4-6位)与OC2M(12-14位)是配置成7种模式,为什么PWM还有7种模式?是因为在不同模式下,有些寄存器的位功能会不同,我们需要的是PWM模式,所以通道二中的值必须为110或者111,两者差别就是输出极性相反!
捕获/比较使能寄存器(TIMx_CCER)
在这里插入图片描述
所谓使能,就是打开,就操作CCXE位,使用到的通道二,就只操作CC2E就可以了,写入值为1就好,
捕获/比较寄存器(TIMx_CCR1~4)
在这里插入图片描述
该寄存器个数为四个,正好对应CH1-CH4,配置是一样的,以通道1为例在输出模式下,该寄存器的值与 (计数器)CNT 的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽了,我们要使用通道二,就要配置CCR2寄存器
重映射
想要用pwm控制led0,但是硬件连接上并没有连接在一起,STM32很强大,可以利用重映射使得pwm口输出电平到led0,STM32 的重映射控制是由复用重映射调试 IO 配置寄存器AFIO_MAPR控制的
在这里插入图片描述
我们用到的是TIM3,所以重映射选择10-11位,但是两位有四种重映射值,那么我们重映射到底映射到哪个IO口了呢?
在这里插入图片描述
这时候我们选择的是led0控制口PB5,当我们的PA7映射到PB5的同时,PA6也映射到了PA4,PB0与PB1不变。
梳理软件步骤
(1):使能定时器时钟使能APB1,GPIO复用时钟直接使用配置函数
实际操作:RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
实际操作:RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
(2):GPIO初始化,配置GPIO复用推挽输出!定时器初始化,确定周期,配置为pwm模式
初始化代码过多,详情见代码
(3):GPIO重映射
函数:void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
实际操作:GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
(4):配置pwm模式,使能通道二输出
初始化代码过多,详情见代码
(5):使能定时器
TIM_Cmd(TIM3, ENABLE);
(6):最后控制占空比用void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);函数,Compare2参数取值范围为0-899;可根据自己的情况布置pwm;

PWM头文件pwm.h

#ifndef PWM_H
#define PWM_H
#include “sys.h”
void pwm_init(u16,u16);
#endif

PWM源文件pwm.c

#include “pwm.h”
#include “sys.h”

void pwm_init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_TypeStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
TIM_TimeBaseInitStructure.TIM_ClockDivision=0;
TIM_TimeBaseInitStructure.TIM_CounterMode= TIM_CounterMode_Up;;
TIM_TimeBaseInitStructure.TIM_Period=arr;
TIM_TimeBaseInitStructure.TIM_Prescaler=psc;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_TypeStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_TypeStructure.TIM_OCMode=TIM_OCMode_PWM2;;
TIM_TypeStructure.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OC2Init(TIM3, &TIM_TypeStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
TIM_Cmd(TIM3, ENABLE);
}
如上配置在前面的步骤中梳理出来的,看起来有点繁琐,可以对应步骤来看

PWM主函数源文件main.c

#include “led.h”
#include “sys.h”
#include “delay.h”
#include “pwm.h”
int main(void)
{
int led1;
int led2;
delay_init();
LED_Init();
pwm_init(899,0);

 while(1)
 { 
	 delay_ms(10);
	 if(led1<300)
	 {
		 TIM_SetCompare2(TIM3,led1);
		 led1++;
		 if(led1>=300)
		 {
			 led2=300;
		 }
	 }
	else
		 {
			 TIM_SetCompare2(TIM3,led2);
			 led2--;
			 if(led2<=0)
			 {
				 led1=0; 
			 }	 
		 }
	 
 }

}
主函数实现很简单,可根据自己的喜好来设置显示内容。
唯有实践,才是能体会到过程的快乐!

现象

在完成软件设计之后,将我们将编译好的文件下载到精英 STM32 开发板上,观看其运行结果是否与我们编写的一致。如果没有错误,我们将看 DS0 不停的由暗变到亮,然后又从亮变到暗。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章