蓝桥杯嵌入式学习STM32之PWM生成

有个关于预装载ARPE的问题我一直没弄懂。希望未来的的我能搞明白并且回来完善这篇文章。
不过我也不是什么都没做,我找了一篇挺棒的博客,虽然看的似懂非懂,但是有点感觉了,不过让我表述出来还是不行的。
博客

其实内容很简单,控制计数器从0到ARR(预设置的值),再设置一个用来比较的值CCRx,如果比CCRx小就输出低电平,反之高电平。

从这个例子很轻松就可以看出ARR控制频率(当然是在相同的时钟条件下)
CCRx控制占空比

蓝桥杯嵌入式学习STM32之PWM生成_第1张图片


工作过程

蓝桥杯嵌入式学习STM32之PWM生成_第2张图片
CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值。
CCMR1: OC1M[2:0]位:
对于PWM方式下,用于设置PWM模式1【110】或者PWM模式2【111】
蓝桥杯嵌入式学习STM32之PWM生成_第3张图片
CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。
CCER:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。

PWM

蓝桥杯嵌入式学习STM32之PWM生成_第4张图片
蓝桥杯嵌入式学习STM32之PWM生成_第5张图片
蓝桥杯嵌入式学习STM32之PWM生成_第6张图片
本次用的是TIM3并且映射到PB5上控制LED。
蓝桥杯嵌入式学习STM32之PWM生成_第7张图片

寄存器

捕获/ 比较模式寄存器(TIMx_CCMR1~2)
捕获/比较使能寄存器(TIMx_CCER)
捕获/比较寄存器(TIMx_CCR1~4)

常用库函数

typedef struct
{
  uint16_t TIM_OCMode;  //PWM模式1或者模式2
  uint16_t TIM_OutputState; //输出使能 OR失能
  uint16_t TIM_OutputNState;
  uint16_t TIM_Pulse; //比较值,写CCRx
  uint16_t TIM_OCPolarity; //比较输出极性
  uint16_t TIM_OCNPolarity; 
  uint16_t TIM_OCIdleState;  
  uint16_t TIM_OCNIdleState; 
} TIM_OCInitTypeDef;


void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);


设置比较值函数:
void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Compare2);
使能输出比较预装载:
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
使能自动重装载的预装载寄存器允许位:
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
ARPE:
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);


配置过程

  1. 使能TIM3和IO口时钟以及AFIO时钟(重映射需要)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
  1. GPIO初始化(参考中文参考手册复用的配置)
	GPIO_InitTypeDef GPIO_InitStruct;
	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);
  1. 设置重映射
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);
  1. 时基的初始化
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period=899;
	TIM_TimeBaseInitStruct.TIM_Prescaler=0;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
  1. 比较输出的初始化
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM2;
	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_Pulse=0;
	
	TIM_OC2Init(TIM3,&TIM_OCInitStruct);
  1. 使能预装载寄存器
	TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);
  1. 使能定时器
	TIM_Cmd(TIM3,ENABLE);

补充:

delay_ms(10);
		if(t==0)
			dir=1;
		if(t>100)
			dir=0;
		
		if(dir==1)
		{
			t++;
			TIM_SetCompare2(TIM3,t);
		}
		else 
			{
				t--;
			TIM_SetCompare2(TIM3,t);
		}

心得体会

没想到这东西居然让我想了半天。
第一点:
while(1)里delay函数很重要,很重要,很重要。
不管你定时器设置周期是长是短。
定时器设置的周期只影响看上去是不是有明显的颗粒感,如果定时器时间长就很有闪烁,时间短就很丝滑。
但是没有delay函数就没有渐变的效果,占空比乱飞。
所以delay很重要,一定要加,不管什么情况。
第二点:上下拉
pwm1 pwm2选择有效使能。
然后我们再设置有效使能是高电平还是低电平。
下面结论仅限于我的观察推理,并没有理论依据:
如果有效使能是后半段,那么前半段一定是下拉的。
如果有效使能是前半段,那么后半段一定是上拉的。
麻蛋,就是这个该死的东西害我想了半天,一直在找bug,疯狂调试!!!

(2020/3/8)
第二个结论存疑,是假的!!

你可能感兴趣的:(STM32,蓝桥杯,stm32,单片机,嵌入式,蓝桥杯,PWM)