PWM的驱动使用(呼吸灯)

目录

一、初始化步骤

二、PWM所需函数

 三、PWM初始化与引脚使用

1、输出比较模式

2、极性的选择

3、初始化:

怎么给结构体赋初始值

4、引脚的使用(引脚定义表)

四、代码(PWM呼吸灯)

1、PWM.c

2、PWM.h

3、main.c

4、模式的选择(复用推挽输出)

 5、PWM参数的计算

 6、效果


一、初始化步骤

 图1-1PWM基本结构

第一步,RCC开启时钟,把我们要用的TIM外设和GPIO外设时钟开打

第二步,配置时基单元,包括前面的时钟源选择和时基单元

第三步,配置输出比较单元,包括CCR的值,输出比较模式,极性选择,输出使能这些参数

第四步,配置GPIO,把PWM对应的GPIO口,初始化为复用推挽输出的配置

第五步,运行控制,启动计数器,就能输出PWM

二、PWM所需函数

TIM_OC(1234)Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

这四个函数就是用来配置输出比较模块的,OC就是Output Compare,输出比较,这四个函数是配置上一章节的PWM基本结构中的输出比较单元x4这一块的,一个函数配置一个单元

参数:TIMx,选择定时器;第二个,结构体,输出比较的那些参数

是用结构体来初始化输出比较单元的

补充:这个函数仅高级定时器使用,在使用高级定时器输出PWM时,需要调用这个函数,使能主输出,否则PWM将不能正常输出。

TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);

是用来给输出比较结构体赋一个默认值

TIM_ForcedOC(1234)Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);

使用来配置前置输出模式的,如果在运行中,想要暂停输出波形并且强制输出高或低电平,则可以使用此函数,但是使用情况不多,因为强制输出高电平和设置100%占空比是一样的

TIM_OC(1234)PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

这四个函数是用来配置CCR寄存器的预装功能(影子寄存器)的;影子寄存器:写入的值不会立刻生效,而是在更新事件才会发生。

TIM_OC(1234)FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);

这四个函数是用来配置快速使能的

TIM_ClearOC(1234)Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);

外部事件时清除REF信号

TIM_OC(1234)PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

TIM_OC(123)NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);

是用来单独设置输出比较的极性的,带个N的就是高级定时器里互补通道的配置,OC4没有互补通道,所以没有OC4N的函数。在结构体初始化的那个函数里可以设置极性。

注:两个地方设置极性的作用是一样的,只不过是用结构体是一起初始化的。这里是单独的函数进行修改的。一般来说,结构体的参数,都会有一个单独的函数可以进行更改。这7个函数就是用来单独更改输出极性的。

TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);

TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);

是用来单独修改输出使能参数的。

TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);

选择输出比较模式,这个是用来单独更改输出比较模式的函数。

TIM_SetCompare(1234)(TIM_TypeDef* TIMx, uint16_t Compare1);  重要

这四个函数是用来单独更改CCR寄存器值的函数。在运行的时候,更改占空比。

 三、PWM初始化与引脚使用

在这次项目的使用引脚是PB6引脚

1、输出比较模式

模式模式参数
冻结模式TIM_OCMode_Timing
相等时置有效电平TIM_OCMode_Active
相等时置无效电平TIM_OCMode_Inactive
相等时电平翻转TIM_OCMode_Toggle
PWM模式1TIM_OCMode_PWM1
PWM模式2TIM_OCMode_PWM2

 图3-1强制输出模式

2、极性的选择

 图3-2极性的选择

参数1:high,高极性,就是极性不翻转,REF波形直接输出;或者说是有效电平是高电平,REF有效时,输出高电平

参数2:low,低极性,就是REF电平取反,或者说是有效电平为低电平

3、初始化:

1、打开时钟,选择内部时钟,初始化时基单元,因为我们是使用PB6引脚,所以在这里我们使用的是TIM2定时器。

2、在时基单元初始化下,初始化输出比较单元,在TIM.h文件中,TIM_OC(x)Init的4个初始化函数,对应的4个输出比较单元/输出比较通道,需要哪个初始化哪个通道,就调用哪个函数,不同通道的对应GPIO口也是不一样的,按照GPIO口需求来。我们使用的是PB6口,所以对应的是OC1_Init函数

图3-3初始化 

 注:在这里,我们这个结构体现在没有给所有的成员赋值,对于这个结构体来说,它现在是一个局部变量,如果不给他的成员赋初始值,它成员的值就是不确定的,会导致出现问题。

例:想把高级定时器当做定时器输出PWM时,自然会把TIM2、3、4改成为TIM1,这样的话,这个结构体原本用不到的成员,现在就需要使用到了。而这些之前没有使用到的成员你没有赋值,就会导致高级定时器输出PWM出现一些奇怪的问题。

问题例子:像高级定时器输出4路PWM,如果把初始化函数放在程序的第一行,则不会出现问题,如果初始化函数之前出现了其他代码,那4路PWM就会有3路不能输出。

原因:就是结构体成员没有配置完整,也没有给结构体赋初始值

正确做法:

方法1:把结构体所有成员都配置完整

方法2:先给结构体成员都赋一个初始值,在修改部分结构体成员

怎么给结构体赋初始值

使用Struct_Init函数,Struct_Init函数,就是用来给结构体赋初始值的

用途:使用Struct_Init赋一个初始值,再更改所需要的值即可,无需一一列出所有成员。

4、引脚的使用(引脚定义表)

 图3-4引脚定义表

 引脚定义表:默认复用功能就是片上外设的端口和GPIO的连接关系,如PA0,有TIM2_CH1_ETR,说明TIM2的ETRE引脚和通道1的引脚,都是借用了PA0这个引脚的位置的。

注:我们要使用TIM2的OC1也就是CH1通道,输出PWM,只能在PA0的引脚上输出,不能任意选择引脚输出,这些关系是定死的,是不能改变的。

 重映射:如PA2,如果你想用USART2的TX引脚,又要使用TIM2的CH3通道,无法同时使用,则可以在重定义列表中寻找,如果重定义的列表找不到,那外设复用的GPIO就不能挪位置。配置重映射是用AFIO来完成。

四、代码(PWM呼吸灯)

1、PWM.c

#include "stm32f10x.h"                  // Device header


void PWM_Init(void)
{
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//注意是开启APB1的时钟函数,因为TIM2是APB1总线的外设
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//选择时基单元的时钟
	 
	  
	  GPIO_InitTypeDef GPIO_InitStructure;
	  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
	  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
	  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	  GPIO_Init(GPIOB,&GPIO_InitStructure);
	
		TIM_InternalClockConfig(TIM4);
	  //定时器上电后默认是使用内部时钟,如果不调用,也是使用内部时钟,可以不写
	  
	
	
		//TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);
	  //通过ETR引脚的外部时钟模式2配置
	
		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(TIM4,&TIM_TimeBaseInitStructure);
		//配置时基单元
		
	  TIM_OCInitTypeDef TIM_OCInitStructure;
		TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值,不用一一列出
		TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1 ;//设置输出比较的模式
		TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High ;//设置输出比较的极性
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能
		TIM_OCInitStructure.TIM_Pulse = 0;//设置CCR
		TIM_OC1Init(TIM4, &TIM_OCInitStructure);
		
		//周期ARR;预分频PSC;CCR这三个值,共同决定输出PWM的周期和占空比
		
		
		TIM_Cmd(TIM4,ENABLE);//启动定时器

}

void PWM_Setcompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM4, Compare);
}




2、PWM.h

#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
void PWM_Setcompare1(uint16_t Comparel);

#endif

3、main.c

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


uint8_t i;//定义一个16位得全局变量Num

int main(void)
{
    OLED_Init(); 
	  PWM_Init();
	
	
	while(1)
	{
			for (i = 0;i <= 100; i++)
		{
					PWM_Setcompare1(i);//设置CCR寄存器的值,并不是直接占空比,占空比是CCR和ARR+1决定的
					Delay_ms(10);
		}
		for (i = 0;i <= 100; i++)
		{
					PWM_Setcompare1(100 - i);
					Delay_ms(10);
		}
	}
}


4、模式的选择(复用推挽输出)

在PWM.c中,我们选择的GPIO口是PB6引脚,选择的是TIM4定时器(普通定时器),当中的模式我们选择的是复用推挽输出。

 图4-1开漏/推挽输出

 图4-2复用开漏/推挽输出

由图4-1可以知道普通开漏/推挽输出:引脚的控制权是来自于输出数据寄存器

如果想用定时器的控制引脚,需要使用复用开漏/推挽输出的模式,这里的输出数据寄存器被断开输出控制权将转移给片上外设,片上外设连接的TIM2的CH1通道,所以只有GPIO设置成复用推挽输出,引脚控制权才能交给片上外设,PWM波形才能通过引脚输出。

 5、PWM参数的计算

 图4-3参数计算

 周期ARR;预分频PSC;CCR这三个值,共同决定输出PWM的周期和占空比

假设设置一个1KHz,占空比50%,分辨率为1%的PWM波形

ARR = 99             CCR = 50               PSC+1 = 720

程序中,我们需要做的是呼吸灯,所以我们把CCR设置为0,在main.c中使用for函数达到呼吸灯的效果

 图4-4for函数

 6、效果

呼吸灯


本章写的是PWM的使用,项目是使用PWM的呼吸灯,在参考本章内容中,如果遇到不懂的可以参考上三章的内容

 TIM定时中断(定时器介绍)_tz得像个小孩的博客-CSDN博客_tim计时器

 定时器定时中断&定时器外部时钟_tz得像个小孩的博客-CSDN博客

 TIM输出比较(PWM)_tz得像个小孩的博客-CSDN博客


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

tz得像个小孩

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

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

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

打赏作者

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

抵扣说明:

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

余额充值