STM32入门(5)

STM32入门(5)

image-20260311102612882

TB6612控制逻辑

TB6612的电机方向由IN1、IN2的电平组合决定:

  • 正转:IN1=1,IN2=0(代码中正转时PA4=1, PA5=0)
  • 反转:IN1=0,IN2=1(代码中反转时PA4=0, PA5=1)
  • 停止/刹车:IN1=IN2(相同电平,本函数未使用)

PWM信号(占空比)控制电机转速,占空比越大转速越快。

项目一:PWM驱动直流电机

// 项目:PWM驱动直流电机
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"

uint8_t KeyNum;		//定义用于接收按键键码的变量
int8_t Speed;		//定义速度变量

int main(void)
{
	/*模块初始化*/
	OLED_Init();		//OLED初始化
	Motor_Init();		//直流电机初始化
	Key_Init();			//按键初始化
	
	/*显示静态字符串*/
	OLED_ShowString(1, 1, "Speed:");		//1行1列显示字符串Speed:
	
	while (1)
	{
		KeyNum = Key_GetNum();	//获取按键键码
		if (KeyNum == 1)		//按键1按下
		{
			Speed += 20;		//速度变量自增20
			if (Speed > 100)	//速度变量超过100后
			{
				Speed = -100;	//速度变量变为-100
								//此操作会让电机旋转方向突然改变,可能会因供电不足而导致单片机复位
								//若出现了此现象,则应避免使用这样的操作
			}
		}
		Motor_SetSpeed(Speed);				 //设置直流电机的速度为速度变量
		OLED_ShowSignedNum(1, 7, Speed, 3);	 //OLED显示速度变量
	}
}

#include "stm32f10x.h"                  // Device header

/**
  * 函    数: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_2;
	GPIO_InitStructure.GPIO_Speed  = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);                // 将PA2引脚初始化为复用推挽引脚
													     // 受外设控制的引脚,均需要配置为复用模式
	
	// 配置时钟源
	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 = 36 - 1;				   // 预分频器,即PSC的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;			   // 重复计数器,高级定时器才会用到
    // 将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);				 
	
	// 输出比较初始化
	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;								// 初始的CRR的值
    // 将结构体变量交给TIM_OC3Init,配置TIM2的输出比较通道3
	TIM_OC3Init(TIM2,&TIM_OCinitStructure);							
	// TIM使能
	TIM_Cmd(TIM2,ENABLE);      // 使能TIM2,定时器开始运行
}

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

void PWM_SetCompare3(uint16_t Compare)
{
	TIM_SetCompare3(TIM2, Compare);		//设置CCR3的值
}


#ifndef __PWM_H
#define __PWM_H

void PWM_Init(void);
void PWM_SetCompare3(uint16_t Compare);

#endif

#include "stm32f10x.h"                  // Device header
#include "PWM.h" 


/**
  * 函    数:直流电机初始化
  * 参    数:无
  * 返 回 值:无
  */
void Motor_Init(void)
{
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);     // 开启GPIOA的时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);					 // 将PA4和PA5引脚初始化为推挽输出
	
	PWM_Init();                                              // 初始化直流电机的底层PWM
}

/**
  * 函    数:直流电机设置速度
  * 参    数:Speed 要设置的速度,范围:-100 ~100
  * 返 回 值:无
  */
void Motor_SetSpeed(int8_t Speed)
{
	if(Speed >= 0)                           // 如果设置为正转的速度值
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_4);	     // PA4置高电平
		GPIO_ResetBits(GPIOA,GPIO_Pin_5);	 // PA5置低电平,设置方向为正转
		PWM_SetCompare3(Speed);				 // PWM设置为速度值
	}
	else									 // 否则,即设置反转的速度值
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_4);	 // PA4置低电平
		GPIO_SetBits(GPIOA, GPIO_Pin_5);	 // PA5置高电平,设置方向为反转
		PWM_SetCompare3(-Speed);			 // PWM设置为负的速度值,因为此时速度值为负数,而PWM只能给正数
	}
}

#ifndef __MOTOR_H
#define __MOTOR_H

void Motor_Init(void);
void Motor_SetSpeed(int8_t Speed);

#endif

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

/**
  * 函    数:按键初始化
  * 参    数:无
  * 返 回 值:无
  */
void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);      // 开启时钟
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;             // 设置为上拉模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}

/**
  * 函    数:按键获取键码
  * 参    数:无
  * 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下
	* 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手
  */
uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;   // 定义变量,默认键码值为0
	
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == RESET)
	{
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == RESET);
		Delay_ms(20);
		KeyNum = 1;
	}
	
	if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == RESET)
	{
		Delay_ms(20);
		while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == RESET);
		Delay_ms(20);
		KeyNum = 2;
	}
	
	return KeyNum;
}

#ifndef __KEY_H_
#define __KEY_H_

void Key_Init(void);
uint8_t Key_GetNum(void);

#endif

posted @ 2026-03-11 11:28  Q&25  阅读(5)  评论(0)    收藏  举报