基于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 不停的由暗变到亮,然后又从亮变到暗。

发布了10 篇原创文章 · 获赞 14 · 访问量 4085

猜你喜欢

转载自blog.csdn.net/weixin_42271802/article/details/104532353