基于STM32F103ZET6库函数PWM输出实验

基于STM32F103ZET6库函数PWM输出实验


使 用 TIM3 的通道 2,把通道 2 重映射到 PB5,产生 PWM 来控制 DS0 的亮度。

PWM 简介

简单一点,就是对脉冲宽度的控制。

STM32 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定 时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4 路的 PWM 输出,这样,STM32 最多可以同时产生 30 路 PWM 输出!这里我们仅利用 TIM3 的 CH2 产生一路 PWM 输出。如果要产生多路输出,大家可以根据我们的代码稍作修改即可。

通过库函数来配置该 功能的步骤。 PWM 相关的函数设置在库函数文件 stm32f10x_tim.h 和 stm32f10x_tim.c 文件中。
1.开启 TIM3 时钟以及复用功能时钟,配置 PB5 为复用输出。
要使用 TIM3,我们必须先开启 TIM3 的时钟。 这里我们还要配置 PB5 为复用输出,这是因为 TIM3_CH2 通道将重映射到 PB5 上,此时,PB5 属于复用功能输出。库函数使能 TIM3 时钟的方法是:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器 3 时钟 

库函数设置 AFIO 时钟的方法是:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);  //复用时钟使能 

这里简单列出 GPIO 初始化的一行代码即可:

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出 

2.设置 TIM3_CH2 重映射到 PB5 上。
因为 TIM3_CH2默认是接在 PA7上的,所以我们需要设置 TIM3_REMAP为部分重映射(通 过 AFIO_MAPR 配置),让 TIM3_CH2 重映射到 PB5 上面。在库函数函数里面设置重映射的函 数是:

void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)

STM32 重映射只能重映射到特定的端口。第一个 入口参数可以理解为设置重映射的类型,比如 TIM3 部分重映射入口参数为 GPIO_PartialRemap_TIM3,这 点可以顾名思义了。所以 TIM3 部分重映射的库函数实现方法是:

GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); 

3.初始化 TIM3,设置 TIM3 的 ARR 和 PSC。
在开启了 TIM3 的时钟之后,我们要设置 ARR 和 PSC 两个寄存器的值来控制输出 PWM 的 周期。当 PWM 周期太慢(低于 50Hz)的时候,我们就会明显感觉到闪烁了。因此,PWM 周 期在这里不宜设置的太小。这在库函数是通过 TIM_TimeBaseInit 函数实现的

TIM_TimeBaseStructure.TIM_Period = arr; 										//设置自动重装载值 
TIM_TimeBaseStructure.TIM_Prescaler =psc; 										//设置预分频值  
TIM_TimeBaseStructure.TIM_ClockDivision = 0; 									//设置时钟分割:TDTS = Tck_tim 
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 					//向上计数模式 
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 								//根据指定的参数初始化 TIMx 的 

4.设置 TIM3_CH2 的 PWM 模式,使能 TIM3 的 CH2 输出。
我们要设置 TIM3_CH2 为 PWM 模式(默认是冻结的),因为我们的 DS0 是低电 平亮,而我们希望当 CCR2 的值小的时候,DS0 就暗,CCR2 值大的时候,DS0 就亮,所以我 们要通过配置 TIM3_CCMR1 的相关位来控制 TIM3_CH2 的模式。在库函数中,PWM 通道设 置是通过函数 TIM_OC1Init()~TIM_OC4Init()来设置的,不同的通道的设置函数不一样,这里我 们使用的是通道 2,所以使用的函数是 TIM_OC2Init()。

void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)

看看结构体 TIM_OCInitTypeDef 的定义:

typedef struct 
{   
	uint16_t TIM_OCMode; 
	uint16_t TIM_OutputState;     
	uint16_t TIM_OutputNState;    
	uint16_t TIM_Pulse;            
	uint16_t TIM_OCPolarity;       
	uint16_t TIM_OCNPolarity;      
	uint16_t TIM_OCIdleState;     
	uint16_t TIM_OCNIdleState;   
}TIM_OCInitTypeDef; 

这里我们讲解一下与我们要求相关的几个成员变量:
参数 TIM_OCMode 设置模式是 PWM 还是输出比较,这里我们是 PWM 模式。
参数 TIM_OutputState 用来设置比较输出使能,也就是使能 PWM 输出到端口。
参数 TIM_OCPolarity 用来设置极性是高还是低。
其他的参数 TIM_OutputNState,TIM_OCNPolarity,TIM_OCIdleState 和 TIM_OCNIdleState 是 高级定时器 TIM1 和 TIM8 才用到的。

要实现我们上面提到的场景,方法是:

TIM_OCInitTypeDef  TIM_OCInitStructure;  
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; 						//选择 PWM 模式 2 
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 			//比较输出使能 
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 				//输出极性高 
TIM_OC2Init(TIM3, &TIM_OCInitStructure);  								//初始化 TIM3 OC2 

5.使能 TIM3。
在完成以上设置了之后,我们需要使能 TIM3。

TIM_Cmd(TIM3, ENABLE);  //使能 TIM3 

6.修改 TIM3_CCR2 来控制占空比。
在经过以上设置之后,PWM 其实已经开始输出了,只是其占空比和频率都是固定 的,而我们通过修改 TIM3_CCR2 则可以控制 CH2 的输出占空比。继而控制 DS0 的亮度。
在库函数中,修改 TIM3_CCR2 占空比的函数是:

void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2)

对于其他通道,分别有一个函数名字,函数格式为 TIM_SetComparex(x=1,2,3,4)。
通过以上 6 个步骤,我们就可以控制 TIM3 的 CH2 输出 PWM 波了。

硬件设计

本实验用到的硬件资源有:
1) 指示灯 DS0
2) 定时器 TIM3

软件设计

在 timer.c 里面加入了 如下代码:

//TIM3 PWM部分初始化 
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);							//使能定时器3时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);    //使能GPIO外设和AFIO复用功能模块时钟
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); 							//Timer3部分重映射  TIM3_CH2->PB5    
	
	//设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOB.5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; 										//TIM_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  								//复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);											//初始化GPIO
	
	//初始化TIM3
	TIM_TimeBaseStructure.TIM_Period = arr; 										//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; 										//设置用来作为TIMx时钟频率除数的预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 									//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  					//TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 								//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
	
	//初始化TIM3 Channel2 PWM模式	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; 								//选择定时器模式:TIM脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 					//比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 						//输出极性:TIM输出比较极性高
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  										//根据T指定的参数初始化外设TIM3 OC2
	
	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  								//使能TIM3在CCR2上的预装载寄存器
	
	TIM_Cmd(TIM3, ENABLE);  														//使能TIM3
	

}

头文件 timer.h 与上一个的不同是加入了 TIM3_PWM_Init 的声明

#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"

void TIM3_Int_Init(u16 arr,u16 psc);
void TIM3_PWM_Init(u16 arr,u16 psc);
#endif

main.c

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"

int main(void)
{		
 	u16 led0pwmval=0;
	u8 dir=1;	
	delay_init();	    	 								//延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	    //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 									//串口初始化为115200
 	LED_Init();			     								//LED端口初始化
 	TIM3_PWM_Init(899,0);	 								//不分频。PWM频率=72000000/900=80Khz
   	while(1)
	{
 		delay_ms(10);	 
		if(dir)
		{
			led0pwmval++;
		}
		else
		{ 
			led0pwmval--;
		}

 		if(led0pwmval>300)
 		{
			dir=0;
		}
		if(led0pwmval==0)
		{
			dir=1;
		}										 
		TIM_SetCompare2(TIM3,led0pwmval);		   
	}	 
}

这里,我们从死循环函数可以看出,我们将 led0pwmval 这个值设置为 PWM 比较值,也就 是通过 led0pwmval 来控制 PWM 的占空比,然后控制 led0pwmval 的值从 0 变到 300,然后又 从 300 变到 0,如此循环,因此 DS0 的亮度也会跟着从暗变到亮,然后又从亮变到暗。至于这 里的值,我们为什么取 300,是因为 PWM 的输出占空比达到这个值的时候,我们的 LED 亮度 变化就不大了(虽然最大值可以设置到 899),因此设计过大的值在这里是没必要的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是北豼不太皮吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值