07:HAL------通用定时器功能(输出比较PWM)

前言:

        下面的以通用定时器为例,当然高级定时器具有通用定时器的全部功能

 灰色部分为我们的输入捕获部分,下节说

一:TIM输出比较功能

1: 简历

        OC(Output Compare)输出比较

        输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形

         每个高级定时器和通用定时器都拥有4个输出比较通道

        高级定时器的前3个通道额外拥有死区生成和互补输出的功能

2:PWM波形

        PWM(Pulse Width Modulation)脉冲宽度调制

        在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域

        PWM参数:      频率 = 1 / TS            占空比 = TON / TS           分辨率 = 占空比变化步距

 

 

3:输出比较模式

CCR输出比较寄存器:CCR1,CCR2, CCR3,CCR4

        有/无效状态由TIMx_CCER决定 CCxP=0:OCx高电平有效 ;CCxP=1:Ocx低电平有效

4:参数计算

条件:向上或者向下计数,有效电平为高电平3个公式全部符合。

中央计数:有效电平为高电平,只符合占空比的公式。

5:PWM基本结构

 6:HAL库配置

要产生pwm必须使能计数器 

7:HAL库函数


二:代码

定时器的功能

A:PWM驱动LED呼吸灯

下面的这个公式是周期的计算

 使用TIM3的通道2,可以看到它复用的PA7上

 我们在配置pwm模式的时候选择的是低电频有效,所以LED的负极连接——PA7;正极连接电源

#include "stm32f1xx_hal.h"


TIM_HandleTypeDef TIM_HandleTIMCH3;
void TIM3_CH2_init(uint16_t psc,uint16_t arr)
{
	TIM_OC_InitTypeDef TIM_OC_Init={0};
	TIM_HandleTIMCH3.Instance=TIM3;
	
	TIM_HandleTIMCH3.Init.Period=arr;
	TIM_HandleTIMCH3.Init.ClockDivision=TIM_COUNTERMODE_UP; /*向上计数*/
	TIM_HandleTIMCH3.Init.Prescaler=psc;
	HAL_TIM_Base_Init(&TIM_HandleTIMCH3);
	
	TIM_OC_Init.OCMode=TIM_OCMODE_PWM1;  /*为pwm模式1*/
	TIM_OC_Init.Pulse=arr/2;     /*比较值 CCRX的值*/
	TIM_OC_Init.OCPolarity=TIM_OCPOLARITY_LOW;   /*输出极性-低电频有效*/
										
	/*配置pwm模式比较值等*/
	HAL_TIM_PWM_ConfigChannel(&TIM_HandleTIMCH3,&TIM_OC_Init,TIM_CHANNEL_2);
	//启动生成PWM波
	HAL_TIM_PWM_Start(&TIM_HandleTIMCH3,TIM_CHANNEL_2);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM3)
	{
			
		__HAL_RCC_GPIOA_CLK_ENABLE() ;
		__HAL_RCC_TIM3_CLK_ENABLE();
		
		GPIO_InitTypeDef GPIO_InitType;
		GPIO_InitType.Mode=GPIO_MODE_AF_PP;   /*复用推完输出*/
		GPIO_InitType.Pin=GPIO_PIN_7;
		GPIO_InitType.Pull=GPIO_NOPULL;
		GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
	
		HAL_GPIO_Init(GPIOA,&GPIO_InitType); 
	
	}

}

 B:PWM驱动LED呼吸灯

复用功能

        和上面的内容一样不过为了练习我们的复用功能,我们使用复用功能;可以看到TIM3_CH2复用在PB5上面,这次我们使用复用功能

         我们在配置pwm模式的时候选择的是低电频有效,所以LED的负极连接——PB5;正极连接电源

主函数完全一样

	__HAL_RCC_AFIO_CLK_ENABLE();
	__HAL_AFIO_REMAP_TIM3_PARTIAL();

        每个引脚的重新映射是不同的:     __HAL_AFIO_REMAP_TIM3_PARTIAL();是不同的;但是因为使用到了AFIO,使用AFIO的时钟必须打开

#include "stm32f1xx_hal.h"


TIM_HandleTypeDef TIM_HandleTIMCH3;
void TIM3_CH2_init(uint16_t psc,uint16_t arr)
{
	TIM_OC_InitTypeDef TIM_OC_Init={0};
	TIM_HandleTIMCH3.Instance=TIM3;
	
	TIM_HandleTIMCH3.Init.Period=arr;
	TIM_HandleTIMCH3.Init.ClockDivision=TIM_COUNTERMODE_UP; /*向上计数*/
	TIM_HandleTIMCH3.Init.Prescaler=psc;
	HAL_TIM_Base_Init(&TIM_HandleTIMCH3);
	
	TIM_OC_Init.OCMode=TIM_OCMODE_PWM1;  /*为pwm模式1*/
	TIM_OC_Init.Pulse=arr/2;     /*比较值 CCRX的值*/
	TIM_OC_Init.OCPolarity=TIM_OCPOLARITY_LOW;   /*输出极性-低电频有效*/
										
	/*配置pwm模式比较值等*/
	HAL_TIM_PWM_ConfigChannel(&TIM_HandleTIMCH3,&TIM_OC_Init,TIM_CHANNEL_2);
	//使能生成PWM波
	HAL_TIM_PWM_Start(&TIM_HandleTIMCH3,TIM_CHANNEL_2);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM3)
	{
			
		__HAL_RCC_GPIOB_CLK_ENABLE() ;
		__HAL_RCC_TIM3_CLK_ENABLE();
		__HAL_RCC_AFIO_CLK_ENABLE();
		__HAL_AFIO_REMAP_TIM3_PARTIAL();
		GPIO_InitTypeDef GPIO_InitType;
		GPIO_InitType.Mode=GPIO_MODE_AF_PP;   /*复用推完输出*/
		GPIO_InitType.Pin=GPIO_PIN_5;
		GPIO_InitType.Pull=GPIO_NOPULL;
		GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
	
		HAL_GPIO_Init(GPIOB,&GPIO_InitType); 
	
	}

}

重新映射功能:

C:PWM驱动舵机

1:连接图

 红色-----接USE5V(3v带不动)     注意舵机应该接的5V的下载器上面,3.3V带不动

橙色-----信号线              棕色---地线

2:舵机介绍

        舵机是一种根据输入PWM信号占空比来控制输出角度的装置

        输入PWM信号要求:周期为20ms,高电平宽度为0.5ms~2.5ms

 高电平宽度=某电频的持续时间

CCR=高电频

舵机的控制一般需要一个20ms的时基脉冲(周期),该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度舵机为例,那么对应的控制关系是这样的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;

#include "stm32f1xx_hal.h"


TIM_HandleTypeDef TIM_HandleTIMCH3;
void TIM3_CH2_init(uint16_t psc,uint16_t arr)
{
	TIM_OC_InitTypeDef TIM_OC_Init={0};
	TIM_HandleTIMCH3.Instance=TIM3;
	
	TIM_HandleTIMCH3.Init.Period=arr;
	TIM_HandleTIMCH3.Init.ClockDivision=TIM_COUNTERMODE_UP; /*向上计数*/
	TIM_HandleTIMCH3.Init.Prescaler=psc;
	HAL_TIM_Base_Init(&TIM_HandleTIMCH3);
	
	TIM_OC_Init.OCMode=TIM_OCMODE_PWM1;  /*为pwm模式1*/
	TIM_OC_Init.Pulse=0;     /*比较值 CCRX的值*/
	TIM_OC_Init.OCPolarity=TIM_OCPOLARITY_HIGH;   /*输出极性-低电频有效*/
										
	/*配置pwm模式比较值等*/
	HAL_TIM_PWM_ConfigChannel(&TIM_HandleTIMCH3,&TIM_OC_Init,TIM_CHANNEL_2);
	//启动生成PWM波形
	HAL_TIM_PWM_Start(&TIM_HandleTIMCH3,TIM_CHANNEL_2);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM3)
	{
			
		__HAL_RCC_GPIOA_CLK_ENABLE() ;
		__HAL_RCC_TIM3_CLK_ENABLE();
		
		GPIO_InitTypeDef GPIO_InitType;
		GPIO_InitType.Mode=GPIO_MODE_AF_PP;   /*复用推完输出*/
		GPIO_InitType.Pin=GPIO_PIN_7;
		GPIO_InitType.Pull=GPIO_NOPULL;
		GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA,&GPIO_InitType); 
	
	}

}
#include "stm32f1xx_hal.h"
#include "pwm.h"
void serveo_init()
{
		TIM3_CH2_init(72-1,20000-1);   /*72*20000/72000000=0.02s=20ms*/
}


void Servo_SetAngle(float Angle)
{
	/*修改占空比*/
		__HAL_TIM_SET_COMPARE(&TIM_HandleTIMCH3,TIM_CHANNEL_2,Angle / 180 * 2000 + 500);
}
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "pwm.h"
#include "key.h"
#include "serveo.h"
int main(void)
{
	uint8_t Angle=0;
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	serveo_init();
	KEY_Init();
	OLED_ShowString(1, 1, "Angle:");
	while(1)
	{
		if(KEY_Scan()==1)
		{
			Angle+=30;
			if(Angle>180) Angle=0;	
				
		}
	Servo_SetAngle(Angle);
	OLED_ShowNum(1,7,Angle,3);
	
}
	
}

计算

 TIM_SetCompareX :  来单独更改CCR寄存器值的函数,可以更改占空比

D:PWM驱动直流电机 

1:连接图

 2:电机与驱动电路

        直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,

        当电极反接时,电机反转直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作
        TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向

 

 电机驱动详情见: 51:电机(ULN2003D)这一篇

3:代码
#include "stm32f1xx_hal.h"


TIM_HandleTypeDef TIM_HandleTIMCH3;
void TIM3_CH2_init(uint16_t psc,uint16_t arr)
{
	TIM_OC_InitTypeDef TIM_OC_Init={0};
	TIM_HandleTIMCH3.Instance=TIM3;
	
	TIM_HandleTIMCH3.Init.Period=arr;
	TIM_HandleTIMCH3.Init.ClockDivision=TIM_COUNTERMODE_UP; /*向上计数*/
	TIM_HandleTIMCH3.Init.Prescaler=psc;
	HAL_TIM_Base_Init(&TIM_HandleTIMCH3);
	
	TIM_OC_Init.OCMode=TIM_OCMODE_PWM1;  /*为pwm模式1*/
	TIM_OC_Init.Pulse=0;     /*比较值 CCRX的值*/
	TIM_OC_Init.OCPolarity=TIM_OCPOLARITY_HIGH;   /*输出极性-低电频有效*/
										
	/*配置pwm模式比较值等*/
	HAL_TIM_PWM_ConfigChannel(&TIM_HandleTIMCH3,&TIM_OC_Init,TIM_CHANNEL_2);
	//使能计数器
	HAL_TIM_PWM_Start(&TIM_HandleTIMCH3,TIM_CHANNEL_2);
	
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM3)
	{
			
		__HAL_RCC_GPIOA_CLK_ENABLE() ;
		__HAL_RCC_TIM3_CLK_ENABLE();
		
		GPIO_InitTypeDef GPIO_InitType;
		GPIO_InitType.Mode=GPIO_MODE_AF_PP;   /*复用推完输出*/
		GPIO_InitType.Pin=GPIO_PIN_7;
		GPIO_InitType.Pull=GPIO_NOPULL;
		GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA,&GPIO_InitType); 
	
	}

}

#include "stm32f1xx_hal.h"
#include "pwm.h"

void motor_init()
{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
		
		GPIO_InitTypeDef GPIO_InitType;
	
		GPIO_InitType.Mode=GPIO_MODE_OUTPUT_PP;
		GPIO_InitType.Pin=GPIO_PIN_5|GPIO_PIN_4;
		GPIO_InitType.Pull=GPIO_PULLUP;
		GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
	
		HAL_GPIO_Init(GPIOA,&GPIO_InitType); 

		TIM3_CH2_init(720-1,100-1);  /*720*100/72000000=0.001s=1MS*/



}

void motor_speed(int8_t speed)
{
	if(speed>0)
	{
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
		__HAL_TIM_SET_COMPARE(&TIM_HandleTIMCH3,TIM_CHANNEL_2,speed);
	}
	else
	{
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
		//speed为负数,需要把他变为正数,使用在加上负号
		__HAL_TIM_SET_COMPARE(&TIM_HandleTIMCH3,TIM_CHANNEL_2,-speed);
	}

}
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "pwm.h"
#include "key.h"
#include "motor.h"
int main(void)
{
	int8_t speed=0;
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	KEY_Init();
	OLED_ShowString(1, 1, "speed:");
	motor_init();
	while(1)
	{
		if(KEY_Scan()==1)
		{
			speed+=20;
			if(speed>100) speed=-100;
		}
		motor_speed(speed);
		OLED_ShowSignedNum(1, 7, speed, 3);
	
}
	
}

E:通用定时器定时

        使用通用定时器定时功能,定时1s并输出pwm波形

#include "stm32f1xx_hal.h"

int32_t num;
TIM_HandleTypeDef TIM_HandleTIMCH3;
void TIM3_CH2_init(uint16_t psc,uint16_t arr)
{
	TIM_OC_InitTypeDef TIM_OC_Init={0};
	TIM_HandleTIMCH3.Instance=TIM3;
	
	TIM_HandleTIMCH3.Init.Period=arr;
	TIM_HandleTIMCH3.Init.ClockDivision=TIM_COUNTERMODE_UP; /*向上计数*/
	TIM_HandleTIMCH3.Init.Prescaler=psc;
	HAL_TIM_Base_Init(&TIM_HandleTIMCH3);
	
	TIM_OC_Init.OCMode=TIM_OCMODE_PWM1;  /*为pwm模式1*/
	TIM_OC_Init.Pulse=arr/2;     /*比较值 CCRX的值*/
	TIM_OC_Init.OCPolarity=TIM_OCPOLARITY_HIGH;   /*输出极性-高2电频有效*/
										
	/*配置pwm模式比较值等*/
	HAL_TIM_PWM_ConfigChannel(&TIM_HandleTIMCH3,&TIM_OC_Init,TIM_CHANNEL_2);
	//使能计数器
	HAL_TIM_PWM_Start(&TIM_HandleTIMCH3,TIM_CHANNEL_2);
	//使能中段
	HAL_TIM_Base_Start_IT(&TIM_HandleTIMCH3);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM3)
	{
			
		__HAL_RCC_GPIOA_CLK_ENABLE() ;
		__HAL_RCC_TIM3_CLK_ENABLE();
			HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
		HAL_NVIC_SetPriority(TIM3_IRQn,2,0);
		HAL_NVIC_EnableIRQ(TIM3_IRQn);
		
		GPIO_InitTypeDef GPIO_InitType;
		GPIO_InitType.Mode=GPIO_MODE_AF_PP;   /*复用推完输出*/
		GPIO_InitType.Pin=GPIO_PIN_7;
		GPIO_InitType.Pull=GPIO_NOPULL;
		GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
	
		HAL_GPIO_Init(GPIOA,&GPIO_InitType); 
	}

}
void TIM3_IRQHandler()
{
	HAL_TIM_IRQHandler(&TIM_HandleTIMCH3);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM3)
	{
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
			num++;
	}
}
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "pwm.h"

int main(void)
{

	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	TIM3_CH2_init(7200-1,10000-1);
	LED_Exit_Init();

	while(1)
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);
		OLED_ShowNum(1,1,num,3);
	}
	
}







时间的计算第一种方法:先计算频率在计算周期频率:72000000/(7200-1+1)/(10000-1+1)=1     周期:1/频率=1

第二种方法:直接计算周期

7200*10000/72000000=1S-----直接就是周期 

中断

想要产生中断必须使能中断,下面这个必须写,CNT==ARR溢出产生的中断。启动定时器,并使能更新中断

	//使能中段
	HAL_TIM_Base_Start_IT(&TIM_HandleTIMCH3);

产生PWM必须使能:启动生成PWM波

	//使能计数器
	HAL_TIM_PWM_Start(&TIM_HandleTIMCH3,TIM_CHANNEL_2);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值