(按键交互版)
目前完成的是基础任务,控制电机的启停,正反转以及控制转速。在设计过程中,我注意到MCXA153开发板有除复位按键之外的两个按键,于是打算用这两个按键实现这些控制功能。实现过程如下,代码以附件形式附上,视频将在下个结果贴中补充。
一、核心硬件原理1.1 TB6612FNG 驱动芯片控制逻辑
TB6612FNG是一款专为直流电机设计的双通道H桥驱动芯片,相比传统L298N,它具有功耗低、集成度高、自带续流二极管等优势,其核心控制逻辑如下:
AIN1 电平 | AIN2 电平 | 电机状态 |
高 | 低 | 正转 |
低 | 高 | 反转 |
高/低 | 高/低 | 刹车/停止 |
此外,芯片的PWMA(对应A通道)引脚接收PWM波输入,通过调整PWM占空比可线性调节电机转速:占空比越高,电机转速越快;占空比为0时,电机停止。
1.2 硬件连接设计
本方案中MCU与TB6612FNG、外设的核心连接关系:
● PWM输出:MCU的FlexPWM模块输出通道(BOARD_PWM_BASEADDR)连接TB6612FNG的PWMA引脚,用于输出调速PWM波;
● 方向控制:MCU的两个GPIO引脚(BOARD_Direct1/Direct2)分别连接TB6612FNG的AIN1/AIN2,通过电平翻转控制电机转向;
● 按键输入:SW2/SW3两个按键分别接MCU的GPIO中断引脚(下降沿触发),用于交互控制;
● 状态指示:MCU的GPIO引脚控制LED,用于指示PWM运行状态(电机启停)。
二、软件实现(基于MCUX SDK)2.1 开发环境
● 开发工具:Keil5
● 底层驱动:NXP MCUX SDK(适配目标MCU,包含PWM、GPIO、中断等底层驱动)
● 核心功能:PWM初始化与占空比更新、GPIO中断(按键)、按键长短按识别、电机状态控制。
2.2 代码架构与核心模块解析
完整代码基于模块化设计,核心分为PWM初始化、GPIO与中断配置、按键交互逻辑、主循环四大模块,以下是关键代码解析:
2.2.1 宏定义与全局变量(核心配置)
/* 按键长按判定阈值(ms),超过该时间判定为长按 */
#define LONG_PRESS_THRESHOLD 500
/* 占空比调整步长,每次按键±10% */
#define DUTY_STEP 10
/* 默认PWM频率1kHz,兼顾调速精度与电机响应 */
#define APP_DEFAULT_PWM_FREQUENCY (1000UL)
/* 全局状态标记 */
volatile bool g_Button2Press = false; // SW2按键按下标记
volatile bool g_Button3Press = false; // SW3按键按下标记
volatile bool g_PwmRunning = false; // PWM运行状态(电机启停)
volatile uint32_t g_PwmDuty = 50; // PWM占空比(0-100)
volatile bool g_DirectionState = false;// 方向引脚状态(控制AIN1/AIN2电平)
2.2.2 PWM初始化(FlexPWM配置)
针对TB6612FNG的驱动需求,配置FlexPWM模块为中心对齐模式(SignedCenterAligned),并设置死区时间(防止H桥桥臂直通):
static void PWM_DRV_Init3PhPwm(void)
{
uint16_t deadTimeVal;
pwm_signal_param_t pwmSignal;
uint32_t pwmSourceClockInHz = PWM_SRC_CLK_FREQ;
uint32_t pwmFrequencyInHz = APP_DEFAULT_PWM_FREQUENCY;
/* 死区时间配置:约650ns,防止H桥上下管同时导通 */
deadTimeVal = ((uint64_t)pwmSourceClockInHz * 650) / 1000000000;
/* 配置PWM信号参数:A通道、高电平有效、初始占空比50% */
pwmSignal.pwmChannel = kPWM_PwmA;
pwmSignal.level = kPWM_HighTrue;
pwmSignal.dutyCyclePercent = g_PwmDuty;
pwmSignal.deadtimeValue = deadTimeVal;
pwmSignal.pwmchannelenable = true;
/* 初始化PWM模块0,中心对齐模式,1kHz频率 */
PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_0, &pwmSignal, 1, kPWM_SignedCenterAligned,
pwmFrequencyInHz, pwmSourceClockInHz);
}
2.2.3 GPIO与中断配置(按键与方向控制)
● 按键配置:SW2/SW3设为数字输入,下降沿触发中断,中断服务函数仅标记按键按下状态(避免中断内复杂操作);
● 方向控制:AIN1/AIN2(BOARD_Direct1/Direct2)设为数字输出,初始全低(电机刹车);
● LED配置:数字输出,初始关闭(PWM未运行)。
/* SW2中断处理函数:仅标记按键按下,清中断标志 */
void BOARD_SW2_IRQ_HANDLER(void)
{
GPIO_PortClearInterruptFlags(BOARD_SW2_GPIO, 1U << BOARD_SW2_GPIO_PIN);
g_Button2Press = true;
SDK_ISR_EXIT_BARRIER;
}
/* 主函数中GPIO初始化 */
gpio_pin_config_t sw2_config = {kGPIO_DigitalInput, 0};
gpio_pin_config_t led_config = {kGPIO_DigitalOutput, 1};
gpio_pin_config_t p_direction_config = {kGPIO_DigitalOutput, 0};
// 按键GPIO初始化
GPIO_PinInit(BOARD_SW2_GPIO, BOARD_SW2_GPIO_PIN, &sw2_config);
// 方向引脚初始化(AIN1/AIN2)
GPIO_PinInit(BOARD_Direct_GPIO, BOARD_Direct1_GPIO_PIN, &p_direction_config);
GPIO_PinInit(BOARD_Direct_GPIO, BOARD_Direct2_GPIO_PIN, &p_direction_config);
// 配置按键中断为下降沿触发
PORT_SetPinInterruptConfig(BOARD_SW2_PORT, BOARD_SW2_GPIO_PIN, kPORT_InterruptFallingEdge);
EnableIRQ(BOARD_SW2_IRQ);
2.2.4 按键长短按交互逻辑(核心业务)
通过计时识别按键短按/长按,结合TB6612FNG控制逻辑实现以下功能:
按键 | 短按 | 长按 |
SW2 | 占空比+10%(≤100%) | 电机启停+LED状态切换 |
SW3 | 占空比-10%(≥10%) | 电机方向切换(翻转AIN1/AIN2电平) |
核心代码:
static void Key_ProcessShortLongPress(void)
{
uint32_t press_time = 0;
/* 处理SW2按键 */
if (g_Button2Press)
{
g_Button2Press = false;
// 计时:等待按键释放,最长计时500ms(长按阈值)
while (GPIO_PinRead(BOARD_SW2_GPIO, BOARD_SW2_GPIO_PIN) == 0)
{
delay_ms(1);
press_time++;
if (press_time > LONG_PRESS_THRESHOLD) break;
}
// 长按:启停PWM + 控制AIN1/AIN2 + LED
if (press_time >= LONG_PRESS_THRESHOLD)
{
g_PwmRunning = !g_PwmRunning;
if (g_PwmRunning)
{
// 电机运行:AIN1/AIN2电平相反(转向),启动PWM
GPIO_PinWrite(BOARD_Direct_GPIO, BOARD_Direct1_GPIO_PIN, g_DirectionState);
GPIO_PinWrite(BOARD_Direct_GPIO, BOARD_Direct2_GPIO_PIN, !g_DirectionState);
PWM_StartTimer(BOARD_PWM_BASEADDR, kPWM_Control_Module_0);
PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA,
kPWM_SignedCenterAligned, g_PwmDuty);
GPIO_PinWrite(BOARD_LED_GPIO, BOARD_LED_GPIO_PIN, 0); // LED亮
}
else
{
// 电机停止:AIN1/AIN2全低(刹车),PWM占空比置0并停止
GPIO_PinWrite(BOARD_Direct_GPIO, BOARD_Direct1_GPIO_PIN, 0);
GPIO_PinWrite(BOARD_Direct_GPIO, BOARD_Direct2_GPIO_PIN, 0);
PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA,
kPWM_SignedCenterAligned, 0);
PWM_StopTimer(BOARD_PWM_BASEADDR, kPWM_Control_Module_0);
GPIO_PinWrite(BOARD_LED_GPIO, BOARD_LED_GPIO_PIN, 1); // LED灭
}
}
// 短按:占空比+10%(不超过100%)
else
{
g_PwmDuty = (g_PwmDuty + DUTY_STEP) > 100 ? 100 : (g_PwmDuty + DUTY_STEP);
PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA,
kPWM_SignedCenterAligned, g_PwmDuty);
}
}
/* 处理SW3按键(逻辑类似) */
if (g_Button3Press)
{
g_Button3Press = false;
while (GPIO_PinRead(BOARD_SW3_GPIO, BOARD_SW3_GPIO_PIN) == 0)
{
delay_ms(1);
press_time++;
if (press_time > LONG_PRESS_THRESHOLD) break;
}
// 长按:翻转方向引脚状态(切换AIN1/AIN2电平)
if (press_time >= LONG_PRESS_THRESHOLD)
{
g_DirectionState = !g_DirectionState;
GPIO_PinWrite(BOARD_Direct_GPIO, BOARD_Direct1_GPIO_PIN, g_DirectionState);
GPIO_PinWrite(BOARD_Direct_GPIO, BOARD_Direct2_GPIO_PIN, !g_DirectionState);
}
// 短按:占空比-10%(不低于10%)
else
{
g_PwmDuty = (g_PwmDuty - DUTY_STEP) < 11 ? 10 : (g_PwmDuty - DUTY_STEP);
PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA,
kPWM_SignedCenterAligned, g_PwmDuty);
}
}
}
2.2.5 主循环
主循环仅轮询按键状态,调用长短按处理函数,降低系统资源占用:
int main(void)
{
// 硬件初始化(GPIO、PWM、中断)
BOARD_InitHardware();
PWM_DRV_Init3PhPwm();
// 初始状态:PWM停止、LED灭、方向引脚全低
PWM_StopTimer(BOARD_PWM_BASEADDR, kPWM_Control_Module_0);
GPIO_PinWrite(BOARD_LED_GPIO, BOARD_LED_GPIO_PIN, 1);
// 主循环
while (1U)
{
Key_ProcessShortLongPress(); // 处理按键交互
delay_ms(10); // 降低循环频率,减少CPU占用
}
}
三、测试验证
1. 硬件接线:按前文硬件连接方案,将MCU的PWM、GPIO引脚与TB6612FNG、按键、LED连接,电机接TB6612FNG的A通道输出;
2. 烧录代码:通过Keil5将代码烧录至目标MCU;
3. 功能验证:
○ SW2短按:电机转速逐步提升(占空比+10%),串口打印当前占空比;
○ SW2长按:电机启停切换,LED同步亮灭(运行亮、停止灭);
○ SW3短按:电机转速逐步降低(占空比-10%),串口打印当前占空比;
○ SW3长按:电机方向瞬间切换(正转→反转/反转→正转)。
我要赚赏金
