失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > PWM的驱动使用(呼吸灯)

PWM的驱动使用(呼吸灯)

时间:2019-08-15 23:37:41

相关推荐

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、输出比较模式

图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 headervoid 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;//设置CCRTIM_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_Hvoid 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位得全局变量Numint 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 = 99CCR = 50 PSC+1 = 720

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

图4-4for函数

6、效果

呼吸灯

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

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

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

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

如果觉得《PWM的驱动使用(呼吸灯)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。