STM32输出比较PWM波形

Introduction

STM32定时器输出比较功能,主要用来输出PWM波形,应用在包含有电机的项目中,如智能车、机器人等;

OC(Output Compare)输出比较,可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形,每个高级定时器和通用定时器都拥有4个输出比较通道,高级定时器的前3个通道额外拥有死区生成和互补输出的功能。

在右下部分,CNT是时基单元里面的计数器;CCR是捕获/比较寄存器,它是输入捕获和输出比较共用的,当使用输入捕获时,它就是捕获寄存器,当使用输出比较时,它就是比较寄存器。请添加图片描述
红框里的电路会比较CNT和CCR的值,CNT计数自增,CCR是我们给定的一个值,当CNT>CCR、CNT<CCR、CNT=CCR时,输出端TIMx_CH1就会对应置1、置0、置1、置0,这样就可以输出一个电平不断跳变的PWM波形了。

在这里插入图片描述
PWM波形是一个数字输出信号,由高低电平组成,通过不断调整PWM波形可以等效地实现一个模拟信号的输出。比如可以使用PWM波形来实现呼吸灯的效果,通过让LED不断点亮、熄灭、点亮达到一定频率时,LED就不会闪烁而是呈现出一个中等亮度,调整点亮和熄灭的时间比例就能让LED呈现出不同的亮度。

占空比50%就是高低电平时间相等的方波,占空比20%就是高电平占20%低电平占80%。占空比决定了PWM等效出来的模拟电压大小,占空比越大等效的模拟电压就越趋近于高电平,占空比越小等效的模拟电压就越趋近于低电平,等效关系一般是线性的,比如高电平是5V,低电平是0V,那50%占空比等效于中间电压,就是2.5V。

分辨率它等于占空比变化步距,如占空比按1%、2%、3%这样的变化就是分辨率为1%。

START

在这里插入图片描述

Step1. 开启外设时钟
把要使用的外设时钟打开,RCC开启TIM和GPIO外设时钟

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

Step2. 配置GPIO
使用PA0输出PWM波形

    GPIO_InitTypeDef GPIO_Initstructure;
	GPIO_Initstructure.GPIO_Mode=GPIO_Mode_AF_PP;//配置为复用推挽输出
	GPIO_Initstructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_Initstructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_Initstructure);

Step3. 配置时基单元
配置时基单元,包括这前面的时钟源选择

    TIM_InternalClockConfig(TIM2);

    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(TIM2,&TIM_TimeBaseInitStructure);

Step4. 配置输出比较单元
配置输出比较单元,CCR的值、输出比较模式、极性选择、输出使能

    TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值函数
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//设置输出比较模式
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//设置输出比较的极性
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//设置输出使能
	TIM_OCInitStructure.TIM_Pulse=50//用来设置CCR的
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);

PWM参数计算
在这里插入图片描述
假如要产生一个频率为1Khz,占空比为50%,分辨率为1%的PWM波形
由公式可得ARR+1=100,CCR=50,PSC+1=720,CK_PSC为固定72MHz。

Step5. 开启计数器
运行控制,启动计数器

    TIM_Cmd(TIM2,ENABLE);

END

检查

void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2,Compare);//单独更改通道1CCR的值
}

调用上面函数可以改变CCR的值进而影响PWM波形占空比,由于使用A0口输出PWM波形,所以就使用A0口实现呼吸灯。
记得在main函数中初始化PWM,在while循环里面调用下面代码即可。

for(i=0;i <=100;i++)
		{
			PWM_SetCompare1(i);
		    Delay_ms(10);
	    }
		for(i=0;i <=100;i++)
		{
			PWM_SetCompare1(100-i);
		    Delay_ms(10);
	    }

Parameter selection

在stm32f10x_tim.h文件
TIM_OCInitTypeDefTIM输出比较初始化结构体定义

   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;  
    } c

TIM_OCMode

在这里插入图片描述
解释 & 说明

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

在这里插入图片描述

在这里插入图片描述
输出模式控制器的输入是CNT和CCR的大小关系,输出是REF的高低电平,输出模式可以根据下面的TIMx_CCMR1寄存器进行配置。
冻结模式,不再管CNT和CCR,直接REF保持不变,维持上一个状态,比如正在输出PWM波,突然想暂停一会儿输出,就可以设置成冻结模式,该模式下输出的高低电平也保持在暂停时刻状态不变化;
匹配时置有效电平、无效电平、电平翻转为高级定时器里说法,可以认为匹配时置有效电平就是置高电平,无效就是低电平。匹配时电平翻转可以方便地输出一个频率可调,占空比始终为50%的PWM波形。
PWM模式1可以输出频率和占空比都可调的PWM波形
在这里插入图片描述
**原因是:**CNT不断计数运行,CCR是自己设定,同时他们两个会不断比较,CCR后面是输出模式控制器。观察右上图,蓝色线是CNT的值,黄色线是ARR的值,蓝色线从0开始自增,一直增到ARR到99,之后清零继续自增,红色线是CCR,假如CCR为30,CNT<30时下面绿色为输出,它会输出高电平,CNT>30就会输出低电平。所以通过改变CCR就可以改变PWM占空比

TIM_OCPolarity

#define TIM_OCPolarity_High                ((uint16_t)0x0000)
#define TIM_OCPolarity_Low                 ((uint16_t)0x0002)
#define IS_TIM_OC_POLARITY(POLARITY) (((POLARITY) == TIM_OCPolarity_High) || \
                                      ((POLARITY) == TIM_OCPolarity_Low))

TIM_OCPolarity_High高极性,就是极性不翻转,REF波形直接输出或者说是有效电平是高电平,REF有效时,输出高电平;
TIM_OCPolarity_Low低极性,就是REF电平取反,或者说是有效电平为低电平;

TIM_OutputState

输出状态使能或者失能

#define TIM_OutputState_Disable            ((uint16_t)0x0000)
#define TIM_OutputState_Enable             ((uint16_t)0x0001)
#define IS_TIM_OUTPUT_STATE(STATE) (((STATE) == TIM_OutputState_Disable) || \
                                    ((STATE) == TIM_OutputState_Enable))

TIM_Pulse

pulse 脉冲,用来设置CCR寄存器值的
参数可以为0~FFFF之间的一个值,就是16位的范围

引脚重映射

在这里插入图片描述
在这里插入图片描述
在引脚表中可以可以看到TIM2的CH1可以从PA0挪到PA15引脚上
引脚重映射需要开启AFIO时钟,以及引脚重映射配置函数

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

在这里插入图片描述
没有重映射,PA0、PA1、PA2、PA3还是他们;
部分重映射,PA0->PA15,PA1->PB3,其他不变;
部分重映射,PA2->PB10,PA3->PB11,其他不变;
全部重映射,全部都变。
在这里插入图片描述
在stm32f10x_gpio.c里面可以看到TIM2有部分重映射1、部分重映射2和完全重映射
选择部分重映射1

GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);

还需注意PA15端口它是调试端口JTDI,如果想让PA15作为普通GPIO或者复用定时器的通道,应该先关闭调试端口复用。
在这里插入图片描述
第一个是解除NJTRST,PB4当作GPIO口使用;
第二个是解除JTAG调试端口复用,PA15、PB3、PB4变回GPIO;
第三个是解除SWD和JTAG的调试端口,PA15,14,13、PB3、PB4变回GPIO;
第三个使用有风险,使用后STLINK就无法下载程序了,这个时候只能使用串口下载程序了。

GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

总结
如果想把PA15、PB3、PB4当作GPIO使用,需要下面第一行和第三行;
如果想重映射定时器或者其他外设的复用引脚,需要下面第一行和第二行;
如果上面都想,就使用下面三行代码;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

注意调用上面程序后,GPIO初始化需要把PA0改成PA15。

同一个定时器不同通道输出PWM的特点
对于同一个定时器的不同通道输出的PWM,它们的频率,因为不同的通道是共用应该计数器的,使用他们的频率是一样的。他们的占空比由各自的CCR决定,所以占空比可以各自设定,还有他们的相位,由于计数器更新,所有PWM会同时跳变,因此他们的相位是同步的。
如果驱动多个舵机或者直流电机,使用一个定时器不同通道的PWM,就完全可以。

  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值