✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇
一、引言
在许多嵌入式系统和机器人项目中,直流电机是常用的执行机构,用于实现各种机械运动。而 TB6612 是一款常用的直流电机驱动芯片,它可以方便地驱动两个直流电机,并且能够控制电机的正反转和调速。STM32 作为一款高性能的微控制器,与 TB6612 结合使用,可以实现对直流电机的精确控制。本文将详细介绍如何使用 STM32 利用 TB6612 驱动直流电机并实现电机调速。
二、TB6612 芯片简介
2.1 主要特性
- 能够同时驱动两个直流电机。
- 输出电流大,单通道连续驱动电流可达 1.2A,峰值电流可达 3.2A。
- 支持正反转控制和制动功能。
- 内置过热保护和低压检测电路,提高了系统的可靠性。
2.2 引脚功能
TB6612 有多个引脚,主要引脚功能如下:
- VM:电源输入引脚,连接电机电源。
- VCC:逻辑电源输入引脚,一般连接 3.3V 或 5V。
- GND:接地引脚。
- AIN1、AIN2、BIN1、BIN2:电机控制信号输入引脚,用于控制电机的正反转。
- PWMA、PWMB:PWM 信号输入引脚,用于控制电机的转速。
- AO1、AO2、BO1、BO2:电机输出引脚,连接电机的正负极。
- STBY:待机控制引脚,低电平使芯片进入待机模式。
三、硬件连接
以 STM32F103C8T6 为例,与 TB6612 的硬件连接如下:
STM32 引脚 | TB6612 引脚 | 功能 |
---|---|---|
PA0 | PWMA | 控制电机 A 的 PWM 信号 |
PA1 | AIN1 | 控制电机 A 的正反转信号 1 |
PA2 | AIN2 | 控制电机 A 的正反转信号 2 |
PA3 | PWMB | 控制电机 B 的 PWM 信号 |
PA4 | BIN1 | 控制电机 B 的正反转信号 1 |
PA5 | BIN2 | 控制电机 B 的正反转信号 2 |
PA6 | STBY | 待机控制信号 |
3.3V | VCC | 逻辑电源 |
电机电源 | VM | 电机电源 |
GND | GND | 接地 |
四、软件实现
4.1 初始化 GPIO 和 PWM
首先,需要初始化 STM32 的 GPIO 引脚,用于控制 TB6612 的正反转信号和待机信号。同时,需要初始化 PWM 定时器,用于生成控制电机转速的 PWM 信号。
#include "stm32f1xx_hal.h"
TIM_HandleTypeDef htim2;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
// 使能 TB6612
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
// 启动 PWM 输出
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
while (1)
{
// 这里可以添加电机控制逻辑
HAL_Delay(1000);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
static void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 71;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 999;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim2);
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6, GPIO_PIN_RESET);
/*Configure GPIO pins : PA1 PA2 PA4 PA5 PA6 */
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void Error_Handler(void)
{
while(1)
{
}
}
4.2 电机控制函数
为了方便控制电机的正反转和调速,可以编写以下电机控制函数:
// 控制电机 A 的正反转和调速
void motorA_control(int direction, int speed)
{
if (direction == 1) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
} else if (direction == -1) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
} else {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
}
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, speed);
}
// 控制电机 B 的正反转和调速
void motorB_control(int direction, int speed)
{
if (direction == 1) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
} else if (direction == -1) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
} else {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, speed);
}
4.3 主函数中的电机控制逻辑
在主函数中,可以调用电机控制函数来实现电机的正反转和调速。
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
// 使能 TB6612
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
// 启动 PWM 输出
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
while (1)
{
// 电机 A 正转,速度为 500
motorA_control(1, 500);
// 电机 B 反转,速度为 300
motorB_control(-1, 300);
HAL_Delay(2000);
// 电机 A 停止
motorA_control(0, 0);
// 电机 B 停止
motorB_control(0, 0);
HAL_Delay(2000);
}
}
五、代码解释
5.1 初始化部分
SystemClock_Config()
:配置系统时钟,确保 STM32 以正确的时钟频率运行。MX_GPIO_Init()
:初始化 GPIO 引脚,用于控制 TB6612 的正反转信号和待机信号。MX_TIM2_Init()
:初始化定时器 2,用于生成 PWM 信号。设置了定时器的预分频器、计数模式、周期等参数,并配置了 PWM 输出通道。
5.2 电机控制函数
motorA_control(int direction, int speed)
:控制电机 A 的正反转和调速。direction
参数为 1 表示正转,-1 表示反转,0 表示停止;speed
参数表示 PWM 占空比,范围为 0 - 999。motorB_control(int direction, int speed)
:控制电机 B 的正反转和调速,原理与motorA_control
相同。
5.3 主函数
在主函数中,首先进行初始化操作,然后使能 TB6612 芯片,启动 PWM 输出。在循环中,交替控制电机 A 和电机 B 的正反转和停止,每个状态持续 2 秒。
六、注意事项
- 电源供应:TB6612 的 VM 引脚需要连接合适的电机电源,确保电机能够正常工作。同时,要注意电源的稳定性和功率。
- PWM 频率:PWM 频率会影响电机的运行效果。可以根据电机的特性和应用需求调整 PWM 频率。
- 过热保护:TB6612 内置了过热保护电路,但在长时间大电流运行时,仍需注意芯片的散热问题。
通过以上步骤和代码,就可以使用 STM32 利用 TB6612 驱动直流电机并实现电机调速。在实际应用中,可以根据具体需求对代码进行扩展和优化,以实现更复杂的电机控制功能。