基于STM32开发板的按键调整PWM占空比实现电机转速调整方法详解

实验名称
:PWM控制电机转速

实验功能

基于正点原子战舰开发板,通过按键(KEY0 / KEY1)改变PWM,进而实现电机转速的调整。当按下KEY0键,电机转速加快;按下KEY1键,电机转速降低。

硬件资源

1. 独立按键

KEY0         –  PE4

KEY1         –  PE3

2. 通用定时器

TIM2_CH2   –  PA1

3. TB6612FNG模块

 

 

PF13   – 高电平 – IN1

PF14   – 低电平 – IN2

PF11   – 高电平 – STBY

原理图

TB6612FNG

 

程序设计

一、关键函数

1. 按键输入

函 数 名:HAL_GPIO_ReadPin ( GPIO_TypeDef  *GPIOx,  uint16_t  GPIO_Pin)

函数功能:
读取GPIO引脚状态
(通过IDR读取)

形参含义:形参1是端口号,形参2为引脚号

返 回 值:0或1(引脚状态值)

2. 通用定时器PWM输出

函 数 名:HAL_TIM_PWM_Init ( TIM_HandleTypeDef *htim)

函数功能:
初始化定时器的PWM输出模式

形参含义:TIM_HandleTypeDef结构体类型指针变量

返 回 值:HAL_StatusTypeDef枚举类型的值

函 数 名:HAL_TIM_PWM_ConfigChannel ( TIM_HandleTypeDef *htim,

TIM_OC_InitTypeDef *sConfig,  uint32_t Channel)

函数功能:
初始化定时器的PWM通道设置

形参含义:TIM_HandleTypeDef结构体类型指针变量,配置定时器的基本参数;

          TIM_OC_InitTypeDef结构体类型指针变量,配置定时器的输出比较参数;

                            定时器通道;

返 回 值:HAL_StatusTypeDef枚举类型的值

函 数 名:HAL_TIM_PWM_Start ( TIM_HandleTypeDef *htim, uint32_t Channel)

函数功能:
启动PWM输出

形参含义:TIM_HandleTypeDef枚举类型的值

返 回 值:HAL_StatusTypeDef枚举类型的值

函 数 名:HAL_TIM_ConfigClockSource ( TIM_HandleTypeDef *htim,

TIM_ClockConfigTypeDef *sClockSourceConfig)

函数功能:配置定时器的时钟源

形参含义:TIM_HandleTypeDef结构体类型指针变量

          TIM_ClockConfigTypeDef结构体类型指针变量,用于配置定时器的时钟源参数

返 回 值:HAL_StatusTypeDef枚举类型的值

二、配置步骤

2.1 GPIO输入配置步骤

      1. 使能GPIO时钟

    本实验用到PA0 / PA1 / PE3,共3个IO口,因此需要先使能GPIOA和GPIOE的时钟。

     __HAL_RCC_GPIOA_CLK_ENABLE();

     __HAL_RCC_GPIOE_CLK_ENABLE();

2. 设置GPIO工作模式

    复用推挽输出模式(带上拉 / 下拉)

3. 读取GPIO引脚高低电平

    通过HAL_GPIO_ReadPin()读取GPIO引脚的高低电平

2.2 定时器的PWM输出模式配置步骤

  1. 开启定时器TIMx的时钟、通道输出的GPIO时钟(通道输出GPIO初始化、优先级设置、中断使能)。

  2. 初始化定时器TIMx(设置TIMx的ARR和PSC等参数)

  3. 设置TIMx_CHy的PWM模式(设置输出比较极性/比较值)

  4. 使能定时器TIMx,使能TIMx的CHy输出

  5. 修改TIMx_CCRy来控制占空比

三、流程图

 

四、代码

代码除main.c外,还包含key.c、 gtim.c、 led. gpio.c四个源文件及其头文件,代码如下:

(1)main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/key/key.h"
#include "./BSP/gtim/gtim.h"
#include "./BSP/led/led.h"
#include "./BSP/gpio/gpio.h"

extern TIM_HandleTypeDef g_timx_pwm_chy_handle;     /* 定时器x句柄 */

int main(void)
{
	uint16_t motor_up(uint16_t PwmVal);
	uint16_t motor_down(uint16_t PwmVal);
	
	uint16_t MotorPwmVal = 0;
	uint8_t key;
	uint8_t t = 0;
	
	HAL_Init();                             /* 初始化HAL库 */
	sys_stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
	delay_init(72);                         /* 延时初始化 */
	usart_init(115200);                     /* 串口初始化为115200 */
	key_init();
	led_init();
	in_init();
	gtim_timx_pwm_chy_init(500 - 1, 72 - 1);/* 1Mhz的计数频率,2Khz的PWM */
	
	
	while (1){
		t++;
		key = key_scan(0);
		
		if (key == KEY0_PRES ){
			if (MotorPwmVal < 250){
				MotorPwmVal += 10;
				LED0_TOGGLE();
			}
			__HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY, MotorPwmVal);
		}
		
		else if (key == KEY1_PRES){
			if (MotorPwmVal > 10 ){
				MotorPwmVal -= 10;
				LED1_TOGGLE();
			}
			else{
				MotorPwmVal = 0;
			}
			__HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY, MotorPwmVal);
		}
		
		delay_ms(10);
	}
}

(2)key.h和key.c

#ifndef __KEY_H
#define __KEY_H

#include "./SYSTEM/sys/sys.h"

/* 引脚定义 */

#define KEY1_GPIO_PORT                  GPIOE
#define KEY1_GPIO_PIN                   GPIO_PIN_3
#define KEY1_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */


#define KEY0_GPIO_PORT                  GPIOE
#define KEY0_GPIO_PIN                   GPIO_PIN_4
#define KEY0_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */

/* 引脚状态读取 */

#define KEY1        HAL_GPIO_ReadPin(KEY1_GPIO_PORT, KEY1_GPIO_PIN)     /* 读取KEY1引脚 */
#define KEY0        HAL_GPIO_ReadPin(KEY0_GPIO_PORT, KEY0_GPIO_PIN)     /* 读取key0引脚 */

#define KEY0_PRES    1              /* KEY0按下 */
#define KEY1_PRES    2              /* KEY1按下 */


void key_init(void);                /* 按键初始化函数 */
uint8_t key_scan(uint8_t mode);     /* 按键扫描函数 */

#endif

#include "./BSP/key/key.h"
#include "./SYSTEM/delay/delay.h"



void key_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    KEY1_GPIO_CLK_ENABLE();                                     /* KEY1时钟使能 */
    KEY0_GPIO_CLK_ENABLE();                                     /* WKUP时钟使能 */

	  gpio_init_struct.Pin = KEY0_GPIO_PIN;                       /* KEY0引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;                    /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;                        /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;              /* 高速 */
    HAL_GPIO_Init(KEY0_GPIO_PORT, &gpio_init_struct);           /* KEY0引脚模式设置,上拉输入 */
	
    gpio_init_struct.Pin = KEY1_GPIO_PIN;                       /* KEY1引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;                    /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;                        /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;              /* 高速 */
    HAL_GPIO_Init(KEY1_GPIO_PORT, &gpio_init_struct);           /* KEY1引脚模式设置,上拉输入 */

}

/* 按键扫描函数 */
uint8_t key_scan(uint8_t mode)
{
    static uint8_t key_up = 1;                  /* 按键按松开标志 */
    uint8_t keyval = 0;

    if (mode) key_up = 1;                       /* 支持连按 */

    if (key_up && (KEY1 == 0 ||KEY0 == 0 ))     /* 按键松开标志为1, 且有任意一个按键按下了 */
    {
        delay_ms(10);                           /* 去抖动 */
        key_up = 0;
			
        if (KEY0 == 0)  keyval = KEY0_PRES;
        if (KEY1 == 0)  keyval = KEY1_PRES;

    }
    else if ( KEY1 == 1  && KEY0 == 1)          /* 没有任何按键按下, 标记按键松开 */
    {
        key_up = 1;
    }

    return keyval;                              /* 返回键值 */
}

(3)gtim.h 和 gtim.c

#ifndef __GTIM_H
#define __GTIM_H

#include "./SYSTEM/sys/sys.h"


#define GTIM_TIMX_PWM_CHY_GPIO_PORT         GPIOA
#define GTIM_TIMX_PWM_CHY_GPIO_PIN          GPIO_PIN_1
#define GTIM_TIMX_PWM_CHY_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)  /* PB口时钟使能 */


#define GTIM_TIMX_PWM                       TIM2 
#define GTIM_TIMX_PWM_CHY                   TIM_CHANNEL_2                                /* 通道Y,  1<= Y <=4 */
#define GTIM_TIMX_PWM_CHY_CCRX              TIM2->CCR2                                   /* 通道Y的输出比较寄存器 */
#define GTIM_TIMX_PWM_CHY_CLK_ENABLE()      do{ __HAL_RCC_TIM2_CLK_ENABLE(); }while(0)   /* TIM3 时钟使能 */

 

void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc);                                  /* 通用定时器 PWM初始化函数 */

#endif

#include "./BSP/timer/gtim.h"

TIM_HandleTypeDef g_timx_pwm_chy_handle;                    /* 定时器x句柄 */

void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc)
{
    TIM_OC_InitTypeDef timx_oc_pwm_chy  = {0};              /* 定时器PWM输出配置 */
		

    GTIM_TIMX_PWM_CHY_GPIO_CLK_ENABLE();                    /* 使能 通道y对应的CPIO时钟 */
    GTIM_TIMX_PWM_CHY_CLK_ENABLE();                         /* 使能 定时器时钟*/

    GPIO_InitTypeDef gpio_init_struct;
    gpio_init_struct.Pin = GTIM_TIMX_PWM_CHY_GPIO_PIN;      /* 通道y的CPIO口 */
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推完输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */
    HAL_GPIO_Init(GTIM_TIMX_PWM_CHY_GPIO_PORT, &gpio_init_struct);

    g_timx_pwm_chy_handle.Instance = GTIM_TIMX_PWM;                    /* 定时器x */
    g_timx_pwm_chy_handle.Init.Prescaler = psc;                        /* 定时器分频 */
    g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;       /* 递增计数模式 */
    g_timx_pwm_chy_handle.Init.Period = arr;                           /* 自动重装载值 */
    HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle);                          /* 初始化PWM */

    timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1;                          /* 模式选择PWM1 */
    timx_oc_pwm_chy.Pulse = arr / 2;                    /* 设置比较值,此值用来确定占空比 */
                                     
    timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_LOW;    /* 输出比较极性为低 */
    HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, GTIM_TIMX_PWM_CHY);     /* 配置TIMx通道y */
    HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY);  /* 开启对应PWM通道 */
}


(4)led.c 和 led.h

#ifndef _LED_H
#define _LED_H
#include "./SYSTEM/sys/sys.h"

/* 引脚定义 */
#define LED0_GPIO_PORT                  GPIOB
#define LED0_GPIO_PIN                   GPIO_PIN_5
#define LED0_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)             /* PB口时钟使能 */

#define LED1_GPIO_PORT                  GPIOE
#define LED1_GPIO_PIN                   GPIO_PIN_5
#define LED1_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)             /* PE口时钟使能 */


/* LED端口定义 */
#define LED0(x)   do{ x ? \
                      HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_SET) : \
                      HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_RESET); \
                  }while(0)      /* LED0翻转 */

#define LED1(x)   do{ x ? \
                      HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_SET) : \
                      HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_RESET); \
                  }while(0)      /* LED1翻转 */

									
/* LED取反定义 */
#define LED0_TOGGLE()   do{ HAL_GPIO_TogglePin(LED0_GPIO_PORT, LED0_GPIO_PIN); }while(0)        
#define LED1_TOGGLE()   do{ HAL_GPIO_TogglePin(LED1_GPIO_PORT, LED1_GPIO_PIN); }while(0)        


/* 外部接口函数*/
void led_init(void);                                                                            /* 初始化 */

#endif
#include "./BSP/led/led.h"


void led_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    LED0_GPIO_CLK_ENABLE();                                 /* LED0时钟使能 */
    LED1_GPIO_CLK_ENABLE();                                 /* LED1时钟使能 */

    gpio_init_struct.Pin = LED0_GPIO_PIN;                   /* LED0引脚 */
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */
    HAL_GPIO_Init(LED0_GPIO_PORT, &gpio_init_struct);       /* 初始化LED0引脚 */

    gpio_init_struct.Pin = LED1_GPIO_PIN;                   /* LED1引脚 */
    HAL_GPIO_Init(LED1_GPIO_PORT, &gpio_init_struct);       /* 初始化LED1引脚 */

    LED0(1);                                                /* 关闭 LED0 */
    LED1(1);                                                /* 关闭 LED1 */
}

(5)gpio.h和gpio.c

#ifndef __GPIO_H
#define __GPIO_H

#include "./SYSTEM/sys/sys.h"

/* 引脚 定义 */

#define IN1_GPIO_PORT                  GPIOF
#define IN1_GPIO_PIN                   GPIO_PIN_13
#define IN1_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOF_CLK_ENABLE(); }while(0)   

#define IN2_GPIO_PORT                  GPIOF
#define IN2_GPIO_PIN                   GPIO_PIN_14
#define IN2_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOF_CLK_ENABLE(); }while(0)   

#define STBY_GPIO_PORT                 GPIOF
#define STBY_GPIO_PIN                  GPIO_PIN_11
#define STBY_GPIO_CLK_ENABLE()         do{ __HAL_RCC_GPIOF_CLK_ENABLE(); }while(0)  

void in_init(void); 

#endif
#include "./BSP/gpio/gpio.h"

void in_init(void){
	GPIO_InitTypeDef gpio_init_struct;
  IN1_GPIO_CLK_ENABLE();                                 
  IN2_GPIO_CLK_ENABLE();                                 

  gpio_init_struct.Pin = IN1_GPIO_PIN;                   
  gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            
  gpio_init_struct.Pull = GPIO_PULLUP;                    
  gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          
  HAL_GPIO_Init(IN1_GPIO_PORT, &gpio_init_struct);       

  gpio_init_struct.Pin = IN2_GPIO_PIN;                   
  HAL_GPIO_Init(IN2_GPIO_PORT, &gpio_init_struct);    
  
	gpio_init_struct.Pin = STBY_GPIO_PIN;                   
  HAL_GPIO_Init(STBY_GPIO_PORT, &gpio_init_struct); 	
	
	HAL_GPIO_WritePin(IN1_GPIO_PORT,IN1_GPIO_PIN,GPIO_PIN_SET);
	HAL_GPIO_WritePin(IN2_GPIO_PORT,IN2_GPIO_PIN,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(STBY_GPIO_PORT,STBY_GPIO_PIN,GPIO_PIN_SET);
}

实验结果:

按键调整端口输出电压大小

按键调整电机转速大小

 

 

 

物联沃分享整理
物联沃-IOTWORD物联网 » 基于STM32开发板的按键调整PWM占空比实现电机转速调整方法详解

发表回复