STM32工作笔记0063---PWM输出实验

技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152

也会用到这个STM32F103ZET6这个开发版的资料

之前我们说过右下角是输出控制,然后时钟来源是内部RC振荡器,

接下来咱们看一下PWM的工作过程.

首先要知道,对于一个向上计数来说,他是从0计数到ARR,然后再从0计数到ARR...不停循环

然后这个pwm怎么实现呢,首先对于每个通道他都有一个寄存器,捕获比较寄存器

这里举个例子,上一讲已经说了,这里,比如比较寄存器中的值是60,那么

这个时候ARR的值,当前加载值最大是100,那么如果是向上计数,那么这个时候

首先,当前加载值会小于60,然后这个时候回输出低电平,如果比60大的时候回输出高电平,这个时候

就会产生一个叫pwm波的波形,而波形的周期可以通过控制arr的值来控制,

而波的宽度,也就是低电平的宽度,可以通过比较寄存器中的值来调整.

上面这个图更明显清晰.

可以看到这里的CCRX就是当前的比较寄存器中的值,而ARR是咱们设置的加载值,然后

可以看到如果值低于CCRX输出低电平,如果高于CCRX就输出高电平,那么,这里如果ARR的值越大,那么

这个PWM的波周期越长,如果CRRX的值越大,那么低电平的宽度就越宽.

产生的就是上面的这种PWM波.

PWM的工作过程是这样的,首先CNT这个是输入的,也就是捕获的值,然后CCR1是比较寄存器中的值,

然后右边有个输出模式控制器,这个输出模式控制器,实际上通过下面的CCMR1这个寄存器来控制的,不同的设置模式也不一样

然后CNT捕获的值,和CCR1这个比较寄存器的值,比较以后会产生一个输入信号,比如,比如当CNT>CCR1的值的时候就

产生一个高电平,然后经过右边CC1P寄存器,如果是高电平的话,经过这个三角以后就会输出0,如果是低电平的话也就是0的话,就输出1,也就是上面说的高电平有效.

然后下面还有个CC1E这个寄存器是用来使能的,使能这个输出电路,让他可以输出高低电平这样. 

这里来说一下这个PWM模式1和模式2的区别,先看模式1 :
这里模式1

是说当向上计数时: 如果TIMX_CNT<TIMX_CCR的时候,通道1为有效电平,

否者通道1为无效电平.

向下计数时,TIMX_CNT>TIMX_CCR1时,通道1为无效电平,(OC1REF=0),否则通道1 为有效电平(OC1REF=1)

所以可以看出,这里只要是TIMX_CNT<TIMX_CCR,这个时候,通道1就是有效电平.

再去看看前面:

比如上面这里TIMX_CNT<TIMX_CCR这个时候,通道1为有效,这个时候如果PWM的模式设置为了模式1,也就是110的情况

下,就说,如果我这时候设置了CCER寄存器的CC1P位位0的话,那么这个时候,高电平有效,就输出高电平,因为

这个时候输出的电平首先是有效的,并且有效的时候,CC1P允许输出高电平.也就是TIMX_CNT<TIMX_CCR的时候输出高电平

如果是PWM模式2的时候,那么就是相反的.

实际上这个模式,就是设这里,比如上面画的这个是模式2哈,如果TIMX_CNT<TIMX_CCR的时候,这个时候,如果为有效的话

那么可以看到这个时候对应PWM波是,低电平,也就是低电平有效.

然后高电平就是相反的.

再看一下这个图,这里就是说,比如模式1的时候,比如这个时候ARR的值是8,这个时候CCR的值是4,那么

可以看到这个时候的PWM,也就是CNT比4小的时候,是有效,高电平,比4大的时候是无效的就是低电平.

这个PWM模式,实际上就是,脉冲宽度调制模式,可以有TIMX_ARR寄存器,产生一个确定频率,也就是确定周期,由TIMX_CCR寄存器

确定占空比,也就是由ARR的值确定PWM波的周期,由CCR这个确定占空比,也就是脉冲的宽度.

这里这个自动重载的预装载寄存器,也就是这个ARPE的值,如果设置为1的话,那么修改了ARR的值,这个时候,会立即生效

也就是说,当向上计数,计数到ARR的时候,会立即生效.

如果ARPE设置为0的话,那么,这个时候设置了ARR的值,不会立即生效,下个比较周期才会生效,也就是,比如原来我的

ARR的值是5,然后我修改成了10,那么如果这个时候ARPE的值是0,这个时候,当计数到5的时候,还是会产生溢出,

然后下一次再计数计数到5就不会产生溢出了,得是计数到10的时候才会产生溢出.

这里就是咱们说,每个定时器,有3个通道,对应的是TIM3_CH1,TIM3_CH2,TIM3_CH3,TIM3_CH4,

而且,每个通道,还可以设置部分重映射,默认比如说,TIM3_CH1通道对应PA6,PA7引脚,然后这个PA6,PA7引脚可以被映射到

PB4,PB5等

这个可以在文档中查:

这个通道的引脚是需要会查文档的.

然后看一下PWM实验的库函数配置

打开对应的代码:

可以看到:官方的库函数再STM32F10X_TIM.C文件中.

头文件中有所有的库函数定义.

首先要做一些设置:

这里首先要设置是使用哪种模式

然后:

然后再去设置,要去设置CCR1,确定哪个通道的比较值是多少,也就是当前输入的值

然后再设置,OC1M,也就是设置PWM使用哪种模式.

然后再去设置CC1P,这个,依据比较的结果,最终判断输出是高电平还是低电平.

然后设置CC1E,用来使能CCER这个寄存器,使其能工作.

然后看一下这个,输出PWM波的函数

可以看到这个TIM_OCXInit这个函数,其中这个x,可以是1,2,3,4也就是x对应的是通道,如果是1就是表示是通道1

可以看到在库函数中有TIM_OC1Init到4的这4个通道的这个库函数,可以用来输出4组PWM波

这里以TIM_OC1Init为例:

可以看到,他有几个参数,第一个是第几个定时器,

第二个是一个结构体TIM_OCInitTypeDef

可以去定义看看:

去看一下结构体的每个参数都代表的是什么意思:

注意这里我们只用到了标红色的,几个参数,第一个的PWM的模式,第二个是使能CCER的CC1E位

然后TIM_Pulse这个是当前的值CNT,也就是CCR中的值,

然后TIM_OCPolarity这个是输出极性.也就是设置CCER的CC1P位.

 

第一个是设置CCR的值,也就是比较值的函数,

第二个是使能输出比较预装载

第三个使能自动重装载的预装载寄存器允许位

第二第三,实际上对应的前面说的这两个步骤.

这个函数,再代码中对应的是,在上面的位置

 还有个重要的是通道的极性.

可以看到这里有4个设置极性的函数.

然后:可以看看

这个修改极性实际上就是修改的CCER寄存器的值.

也就是上面标志的位.

这里咱们用一个PWM波来驱动LED亮,

注意这里咱们改变的不是频率而是占空比.

其实也是可以改变频率的,只不过这里咱们改变的是占空比,不是周期,也就是CCR的值,而不是ARR的值.

比如这里,占空是,上面的横线,也就是因为高电平1的时候LED会灭,也就是说,

占空比越大,暗的时间就越长,占空比越小,也就是下面的线越长,也就是LED亮的时间就越长.

这里咱们用的是引脚PB5,也就是

用TIM3定时器的通道2输出的一个PWM波.

步骤是:

1.首先使能定时器3和IO口的时钟GPIOB的第5个引脚的时钟.

2.然后因为这里IO口不是普通的输入输出,而是作为定时器的,也就是不是MCU的输入输出,而是作为外设定时器的

  输出了,所以这里要修改,设置成端口复用.

然后,因为我们要把PB5用作PWM的输出引脚,所以这里要设置重映射,所以就需要开启AFIO时钟,重映射时钟,

为什么需要设置重映射呢>?

因为可以看到PB5,原来默认的输出中,是没有定时器,如果用的话,就需要映射到TIM3_CH2的通道2上才能用.

映射方法,就是上面说的,首先开启AFIO时钟,然后配置PB5,也就是GPIOB第5个引脚的,映射就可以了.

然后,再去初始化定时器:

然后,设置重映射以后,再去初始化定时器,

初始化定时器的时候指定,自动重装载值和预分频系数,这样就确定了

也就是确定了ARR的值以后,就确定了PWM波的周期.

然后再去5步,调用通道2的输出初始化函数.

然后再去使能预装载寄存器,实际上就是确定极性和初始化CCER寄存器,这样就把PWM波的输出规则制定好了

你好再去使能定时器7

8.然后通过不断修改CCR的值,来改变占空比.,这里用的是TIM_SetCompare2,因为用的是

通道2所以这里是TIM_SetCompare2

然后开始写函数,

这里需要写一个函数来包含1,到7步,然后在外面去设置不同的CCR来改变占空比就可以了.

我们定义一个名字叫TIM3_PWM_Init()的函数.

然后去实现:

这7个步骤.

第一步,先去使能GPIOB时钟和定时器3时钟.

然后,再去初始化这个IO口

GPIOB第5个引脚.

注意这里IO口模式要改为复用模式

然后这里,再去设置重映射就好了,AFIO寄存器已经使能了.

这里就是注意,TIM3_CH2定时器3的,通道2,可以用PB5这个引脚.

可以看到用上面的这个代码,进行部分重映射,

第一个参数是传入,哪个定时器的部分重映射,这里用定时器3,然后第二个参数是使能就好了.

然后下一步:

第4步,再去初始化定时器.

每个参数是什么意思都有说.

这里,然后再去初始化通道2

//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_OC2Init这个函数来初始化通道2.

要注意这里初始化通道2,产生PWM波的时候,

这里设置了模式2,然后设置了极性输出,然后还有失能.

注意这里,设置成模式2是什么意思呢?

当TIMX_CNT<TIMX_CCR的时候,通道为无效低电平,

也就是当TIMX_CNT>TIMX_CCR,也就是这里,当当前值,大于CCR的值的时候的时候,输出高电平.

也就是大于CCRX的值的时候,输出高电平,跟上图说的一样,所以说,如果这里

我们把CCRX的值,设置的很小的时候,上面的横线就很长,也就是占空比就挺大,

如果把CCRX的值设置的很大的时候,,占空比就很小,也就是上面的横线就很小.

初始化通道2 以后,然后就可以再去

使能预装载寄存器的值.TIM_OC2PreloadConfig(;)

这里也就是相当于设置CCR的值,第一个参数是哪个定时器,第二个参数是使能ENABLE

然后再去设置ARR的值,这个值可以使用也可以先不用设置,因为后面也是可以通过设置,

为了跟上面的步骤,保持一致,这里先不去设置.

然后再去使能这个定时器.

TIM_Cmd()

这个时候1到7步已经做完了,

然后再去外面去改变CCR的值就可以了.

可以看到这里的main.c

前面一堆设置初始化,然后去调用TIM3_PWM_Init(),一个是给的ARR的值是899,这里也就是899会+1

然后不分频.根据前面的公式就可以计算出频率

上一讲,有说到,定时器中断实验中,定时器的频率就是这样计算的,

72000 000 /900 = 80khz.

这里再看一下下面的代码:

这里咱们设置的初始值是899,那么可以看到这个dir是1,那么他就一直led0pwmval一直++,从0开始一直++

否则led0pwmval就会--, 而这里led0pwmval,最大值是300,所以这里实际上,他是

从0到300,然后再从300到0,这样来循环,上面咱们设置的模式是模式2所以,高电平的时候是占空比,前面有说也就是

,当CCR的值小,那么高电平占空比就会时间比较长,也就是LED会比较暗,如果CCR的值越大,那么占空比越小

低电平的时间就越长,那么LED也就月亮.

所以,这里我们不停的去修改占空比,所以LED的亮度会不停的变化.

下载了程序去看一下

可以看到,实际上,他的亮度是从暗慢慢的到亮,然后再从亮慢慢变暗,然后再从暗慢慢变亮...这样

这个PWM还是挺重要的,所以需要掌握.

猜你喜欢

转载自blog.csdn.net/lidew521/article/details/108286894