新手必看!!附源码!!STM32通用定时器-比较输出PWM


  

一、什么是PWM?

   PWM(脉冲宽度调制)是一种用于控制电子设备的技术。它通过调整信号的脉冲宽度来控制电压的平均值。PWM常用于调节电机速度、控制LED亮度、产生模拟信号等应用。

二、PWM的原理

   PWM的基本原理是通过以一定频率产生的脉冲信号,通过调整脉冲的宽度(占空比)来模拟电压的不同电平。占空比是指脉冲高电平的时间占整个周期的比例。通过调整占空比,可以在输出端产生不同的电平,从而实现对电机、LED等设备的精确控制。

   例如,对于一个50%占空比的PWM信号,脉冲的高电平时间占整个周期的一半,这将导致输出电平的平均值为一半的电压。通过调整占空比,你可以在0%到100%的范围内控制输出电平的变化。

三、PWM模式以及输出PWM原理

ARR: 自动重装载寄存器的值。
CCRx: 捕获/比较寄存器的值。

PWM波周期或频率由ARR决定,PWM波占空比由CCRx决定

(1)PWM模式1
在向上计数时,一旦CNT<CCRx 时输出为有效电平,否则为无效电平。
在向下计数时,一旦CNT>CCRx 时输出为无效电平,否则为有效电平。

如:
在这里插入图片描述
当CNT < CCRx,IO输出1。
当CNT >= CCRx,IO输出0。

在这里插入图片描述
当CNT <=CCRx,IO输出1。
当CNT > CCRx,IO输出0。

(2)PWM模式2
在向上计数时,一旦CNT>CCRx 时输出为有效电平,否则为无效电平。
在向下计数时,一旦CNT<CCRx 时输出为无效电平,否则为有效电平。
如:
在这里插入图片描述当CNT < CCRx,IO输出0。
当CNT >= CCRx,IO输出1。
在这里插入图片描述
当CNT <= CCRx,IO输出0。
当CNT > CCRx,IO输出1。

四、PWM极性设置

当极性为高 (TIM_OCPolarity_High) 时,不进行反相。即按pwm模式正常的去进行比较与输出。
当极性为低 (TIM_OCPolarity_Low) 时,输出通道在比较匹配时为低电平,相当于对输出信号进行反相。

如:pwm模式1向上计数。
设置高极性:当CNT < CCRx,IO输出1。 当CNT >= CCRx,IO输出0。
设置低极性:当CNT < CCRx,IO输出0。 当CNT >= CCRx,IO输出1。

五、复用与映射

在这里插入图片描述
如:利用引脚来使用定时器功能时,需要进行复用与映射操作。
   我们利用引脚来使用芯片内一些外设的功能时,需要打开GPIO的复用功能。打开复用功能后,可以对应很多的外设模块,那么我们如何确定使用哪个外设模块呢?这时就需要用到映射功能。如将PA0映射到TIM5的CH1。这时就可以利用PA0来使用定时器功能了。

在这里插入图片描述

GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3 ,ENABLE );    //重映射--部分重映射
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3 ,ENABLE );       //重映射--完全重映射

   配置过程:①打开定时器、GPIO、和AFIO的时钟。②使用上面的代码进行重映射。③配置GPIO的各功能、定时器的各功能。④使能定时器。

举例:使用定时器3的部分重映射。

#include "stm32f10x.h"                  // Device header

void PWM_remapGPIO_Init(uint16_t ARR,uint8_t psc)
{
	GPIO_InitTypeDef PWM_GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_OCInitTypeDef TIM_OCInitStruct;
	//1. 打开定时器、GPIO、和AFIO的时钟。
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	//2.使用上面的代码进行重映射。
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//选则TIM3部分重映像
	
	//  3· GPIO功能配置
	PWM_GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
	PWM_GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
	PWM_GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&PWM_GPIO_InitStruct);
	
	//3·配置定时器功能
	TIM_TimeBaseInitStruct.TIM_ClockDivision = 0;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = ARR;
	TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
	
	//3·设置TIM3_CH2的PWM模式,使能TIM3的CH2输出
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;//设置定时器模式:PWM2模式
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
	TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High;
	TIM_OC2Init(TIM3,&TIM_OCInitStruct);
	
	TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能TIM3重载CCR2上的预装载寄存器
	
	// 4. 使能定时器。
	TIM_Cmd(TIM3,ENABLE);
}


六、配置PWM输出实验步骤

实验内容:将PC6复用为TIM3通道1,用于输出pwm。注:stm32的pwm输出引脚是使用的IO口的复用功能。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

(1)具体代码1–寄存器:

    void PWM_Init_TIM3_CH1(u16 ccr)
{
	//1.初始化PC6引脚
	RCC->AHB1ENR |=(0x01 <<2); //开启GPIOC的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);  //开启AFIO时钟
	AFIO->MAPR |=(0x03 <<10); //定时器3 完全重映射
	
    GPIOC->CRL &= 0XF0FFFFFF;//PC6清0
    GPIOA->CRL |= 0X0B000000;//复用功能输出(推挽50MHz输出)
      	
	//2.初始化基本定时器配置
	RCC->APB1ENR |= 1 << 1;      //使能TIM3时钟 
	TIM3->SMCR &=~(0x07 << 0);   //选择内部时钟源
	TIM3->CR1 &=~(0x03<<5);  //边沿对齐
	TIM3->CR1 &=~(0X01<<4); //设置为向上计数模式
	TIM3->CR1 |=(0x01 <<7);   //有影子,缓冲。
	
	TIM3->ARR = 99;//设定计数器主动重装值(决定PWM的频率)
	TIM3->PSC = 7199;//预分频器 0为不分频  
	
	//3.初始化输出通道
	TIM3->CCR1 =ccr;   //写入比较值
	TIM3->CCMR1 &=~(0x03 << 0) ;    //通道配置为输出功能
	TIM3->CCMR1 |=(0x01 << 3);    //有影子
	TIM3->CCMR1 &=~(0x01 <<7);    //OC1Ref不受ETRF输入影响。
	TIM3->CCMR1 &= ~0x07 <<4; 
	TIM3->CCMR1 |=(0x06 <<4); //PWM模式1
	
	TIM3->CCER &=~(0x01 <<1); //实际波形=参考波形。 不反相
	TIM3->CCER  |= (0x01 << 0);//输入/捕获1输出使能
	TIM3->EGR |=(0x01 <<0); //产生更新事件,将上面配置更新到影子寄存器
	TIM3->CR1 |= (0X01 << 0);//使能定时器3    
}

主函数:

int main()
{
  //pwm范围为0-ARR。 高低电平随着pwm模式不同而不同。
  //如比较值为90,pwm模式1向上计数,低于比较值90时,为高电平。
   PWM_Init_TIM3_CH1(90);  
   while(1)
  {
  
   }

}

(2)具体代码2–库函数(不进行重映射)


void Motor_PWM_Init(u16 arr,u16 psc)
{
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;  //时间基 结构体变量
	GPIO_InitTypeDef GPIO_InitStruct;								//GPIO初始化 结构体变量
	TIM_OCInitTypeDef TIM_OCInitStruct;							//通道初始化 结构体变量
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //使能TIM1定时器时钟线
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//使能GPIOA时钟线
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;  //这里跟TIM3 产生PWM波功能无关
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计时模式
	TIM_TimeBaseInitStruct.TIM_Period = arr;    //计算到1000 那就是定时10ms
	TIM_TimeBaseInitStruct.TIM_Prescaler = psc;  //最高频率72MHZ  这里定义 预分频720 																					 
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);//初始化函数 让刚刚配置的参数 输入到对应寄存器里面
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //GPIO采用复用推挽输出模式
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //TIM1同时产生两路PWM波 在管脚a8 a11
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  //GPIO速度50MHZ
	GPIO_Init(GPIOA,&GPIO_InitStruct);  //初始化函数 让刚刚配置的参数 输入到对应寄存器里面
	
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //PWM1模式
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性高
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//让捕获/比较寄存器使能
	TIM_OCInitStruct.TIM_Pulse = 0;  //初始化占空比0   占空比可以依照TIM_Period进行配置 在它范围内就好了
	
	TIM_OC1Init(TIM3,&TIM_OCInitStruct); //初始化函数 让刚刚配置的参数 输入到对应寄存器里面
	TIM_OC2Init(TIM3,&TIM_OCInitStruct); //初始化函数 让刚刚配置的参数 输入到对应寄存器里面
	
	TIM_Cmd(TIM3,ENABLE);    //使能定时器TIM1
	TIM_CtrlPWMOutputs(TIM3,ENABLE);  //确定让TIM1输入PWM
	
	TIM_OC1PreloadConfig(TIM3,ENABLE);  //让捕获/比较1寄存器 预装载功能使能 同时配置CC1通道为输出
	TIM_OC2PreloadConfig(TIM3,ENABLE); //让捕获/比较1寄存器 预装载功能使能 同时配置CC4通道为输出
	
	TIM_ARRPreloadConfig(TIM3,ENABLE);  //自动重装载预装载允许
}

主函数:

u16 dir=1;
u16 ledpwm=100;
int main(void)
{
	
    led_int();
	delay_init(); //延时函数初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设 置 NVIC 中 断 分 组 2
    Motor_PWM_Init(899,0);
    uart1_init(115200);
	while(1)
	{	 
		delay_ms(2);
		 if(dir)
		 {
			 ledpwm++;
		 }
		 else
		 {		 
			 ledpwm--;
		 }
		 if(ledpwm>900)
			  dir=0;
		 if(ledpwm==0)
			  dir=1; 
		 TIM_SetCompare1(TIM3,ledpwm);
	}
 }

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值