【STM32】PWM:脉冲宽度调制

这篇具有很好参考价值的文章主要介绍了【STM32】PWM:脉冲宽度调制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

注意点:

TIM_Period---->指要进行比较的值Compare

TIM_Prescaler----> 指要进行分频的值【分频值/原始时钟值】

PWM是一种周期固定,脉宽可 调整的输出波形。

​​​​​​https://www.cnblogs.com/brianblog/p/7117896.html

0.通用寄存器输出

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

1.捕获/比较通道1的主电路--中间部分

1)在程序员写入CCR1(比较值)的时候,值是不会传输到影子寄存器中的

2)影子寄存器百年直接被访问

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2.捕获/比较通道的输出部分--输出

有8种输出模式

PWM输出有两种模式:PWM1和PWM2

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

3.通用定时器输出PWM原理

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

PWM波周期或者频率由ARR(就是要进递增/递减的值)决定,PWM波占空比由CRRx决定。

4.PWM模式图解

ccr pwm,STM32,stm32,嵌入式硬件,单片机

1.定时器的PWM输出功能介绍

使用PWM波形,就可以在数字系统等效输出模拟量

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机 ccr pwm,STM32,stm32,嵌入式硬件,单片机

1)通过定时器的中断,在isr中将一个GPIO引脚电平反转,可以实现PWM输出功能【麻烦,设置多】

2)定时器附带专用的PWM输出功能,定时器那边和某一个引脚绑定,然后定时器设置好了之后内部开始+1或者-1,然后时间到了之后不是产生中断,而是直接将绑定的引脚电平反转产生PWM输出。【CPU不参与,效率高】

1.占空比:脉宽(高电平)占总周期的比例

1)可以用来调制脉冲宽度--》脉冲宽度调制

2)占空比的调节,是通过比较值与计数器的大小差距,当两者的关系改变的时,会进行电平反转。

3)占空比越大,那等效的模拟电压就越趋近于低电平​​​​​​​。占空比越小,等效的模拟电压降越趋近于高电平。

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2.PWM频率

频率越大,切换速度越快,时间段越短

ccr pwm,STM32,stm32,嵌入式硬件,单片机

3.PWM占空比和周期

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

4.PWM1  VS  PWM2

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

5.PWM参数计算

ccr pwm,STM32,stm32,嵌入式硬件,单片机

6.通用定时器-->输出比较通道

ccr pwm,STM32,stm32,嵌入式硬件,单片机

7.输出比较模式

1.冻结:相当于CNT和CCR是无效的,当我们想要在输出PWM的时候先暂停一下,就使用这个模式。

2.匹配时电平翻转:可以输出占空比50%的PWM波

3.PWM1和PWM2模式:都可以输出可调的PWM波形

ccr pwm,STM32,stm32,嵌入式硬件,单片机

 8.高级定时器-->输出比较通道

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2.专用PWM输出的实现原理

1.比较功能

1)所谓的比较原理,设计3个计数有关的寄存器:CMP(比较),CNT(计数器),ARR(存放计数原始值)

定时器有4个输出通道,每一个通道都有一个捕获/比较寄存器,将寄存器值(ARR)和计数器值(CNT)进行比较,通过比较结果输出高低电平,实现PWM信号输出。

高低电平的1和0可以进行设置

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2)在输入捕获/输出比较功能中--都要使用同一个外部引脚

ccr pwm,STM32,stm32,嵌入式硬件,单片机

3)每一个定时器只有一个计数器,但是每一个通道都有自己的捕获/比较寄存器,因此对于一个定时器来说,4路输出的PWM频率(周期)都是相同的,而不同通道的占空比可以不同。

2.相关寄存器

1.TIMx_CNT(计数器),TIMx_ARR(自动重装载寄存器),TIMx_CCRn(捕获/比较寄存器)

TIMx_CCRn:是来选择哪一条通道

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2.CCMR1,CCMR2,CCER:捕获/比较模式寄存器的基本配置

CCMR1:处理了通道1和通道2

CCMR2:处理了通道3和通道4

CCER:配置要什么电平才是有效的

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

3.CR1,CR2,PSC

CR1,CR2:使能,开关

PSC:分频功能

3.标准库中相关的API

1.TIM_TimeBaseInit

定时器的基本初始化,包括要进行分频的频率,计数个数

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
  uint16_t tmpcr1 = 0;

  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx)); 
  assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
  assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));

  tmpcr1 = TIMx->CR1;  

  if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||
     (TIMx == TIM4) || (TIMx == TIM5)) 
  {
    /* Select the Counter Mode */
    tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;
  }
 
  if((TIMx != TIM6) && (TIMx != TIM7))
  {
    /* Set the clock division */
    tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;
  }

  TIMx->CR1 = tmpcr1;

  /* Set the Autoreload value */
  //要计数的值
  TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;
 
  /* Set the Prescaler value */
  //预分频参数
  TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;
    
  if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17))  
  {
    /* Set the Repetition Counter value */
    TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
  }

  /* Generate an update event to reload the Prescaler and the Repetition counter
     values immediately */
     //预分频器参数的改变
  TIMx->EGR = TIM_PSCReloadMode_Immediate;           
}

2.TIM_OC1Init(TIM_OCnInit)

TIM_OCn--->指的使用了哪一个通道

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)
{
  uint16_t tmpccmrx = 0, tmpccer = 0, tmpcr2 = 0;
   
  /* Check the parameters */
  assert_param(IS_TIM_LIST8_PERIPH(TIMx));
  assert_param(IS_TIM_OC_MODE(TIM_OCInitStruct->TIM_OCMode));
  assert_param(IS_TIM_OUTPUT_STATE(TIM_OCInitStruct->TIM_OutputState));
  assert_param(IS_TIM_OC_POLARITY(TIM_OCInitStruct->TIM_OCPolarity));   
 /* Disable the Channel 1: Reset the CC1E Bit */
  TIMx->CCER &= (uint16_t)(~(uint16_t)TIM_CCER_CC1E);
  /* Get the TIMx CCER register value */
  tmpccer = TIMx->CCER;
  /* Get the TIMx CR2 register value */
  tmpcr2 =  TIMx->CR2;
  
  /* Get the TIMx CCMR1 register value */
  tmpccmrx = TIMx->CCMR1;
    
  /* Reset the Output Compare Mode Bits */
  tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR1_OC1M));
  tmpccmrx &= (uint16_t)(~((uint16_t)TIM_CCMR1_CC1S));

  /* Select the Output Compare Mode */
  tmpccmrx |= TIM_OCInitStruct->TIM_OCMode;
  
  /* Reset the Output Polarity level */
  tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC1P));
  /* Set the Output Compare Polarity */
  tmpccer |= TIM_OCInitStruct->TIM_OCPolarity;
  
  /* Set the Output State */
  tmpccer |= TIM_OCInitStruct->TIM_OutputState;
    
  if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)||
     (TIMx == TIM16)|| (TIMx == TIM17))
  {
    assert_param(IS_TIM_OUTPUTN_STATE(TIM_OCInitStruct->TIM_OutputNState));
    assert_param(IS_TIM_OCN_POLARITY(TIM_OCInitStruct->TIM_OCNPolarity));
    assert_param(IS_TIM_OCNIDLE_STATE(TIM_OCInitStruct->TIM_OCNIdleState));
    assert_param(IS_TIM_OCIDLE_STATE(TIM_OCInitStruct->TIM_OCIdleState));
    
    /* Reset the Output N Polarity level */
    tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC1NP));
    /* Set the Output N Polarity */
    tmpccer |= TIM_OCInitStruct->TIM_OCNPolarity;
    
    /* Reset the Output N State */
    tmpccer &= (uint16_t)(~((uint16_t)TIM_CCER_CC1NE));    
    /* Set the Output N State */
    tmpccer |= TIM_OCInitStruct->TIM_OutputNState;
    
    /* Reset the Output Compare and Output Compare N IDLE State */
    tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS1));
    tmpcr2 &= (uint16_t)(~((uint16_t)TIM_CR2_OIS1N));
    
    /* Set the Output Idle state */
    tmpcr2 |= TIM_OCInitStruct->TIM_OCIdleState;
    /* Set the Output N Idle state */
    tmpcr2 |= TIM_OCInitStruct->TIM_OCNIdleState;
  }
  /* Write to TIMx CR2 */
  TIMx->CR2 = tmpcr2;
  
  /* Write to TIMx CCMR1 */
  TIMx->CCMR1 = tmpccmrx;

  /* Set the Capture Compare Register value */
  TIMx->CCR1 = TIM_OCInitStruct->TIM_Pulse; 
 
  /* Write to TIMx CCER */
  TIMx->CCER = tmpccer;
}

3.TIM_OCInitTypeDef:OC的结构体

typedef struct
{
//选择TIM的模式:PWM1或者PWM2
  uint16_t TIM_OCMode;        /*!< Specifies the TIM mode.
                                   This parameter can be a value of @ref TIM_Output_Compare_and_PWM_modes */
//选择TIM的输出状态:向上/向下
  uint16_t TIM_OutputState;   /*!< Specifies the TIM Output Compare state.
                                   This parameter can be a value of @ref TIM_Output_Compare_state */

  uint16_t TIM_OutputNState;  /*!< Specifies the TIM complementary Output Compare state.
                                   This parameter can be a value of @ref TIM_Output_Compare_N_state
                                   @note This parameter is valid only for TIM1 and TIM8. */
//要进行比较的值:Compare值
  uint16_t TIM_Pulse;         /*!< Specifies the pulse value to be loaded into the Capture Compare Register. 
                                   This parameter can be a number between 0x0000 and 0xFFFF */
//输出的极性
  uint16_t TIM_OCPolarity;    /*!< Specifies the output polarity.
                                   This parameter can be a value of @ref TIM_Output_Compare_Polarity */

  uint16_t TIM_OCNPolarity;   /*!< Specifies the complementary output polarity.
                                   This parameter can be a value of @ref TIM_Output_Compare_N_Polarity
                                   @note This parameter is valid only for TIM1 and TIM8. */

  uint16_t TIM_OCIdleState;   /*!< Specifies the TIM Output Compare pin state during Idle state.
                                   This parameter can be a value of @ref TIM_Output_Compare_Idle_State
                                   @note This parameter is valid only for TIM1 and TIM8. */

  uint16_t TIM_OCNIdleState;  /*!< Specifies the TIM Output Compare pin state during Idle state.
                                   This parameter can be a value of @ref TIM_Output_Compare_N_Idle_State
                                   @note This parameter is valid only for TIM1 and TIM8. */
} TIM_OCInitTypeDef;

1.TIM_OCMode:选择TIM的模式

选择PWM1或者PWM2

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2.TIM_OutputState:选择输出状态

选择输出的状态:enable/able

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

3.TIM_Pulse:输入要进行比较的值(Compare)

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

4.TIM_OCPolarity:设置输出极性

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

4.TIM_OC1PreloadConfig

作用:TIM_CCMRx寄存器OCxPE位使能相应的预装在寄存器【这个预装载的值是比较值】

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload)
{
  uint16_t tmpccmr1 = 0;
  /* Check the parameters */
  assert_param(IS_TIM_LIST8_PERIPH(TIMx));
  assert_param(IS_TIM_OCPRELOAD_STATE(TIM_OCPreload));
  tmpccmr1 = TIMx->CCMR1;
  /* Reset the OC1PE Bit */
  tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC1PE);
  /* Enable or Disable the Output Compare Preload feature */
  tmpccmr1 |= TIM_OCPreload;
  /* Write to TIMx CCMR1 register */
  TIMx->CCMR1 = tmpccmr1;
}

6.TIM_ClearOC1Ref

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear)
{
  uint16_t tmpccmr1 = 0;
  /* Check the parameters */
  assert_param(IS_TIM_LIST3_PERIPH(TIMx));
  assert_param(IS_TIM_OCCLEAR_STATE(TIM_OCClear));

  tmpccmr1 = TIMx->CCMR1;

  /* Reset the OC1CE Bit */
  tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC1CE);
  /* Enable or Disable the Output Compare Clear Bit */
  tmpccmr1 |= TIM_OCClear;
  /* Write to TIMx CCMR1 register */
  TIMx->CCMR1 = tmpccmr1;
}

7.TIM_OC1PolarityConfig

void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity)
{
  uint16_t tmpccer = 0;
  /* Check the parameters */
  assert_param(IS_TIM_LIST8_PERIPH(TIMx));
  assert_param(IS_TIM_OC_POLARITY(TIM_OCPolarity));
  tmpccer = TIMx->CCER;
  /* Set or Reset the CC1P Bit */
  tmpccer &= (uint16_t)~((uint16_t)TIM_CCER_CC1P);
  tmpccer |= TIM_OCPolarity;
  /* Write to TIMx CCER register */
  TIMx->CCER = tmpccer;
}

8.TIM_CtrlPWMOutputs

高级定时器专用的

ccr pwm,STM32,stm32,嵌入式硬件,单片机

9.TIM_SetComparex

设置TIMx Capture Compare1寄存器值-->通过设置参数值可以修改PWM的占空比

ccr pwm,STM32,stm32,嵌入式硬件,单片机

10.TIM_OCStructInit

用默认值填充每个TIM_OCInitStruct成员。因为我们给定时器初始化的时候,并不是整个都进行赋值,后面可能会出现错误,所以我们需要在设置我们定时器需要的值之前先初始化全部参数。

ccr pwm,STM32,stm32,嵌入式硬件,单片机

4.GPIO引脚和PWM的对应关系

STM32F103中文教程及参考手册.pdf · 林何/STM32F103C8 - 码云 - 开源中国 (gitee.com)

在AFIO中进行查找

没有重映像:表示默认接入的io口

完全重映像:如果使用这个则要调用函数进行声明【GPIO_PinRemapConfig】

ccr pwm,STM32,stm32,嵌入式硬件,单片机

5.TIM2的专用PWM输出编程实践

ccr pwm,STM32,stm32,嵌入式硬件,单片机

1.官方示例代码

我们使用的是TIM3,因为我们复用了GPIOA,所以要去AFIO中去查找TIM3对应的关系

ccr pwm,STM32,stm32,嵌入式硬件,单片机

#include "pwm.h"
#include "led.h"

//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM1_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);			// 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  		//使能GPIO外设时钟使能
	                                                                     	
	//设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; 						//TIM_CH1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  				//复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	TIM_TimeBaseStructure.TIM_Period = arr; 						//设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 80K
	TIM_TimeBaseStructure.TIM_Prescaler =psc; 						//设置用来作为TIMx时钟频率除数的预分频值  不分频
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 					//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;		//TIM向上计数模式
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); 				//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; 				//选择定时器模式:TIM脉冲宽度调制模式2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//比较输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;								//设置待装入捕获比较寄存器的脉冲值
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 		//输出极性:TIM输出比较极性高
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);  						//根据TIM_OCInitStruct中指定的参数初始化外设TIMx

	TIM_CtrlPWMOutputs(TIM1,ENABLE);								//MOE 主输出使能	

	TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  				//CH1预装载使能	 
	
	TIM_ARRPreloadConfig(TIM1, ENABLE); 							//使能TIMx在ARR上的预装载寄存器
	
	TIM_Cmd(TIM1, ENABLE);  										//使能TIM1
}

2.代码移植

我们先去查看我们进行操作的TIM2对应应该复用哪一个AFIO引脚

ccr pwm,STM32,stm32,嵌入式硬件,单片机

可知TIM2的通道1对于的没有重映像是PA0

ccr pwm,STM32,stm32,嵌入式硬件,单片机

#include "stm32f10x.h"                  // Device header
/**
	使用TIM2的Channel1,无重映射时对应PA0引脚,在原理图上对应P1.0
*/

void pwm_init(void);


int main(){
	
	pwm_init(); //频率是2Kh
	return 0;
}
 
void pwm_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;   //声明一个结构体变量,用来初始化GPIO

	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//声明一个结构体变量,用来初始化定时器

	TIM_OCInitTypeDef TIM_OCInitStructure;//根据TIM_OCInitStruct中指定的参数初始化外设TIMx

	/* 开启时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

	/*  配置GPIO的模式和IO口 */
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure);		// GPA15,



	// time = CNT/fHz = 9000/72000000s
	// Fpwm = 1/T = 72000000/9000Hz = 8000Hz = 8KHz
	//TIM3定时器初始化
	TIM_TimeBaseInitStructure.TIM_Period = 9000 - 1;	   //不分频,PWM 频率=72000/900=8Khz//设置自动重装载寄存器周期的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 0;//设置用来作为TIMx时钟频率预分频值,100Khz计数频率
	TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;	//TIM向上计数模式
	TIM_TimeBaseInit(TIM2, & TIM_TimeBaseInitStructure);

	// 将TIM2的输出引脚进行fll remap到PA15,也就是P3.7
	//GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);


	//PWM初始化	  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//PWM输出使能
	//TIM_OCInitStructure.TIM_Pulse = 4500 - 1;
	//TIM_Pulse:设置占空比【占了1/3==3000/9000】
	TIM_OCInitStructure.TIM_Pulse = 3000 - 1;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

	TIM_OC1Init(TIM2,&TIM_OCInitStructure);

	TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
	
	TIM_Cmd(TIM2,ENABLE);//使能或者失能TIMx外设
}







ccr pwm,STM32,stm32,嵌入式硬件,单片机

6.通用定时器PWM输出实验配置步骤

1.具体步骤

1.初始化时钟

2.初始化定时器

3.配置Oc部分

4.使能定时器

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2.相关HAL库函数介绍

ccr pwm,STM32,stm32,嵌入式硬件,单片机

 ccr pwm,STM32,stm32,嵌入式硬件,单片机

3.条件分析

ccr pwm,STM32,stm32,嵌入式硬件,单片机

1.查看相关的原理分析引脚的连接

1)如果相关的开发版原理图上有led对应的引脚与定时器的通道相对应则直接使用(无论是复用GPIO还是重映射)

例如下面这种情况,就是开发板上led对应PB5,而PB5的重映射功能上有定时器的相关通道

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2)如果相关的开发板上没有对应的,则直接找一个相关的定时器接口(比如stm32f103C8T5对应的

ccr pwm,STM32,stm32,嵌入式硬件,单片机

7.PWM驱动LED呼吸灯

1.硬件接线

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2.代码编写

1.初始化注意点

1)注意点:我们在对定时器结构体赋值的时候,并不是给全部变量进行赋值,所以这个值是局部变量,所以如果我们初始化没有全部赋值,则需要在最前面对结构体初始一个默认值

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2)决定输出PWM的周期和占空比(ARR【Period】,PSC【Prescaler】,Pulse【CCR】)

ccr pwm,STM32,stm32,嵌入式硬件,单片机

3)我们的PWM需要通过一个GPIO引脚输出出去,所以我们需要对应引脚定义表,查看该定时器,对应是哪一个GPIO引脚。

ccr pwm,STM32,stm32,嵌入式硬件,单片机

ccr pwm,STM32,stm32,嵌入式硬件,单片机

4)为什么GPIO引脚使用复用推挽输出?

我们使用的GPIO设置高低电平(占空比)的大小,所以是输出模式。

如果使用定时器则需要使用复用开漏/推挽输出模式。输出控制权将转移给片上外设,这里的片上外设引脚连接的就是TIM2的CH1通道,所以只有将GPIO设置为复用推挽输出,引脚的控制器才可以交给片上外设,PWM波形才可以通过引脚输出,引脚的控制器才能交给片上外设,PWM波形才能通过引脚输出。

ccr pwm,STM32,stm32,嵌入式硬件,单片机

2.初始化函数

/**
  * 函    数:PWM初始化
  * 参    数:无
  * 返 回 值:无
  */
void PWM_Init(void)
{
	/*开启时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
	

	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA0引脚初始化为复用推挽输出	
																	//受外设控制的引脚,均需要配置为复用模式		
	
	/*配置时钟源*/
	TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
	
	/*时基单元初始化*/
	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);             //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
	
	/*输出比较初始化*/
	TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量
	TIM_OCStructInit(&TIM_OCInitStructure);							//结构体初始化,若结构体没有完整赋值
																	//则最好执行此函数,给结构体所有成员都赋一个默认值
																	//避免结构体初值不确定的问题
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式,选择PWM模式1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//输出极性,选择为高,若选择极性为低,则输出高低电平取反
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);						//将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1
	
	/*TIM使能*/
	TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}

3.PSC,ARR,CCR值的计算

我们想要产生一个频率为1KHZ,占空比为50%,分辨率为1%的PWM

ccr pwm,STM32,stm32,嵌入式硬件,单片机

	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;					//计数周期,即ARR的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;				//预分频器,即PSC的值
	TIM_OCInitStructure.TIM_Pulse = 50;								//初始的CCR值

4.修改CCR的值(修改占空比)

/**
  * 函    数:PWM设置CCR
  * 参    数:Compare 要写入的CCR的值,范围:0~100
  * 返 回 值:无
  * 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比
  *           占空比Duty = CCR / (ARR + 1)
  */
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2, Compare);		//设置CCR1的值
}

5.main

uint8_t i;			//定义for循环的变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	PWM_Init();			//PWM初始化
	
	while (1)
	{
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(i);			//依次将定时器的CCR寄存器设置为0~100,PWM占空比逐渐增大,LED逐渐变亮
			Delay_ms(10);				//延时10ms
		}
		for (i = 0; i <= 100; i++)
		{
			PWM_SetCompare1(100 - i);	//依次将定时器的CCR寄存器设置为100~0,PWM占空比逐渐减小,LED逐渐变暗
			Delay_ms(10);				//延时10ms
		}
	}
}

6.AFIO使用

	/*GPIO重映射*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);			//开启AFIO的时钟,重映射必须先开启AFIO的时钟
	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);			//将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);		//将JTAG引脚失能,作为普通GPIO引脚使用

8.同一个定时器使用多个通道输出多道PWM通道

1)频率相同:对于同一个定时器的不同通道输出的PWM,因为不同通道是共用一个计数器,所以频率应该是相同的。

2)占空比不同:占空比由各自CCR决定

3)相位相同:由于计数器更新,所有PWM同时跳变,所以相位是同步的。

4)如果驱动多个舵机或者直流电机,使用同一个定时器不同通道的PWM即可。

ccr pwm,STM32,stm32,嵌入式硬件,单片机文章来源地址https://www.toymoban.com/news/detail-835825.html

到了这里,关于【STM32】PWM:脉冲宽度调制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32定时器输出PWM脉冲

    一、什么是PWM脉冲? PWM (Pulse Width Modulation) 脉冲宽度调制,通常应用于惯性系统中,( 不是不能即停的设备,因为如果设备不具有关心,那么运动是断断续续的,不具有连续性 ),通过脉宽调节输出不同的波形作用域受控对象。 二、 PWM中三个重要的参数 1.频率=1/Ts ;这个很

    2024年02月15日
    浏览(54)
  • STM32精准脉冲数PWM生成方法解答

    本文介绍了在STM32上生成精准脉冲数PWM的方法,包括使用定时器中断法和两个定时器结合产生PWM脉冲的方法。详细讨论了定时器的配置和工作原理,以及如何通过定时器控制脉冲的个数和周期。通过示例代码和硬件仿真,展示了如何实现精准的脉冲数PWM输出。

    2024年02月03日
    浏览(40)
  • 基于STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的PWM(脉冲宽度调制)应用

    STC12C5A60S2系列1T 8051单片机辅助寄存器AUXR PCA辅助寄存器AUXR1 作用:用来设置STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块的单片机引脚 PCA工作模式寄存器CMOD 作用:用来设置STC12C5A60S2系列1T 8051单片机可编程计数阵列CCP/PCA/PWM模块以下功能 (1)、空闲情况下是否停止

    2024年02月08日
    浏览(49)
  • 12.[STM32]PWM脉宽调制-舵机控制(一篇足以)

    🍌 🍌🍌 作者简介:大家好啊,我叫DW,每天分享一些我新学到的知识,期待和大家一起进步 🍋 🍋🍋 系列专栏: STM32 🍎 🍎🍎 🍎🍎🍎 🌞小实验目标:控制舵机旋转🌞 🍊如有写得不好的地方欢迎大家指正🍊 创作时间:🍊🍊🍊2022年5月2日🍊🍊🍊 在机器人机电控

    2023年04月15日
    浏览(40)
  • (STM32)PWM输出控制电机旋转并且使用编码器读取脉冲数

    目录  前言 一、pwm输出让电机转  1.电机的接线说明 2.驱动的接线说明 3.pwm输出代码  pwm.c pwm.h 4.输出pwm控制电机旋转 二、配置定时器编码器模式 1.定时器编码器模式 编码器原理 编码器相关的概念 2.编码器模式——代码部分 3.获取脉冲数 三、定时读取编码器读取的脉冲数

    2024年02月03日
    浏览(58)
  • STM32主从模式实现两路同步PWM脉冲输出,频率、占空比可调

    原理:定时器1为主模式,定时器8为从模式,TIM1的定时器使能操作作为触发输出[TRGO]触发TIM8并使能TIM8的计数器,同时输出两路频率、占空比以及脉冲数量(小于256个,高级定时器重复计数功能为8位)可调PWM波形。 关键代码: 定时器1(TIM1)设为主模式: 定时器2(TIM8)设为从

    2024年02月13日
    浏览(42)
  • 步进电机简单使用:STM32 PWM输出固定数目的脉冲数(基于CubeMX)

    使用步进电机之前,我们需要了解步距角的概念:步进电机接收到一个脉冲转动的角度,步进电机步距角通常 为1.8°,即步进电机接收到一个脉冲转动1.8°,则若步进电机接收到360°/1.8°=200个脉冲,步进电机就能转动一圈 步进电机通过驱动器控制,驱动器如下图所示(都比较

    2024年02月06日
    浏览(45)
  • STM32 PWM模式与输出比较模式的区别。PWM占空比不生效,在STM32CubeMX中配置PWM的两种模式——蓝桥杯嵌入式

      🎊【蓝桥杯嵌入式】专题正在持续更新中,原理图解析✨,各模块分析✨以及历年真题讲解✨都已更新完毕,欢迎大家前往订阅本专题🎏 🎏【蓝桥杯嵌入式】蓝桥杯第十届省赛真题 🎏【蓝桥杯嵌入式】蓝桥杯第十二届省赛程序真题 🎏【蓝桥杯嵌入式】蓝桥杯第十三届

    2023年04月15日
    浏览(80)
  • 【STM32F429】HAL库的PWM中断,精确控制脉冲数,控制步进电机

    这两天在调步进电机,希望是使得步进电机每次都达到期望的高度。在查了一天的资料,发现大部分上传的资料都是使用CubeMX生成的,可复制性很高,但未免有失可读性,故上传我的心得经验。 本来原子哥的例程里有整合度很高的,已经封装好的精确控制步进电机前进距离的

    2024年02月08日
    浏览(53)
  • 嵌入式-stm32-用PWM点亮LED实现呼吸灯

    答:LED需要低电平才能亮,高电平是灯灭。 答:这是用到不同占空比来实现的,控制LED实现呼吸灯,就是通过占空比的高低电平和其持续时间来实现。 ①例如,要定时500ms,则:PSC=7199,ARR=4999,Tclk=72Mhz。 ②假如频率为 2kHz ,则:PSC=71,ARR=499, 频率和周期是描述波形的两个基

    2024年02月03日
    浏览(98)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包