ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

STM32F103五分钟入门系列(十五)输出比较(PWM输出)+各类测试

2021-08-03 19:04:20  阅读:419  来源: 互联网

标签:STM32F103 输出 定时器 TIM 寄存器 OCInitStructure GPIO PWM


学习板:STM32F103ZET6

参考:

STM32F103五分钟入门系列(十二)定时器中断

PWM输出

前言

在之前的《定时器中断》中总结了定时器相关的内容,在那篇博客中也提到过输入捕获和输出比较,本博和接下来的一篇博客总结这两块内容。其中本博总结的的是下图标注的部分,通过输出一个PWM脉冲,来深入了解输出比较方面的东西。
在这里插入图片描述

博主很喜欢从寄存器入手总结一个东西,因为从寄存器中可以找到许多平时被库函数封装起来的东西,这些东西非常有利于理解相应的内容。本博也不例外,会从寄存器再到库函数慢慢了解PWM输出的真正含有。

一、定时器输出PWM简介

STM32除了基本定时器TIM6、TIM7,其他定时器都可以产生PWM输出。其中高级定时器TIM1、TIM8可以同时产生7路的PWM输出;通用定时器TIM2~5也可以同时输出4路的PWM。共可以输出30路的PWM。

其工作原理如下:
在这里插入图片描述

如上图,为一个向上计数的计数器,从0计数到重装载值ARR后,再回到0开始重新计数。

现给它一个“阈值”CCRX,超过这个“阈值”的计数范围(时间段)可以让某IO口输出高电平,未超过该“阈值”的计数范围(时间段)可以让某IO口输出低电平;当然也可以反过来:超出“阈值”输出低电平,未超出“阈值”输出高电平。这样就可以输出稳定的方波了。

上图所示,横坐标:0~t2、t2 ~t4、t4 ~t6,即是计数的一个周期,又是输出PWM的一个周期,可见,影响PWM周期的因素只是这个重装载值ARR。

上图所示。当:

超出“阈值”输出高电平,未超出“阈值”输出低电平

此时横坐标:0~t1、t2 ~t3、t4 ~t5 计数时间段输出的是PWM低电平,其它时间段输出高电平,占空比:(t2-t1)/t2=(t4-t3)/(t4-t2)…

当:

超出“阈值”输出低电平,未超出“阈值”输出高电平

此时横坐标:0~t1、t2 ~t3、t4 ~t5 计数时间段输出的是PWM高电平,其它时间段输出低电平,占空比:t1/t2=(t3-t2)/(t4-t2)…

可见,这个“阈值”CCRx影响这输出PWM占空比,当然影响占空比的因素还有“模式”,即超出“阈值”后的部分究竟是高电平还是低电平。

综上,只要配置好定时器、设置好重装载值(确定周期)、设置好模式(确定占空比)、设置好“阈值”CCRx(确定占空比)就可以输出PWM了。当然也可以让其它设置固定,只改变“阈值”的情况下,输出周期一定,占空比变化的PWM。

二、输出比较相关寄存器

1、捕获/比较模式寄存器 1(TIMx_CCMR1)(CH1、CH2

在这里插入图片描述

该寄存器设置通道1和通道2,(通用定时器有4个通道,高级定时器7个通道),其中低8位设置CH1,高8位设置CH2

位1:0

在这里插入图片描述

位1:0在捕获/比较中共用,不好理解就直接放图:

①位1:0=00,CC1通道配置为输出:
在这里插入图片描述

②位1:0=01,CC1通道被配置为输入,IC1映射在TI1上

在这里插入图片描述

③位1:0=10,CC1通道被配置为输入,IC1映射在TI2上
在这里插入图片描述

④位1:0=11,CC1通道被配置为输入,IC1映射在TRC上

在这里插入图片描述

位2

在这里插入图片描述

该位置1时可将输出PWM的响应时间缩短2个时钟周期

位3

在这里插入图片描述

该位使能输出比较1预装载值,输出比较的预装载置存储在TIMx_CCR1寄存器中,如果该位置0,则随时可以把重装载值写入到TIMx_CCR1寄存器;如果该位置1,则只有更新事件到来时才可以将重装载值写入到TIMx_CCR1寄存器。

位6:4

在这里插入图片描述

主要看一下110、111的情况,首先要清楚CCR1中装载的值是本博开头说的那个“阈值”,这个“阈值”要和计数器当前值比较的。

①当位6:4=110时为PWM1模式—向上计数。

本博开头《PWM简介》所说的就是向上计数,当时分为以下两种情况:

超出“阈值”输出高电平,未超出“阈值”输出低电平
超出“阈值”输出低电平,未超出“阈值”输出高电平

位6:4=110时的描述:

110:PWM模式1- 在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。

在这里插入图片描述

这个描述怎么理解呢?如上图:

当计数器的值小于“阈值”(TIMx_CNT<TIMx_CCR1)时,通道1位有效电平,即上图的0~t1、t2 ~t3、t4 ~t5时间段为有效电平,剩下时间段为无效电平。

同理:当位6:4=111时,当计数器的值小于“阈值”(TIMx_CNT<TIMx_CCR1)时,通道1位无效电平,即上图的0~t1、t2 ~t3、t4 ~t5时间段为无效电平,剩下时间段为有效电平。

注意:有效电平不是高电平,有效电平可能是高电平,也可能是低电平,有效电平的极性在CCER寄存器中设置。
在这里插入图片描述

综上:

(1)CCRE寄存器把有效电平极性设置为高电平有效,CCMR1寄存器位6:4=110,为PWM1模式时:

在这里插入图片描述

(2)CCRE寄存器把有效电平极性设置为低电平有效,CCMR1寄存器位6:4=110,为PWM1模式时:
在这里插入图片描述

(3)CCRE寄存器把有效电平极性设置为高电平有效,CCMR1寄存器位6:4=111,为PWM2模式时:

在这里插入图片描述

(4)CCRE寄存器把有效电平极性设置为低电平有效,CCMR1寄存器位6:4=111,为PWM2模式时:
在这里插入图片描述

位7

在这里插入图片描述

该位设置C1REF是否受ETRF影响

在这里插入图片描述

位15:8

在这里插入图片描述

这高8位是设置通道2的,与前面通道1的总结一模一样,不在赘述。

2、捕获/比较模式寄存器 2(TIMx_CCMR2)(CH3、CH4

在这里插入图片描述

该寄存器与CCMR1一样,不过是对通道3和通道4的设置。不再赘述。

3、捕获/比较使能寄存器(TIMx_CCER)

在这里插入图片描述

位1:0

在这里插入图片描述

位0是使能位,使能CC1通道输出

在这里插入图片描述

.
位1是设置通道的输出极性位,之前CCMR1已经总结过了,0时有效电平是高电平,1时有效电平是低电平。

剩下的位5:4、位9:8、13:12分别设置CH2、CH3、CH4,与刚刚总结的CH1设置一样,不再赘述。

4、自动重装载寄存器(TIMx_ARR)

该寄存器应该在《定时器中断》这篇博客中总结的,不过那篇博客当时无心去总结寄存器,就没有总结,现在补上…

在这里插入图片描述

该寄存器是16位寄存器,不像看门狗的重装载寄存器,只有7位。用来存储计数器的装载值的,每次计数到0(向下计数、上/下计数)或计数到最大值(向上计数)时都要重装载初值。

5、捕获/比较寄存器 1、2、3、4(TIMx_CCRx)

在这里插入图片描述

该寄存器也是16位寄存器,装载的是之前所说的那个“阈值”。

三、输出比较的相关库函数

1、初始化通道函数TIM_OCxInit()

在这里插入图片描述

以通道1的设置函数TIM_OC1Init()为例说明。通道2函数TIM_OC1Init()设置时由于在CCMR1高8位,所以设置时需要把一些定义的16进制数左移再赋值,比较好理解,同通道3、4。

参数:

参数1:TIMx,表示选择哪个定时器

参数2:TIM_OCInitTypeDef* TIM_OCInitStruct

在这里插入图片描述

①TIM_OCMode:

在这里插入图片描述

就是对CCMR寄存器的位6:4的设置

在这里插入图片描述

②TIM_OutputState

在这里插入图片描述

对CCER寄存器位0置1,开启OC1信号输出:

在这里插入图片描述

③TIM_OutputNState()

该参数设置TIM互补输出比较状态,高级定时器 TIM1 和 TIM8 才用到

在这里插入图片描述

④TIM_Pulse

该值指定要加载到捕获比较寄存器中的脉冲值,所以这里用不到

⑤TIM_OCPolarity

设置输出极性,对CCER寄存器的位1设置

在这里插入图片描述
⑥TIM_OCNPolarity

指定互补输出极性。在高级定时器 TIM1 和 TIM8 才用到。

⑦TIM_OCIdleState

指定空闲状态期间的TIM输出比较引脚状态。在高级定时器 TIM1 和 TIM8 才用到。

⑧TIM_OCNIdleState

指定空闲状态期间的TIM输出比较引脚状态在高级定时器 TIM1 和 TIM8 才用到。

所以对于通用定时器,有用的参数为:TIM_OCMode、TIM_OutputState、TIM_OCPolarity

例:

(1)CCRE寄存器把有效电平极性设置为高电平有效,CCMR1寄存器位6:4=110,为PWM1模式时:

在这里插入图片描述设置:

	TIM_OCInitTypeDef TIM_OCInitStructure;
	 
	 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
	 TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
	 TIM_OC2Init(TIM3, &TIM_OCInitStructure);

(2)CCRE寄存器把有效电平极性设置为低电平有效,CCMR1寄存器位6:4=110,为PWM1模式时:
在这里插入图片描述设置:

	TIM_OCInitTypeDef TIM_OCInitStructure;
	 
	 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
	 TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
	 TIM_OC2Init(TIM3, &TIM_OCInitStructure);

(3)CCRE寄存器把有效电平极性设置为高电平有效,CCMR1寄存器位6:4=111,为PWM2模式时:

在这里插入图片描述设置:

	TIM_OCInitTypeDef TIM_OCInitStructure;
	 
	 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2;
	 TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
	 TIM_OC2Init(TIM3, &TIM_OCInitStructure);

(4)CCRE寄存器把有效电平极性设置为低电平有效,CCMR1寄存器位6:4=111,为PWM2模式时:
在这里插入图片描述设置:

	TIM_OCInitTypeDef TIM_OCInitStructure;
	 
	 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2;
	 TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	 TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
	 TIM_OC2Init(TIM3, &TIM_OCInitStructure);

2、修改占空比函数TIM_SetCompareX()

在这里插入图片描述

以设置通道1占空比的函数TIM_SetCompare1()为例:

在这里插入图片描述
参数:

参数1:表示哪个定时器

参数2:为自定义数,本博开头所述“阈值”来决定占空比,这个“阈值”就是与计数器目前值比较的那个数,存储在CCR寄存器中,如果对这个寄存器的值一直设置变化,则相应的输出PWM的占空比也一直变化。该寄存器是16位寄存器,所以这个值可以在0~0xffff之间取值。.

3、使能预装载寄存器TIM_OCxPreloadConfig()

以使能通道1的预装载寄存器为例:

在这里插入图片描述
参数:

第一个参数是选择哪个定时器

第二个参数:
在这里插入图片描述

是对CCMR寄存器位3操作,将该位置1

在这里插入图片描述
此时只有更新事件到来之时才给CCR寄存器里装载值(就是那个“阈值”、比较值)

四、输出比较的编程顺序

1、使能相关时钟

(1)定时器时钟使能

输出比较会用到定时器,所以定时器的时钟必须有,如使能定时器2:

在这里插入图片描述
根据搭载在哪个外设上,选用对应的使能函数:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

(2)使能复用时钟

因为GPIO正常情况下只做输入输出(个别除外),察看《STM32F103ZET6》
在这里插入图片描述

上图中【main】表示正常情况下IO口做什么,此时只需要使能对应IO时钟即可。【Default】表示除了main功能外还有其它功能,此时就需要开启复用时钟。【Remap】表示重映射,将其它IO口的功能映射到本IO上,此时需要 GPIO_PinRemapConfig设置映射关系,重映射分为部分重映射和完全重映射,根据需要映射即可。可察看《STM32F103ZET6》或者《STM32中文参考手册》:

在这里插入图片描述

2、重映射GPIO_PinRemapConfig()(如果需要

如将TIM3_CH2重映射到PB5引脚

在这里插入图片描述

上图可见是【部分重映射】

GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);

当然将TIM3_CH2重映射到PC7引脚,这里就需要【完全重映射】:

GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);

3、配置IO GPIO_Init()

使用GPIO_Init()函数设置对应IO口

4、初始化定时器、设置定时器TIM_TimeBaseInit()

STM32F103五分钟入门系列(十二)定时器中断中也总结过,使用TIM_TimeBaseInit()设置定时器

5、设置定时器相关通道PWM模式、使能对应通道输出 TIM_OCxInit()

这个本博之前总结到了,使用的库函数: TIM_OCxInit()

6、使能预装载寄存器TIM_OCxPreloadConfig()

7、使能定时器

STM32F103五分钟入门系列(十二)定时器中断中也总结过,使用TIM_Cmd()使能定时器

8、修改占空比函数TIM_SetCompareX()(如果需要

这个本博之前总结到了,使用的库函数:TIM_SetCompareX()

五、举例1+测试

1、题

题:

使用定时器3通道1输出1KHZ的脉冲,占空比为50%。

2、分析

分析:

默认状态下,通用定时器内部时钟为72MHZ,若这里采用7200预分频系数(最大65535),则计数器时钟为:72MHZ/7200=10KHZ,即每计一次数的时间为0.1ms。

重装载值决定输出PWM的周期,若输出1KHZ,则输出PWM的周期为1ms,则只需计10个数就完成一个周期,重装载一次初值,所以重装载值设置为9。

占空比为50%,所有比较值(“阈值”)为重装载值的一半,为5(0~5,和5 ~9 ~0)

在这里插入图片描述

查《STM32F103ZET6》可知,定时器3通道1为PA6的复用引脚,故不需要重映射,且最后可在PA6引脚上测得PWM输出。

PWM模式可采用PWM1,有效电平为高电平,即下图:

在这里插入图片描述

3、pwm.h编写

pwm.h文件固定格式:

#ifndef _PWM_
#define _PWM_
void PWM_Init(void);
#endif

4、pwm.c编写

(1)使能定时器时钟、使能IO时钟、使能复用时钟

在这里插入图片描述

定时器3搭载在APB1外设上,所以:

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);

(2)配置IO

	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(GPIOA, &GPIO_InitStructure);

(3)初始化定时器、设置定时器

	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_Period=10;
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);

(4)设置定时器相关通道PWM模式、使能通道

	TIM_OCInitTypeDef  TIM_OCInitStructure;
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OC1Init(TIM3,&TIM_OCInitStructure);

(5)使能预装载寄存器

 TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);

(6)使能定时器

TIM_Cmd(TIM3, ENABLE);

(7)设置占空比

可以在主函数中设置:

TIM_SetCompare1(TIM3, 5);

5、完整程序

//pwm.h
#ifndef _PWM_
#define _PWM_
void PWM_Init(void);
#endif
//pwm.c
#include "pwm.h"
#include "stm32f10x.h"
void PWM_Init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	
	TIM_TimeBaseInitStructure.TIM_Period=9;
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);

	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OC1Init(TIM3,&TIM_OCInitStructure);
	
	TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);

	TIM_Cmd(TIM3, ENABLE);
}
//main
#include "stm32f10x.h"
#include "pwm.h"
 int main(void)
 {	
	 PWM_Init();
	 TIM_SetCompare1(TIM3, 5);
	 while(1)
	 {
	 } 
 }
 

6、测试

将PA6信号线引出到示波器,其波形如下:

在这里插入图片描述

六、例2+测试

1、题

题:

接上例,使用定时器3通道1输出500HZ的脉冲,占空比为70%。不过采用PWM2模式,有效电平为高电平

2、分析

分析:

默认状态下,通用定时器内部时钟为72MHZ,若这里采用7200预分频系数(最大65535),则计数器时钟为:72MHZ/7200=10KHZ,即每计一次数的时间为0.1ms。

重装载值决定输出PWM的周期,若输出500HZ,则输出PWM的周期为2ms,则只需计20个数就完成一个周期,重装载一次初值。所以重装载值设置为19。

CCRE寄存器把有效电平极性设置为高电平有效,CCMR1寄存器位6:4=111,为PWM2模式时:

在这里插入图片描述

现已知ARR=20,t2=2ms,则要想占空比为70%,需要t1=0.6ms、CCRx=6。

故只需修改下面代码:

初始定时器:

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
	TIM_TimeBaseInitStructure.TIM_Period=19;
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);

设置定时器相关PWM模式、使能通道

	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OC1Init(TIM3,&TIM_OCInitStructure);

设置占空比:

TIM_SetCompare1(TIM3, 6);

3、完整程序

//pwm.h
#ifndef _PWM_
#define _PWM_
void PWM_Init(void);
#endif
//pwm.c
#include "pwm.h"
#include "stm32f10x.h"
void PWM_Init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	
	TIM_TimeBaseInitStructure.TIM_Period=19;
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);

	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OC1Init(TIM3,&TIM_OCInitStructure);
	
	TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
	
	TIM_Cmd(TIM3, ENABLE);
}
//main.c
#include "stm32f10x.h"
#include "pwm.h"
 int main(void)
 {	
	 PWM_Init();
	 TIM_SetCompare1(TIM3, 6);
	 while(1)
	 {
	 }
 }

4、测试

将PA6信号线引出到示波器,其波形如下:

在这里插入图片描述

七、例3—控制呼吸灯(飞线法)(+测试)

1、题

题:

使用PWM输出控制LED从亮到暗再从暗到亮循环

2、分析

分析:

采用(六)中例子的PWM,500HZ,PWM2模式、有效电平高电平,在PA6输出。

将PA6与PB5用飞线连接起来,PB5设置为浮空输入,在主函数中不断改变占空比。

注意改变占空比时,TIM_SetCompare1()函数传递的值有范围的,这个值必须小于等于重装载值。

3、完整代码

led.h代码:

//led.h
#ifndef __LED_H 
#define __LED_H	 
void LED_Init(void);	
#endif

led.c代码:

//led.c
#include "led.h"
#include "stm32f10x.h"
void LED_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	 
	GPIO_SetBits(GPIOB, GPIO_Pin_5);
}

注意上述代码的这个地方:

GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;

pwm.h和pwm.c与(六)中代码一样

main.c代码:

#include "stm32f10x.h"
#include "pwm.h"
#include "led.h"
#include "delay.h"
 int main(void)
 {	
	 u16 temp=0;
	 delay_init();
	 PWM_Init();
	 LED_Init();	
	 while(1)
	 {
		 for(temp=0;temp<20;temp++)
		 {
		  TIM_SetCompare1(TIM3, temp);
			 delay_ms(100);
		 }
	 }
	 
 }

上面代码注意for循环中,temp最大值不能超过计数器的重装载值19。

4、测试

在板子上将输出占空比变化的PWM的引脚PA6与LED0的引脚用飞线连起来,下载后效果如下:
在这里插入图片描述

示波器测一下PA6引脚的输出:

在这里插入图片描述

八、例4—控制呼吸灯(引脚映射法)+测试

1、题

题:

使用PWM输出控制LED从亮到暗再从暗到亮循环

2、分析

分析:

采用(六)中例子的PWM,500HZ,PWM2模式、有效电平高电平

察看《STM32F103ZET6》文件:

在这里插入图片描述

可以发现,定时器3通道2映射在PB5引脚上,所以可以通过TIM3_CH2 输出占空比可变的PWM即可。

察看IO的映射,《中文参考手册》:
在这里插入图片描述

发现是TIM3_CH2通过部分重映射到PB5(连接LED0的引脚)
需要注意的是PB5一定要复用输出,且一定要使能端口部分重映射。

3、完整代码

led.h代码:

//led.h
#ifndef __LED_H 
#define __LED_H	 
void LED_Init(void);	
#endif

led.c代码:

//led.c
#include "led.h"
#include "stm32f10x.h"
void LED_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	 
	GPIO_SetBits(GPIOB, GPIO_Pin_5);

}

上述代码请注意以下修改内容:

GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;

pwm.h代码:

//pwm.h
#ifndef _PWM_
#define _PWM_
void PWM_Init(void);
#endif

pwm.c代码:

//pwm.c
#include "pwm.h"
#include "stm32f10x.h"
void PWM_Init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
	
	TIM_TimeBaseInitStructure.TIM_Period=19;
	TIM_TimeBaseInitStructure.TIM_Prescaler=7200;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);

	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OC2Init(TIM3,&TIM_OCInitStructure);
	
	TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
	
	TIM_Cmd(TIM3, ENABLE);
}

上述代码请注意以下修改内容:

GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);
//...
TIM_OC2Init(TIM3,&TIM_OCInitStructure);
//...
IM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);

main.c代码:

///main.c
#include "stm32f10x.h"
#include "pwm.h"
#include "led.h"
#include "delay.h"
 int main(void)
 {	
	 u16 temp=0;
	 delay_init();
	 PWM_Init();
	 LED_Init();	
	 while(1)
	 {
		 for(temp=0;temp<20;temp++)
		 {
		  TIM_SetCompare2(TIM3, temp);
			 delay_ms(100);
		 }
	 } 
 }

上述代码请注意以下修改内容:

TIM_SetCompare2(TIM3, temp);

4、测试

下载程序后LED0显示:

在这里插入图片描述

将LED0的引脚PB5接示波器的效果:

在这里插入图片描述

标签:STM32F103,输出,定时器,TIM,寄存器,OCInitStructure,GPIO,PWM
来源: https://blog.csdn.net/Curnane0_0/article/details/119320557

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有