Files
SmartMassager_STM32/Core/Src/motor_driver.c
wangbeihong b883e0a7f9 feat: 实现智能按摩器完整功能 (定时/语音/电机/显示)
- 新增MP3语音模块驱动,集成18个语音提示,支持播放/停止/音量调节
- 实现0/10/20/30分钟循环定时倒计时,实时显示剩余时间,定时结束自动停机
- 优化电机控制:一档力度提升至75%,降档冲击时间延长至800ms,降档时触发100%冲击防卡顿
- 屏幕显示重构为分区动态更新:时间状态(Zone1)/档位(Zone2)/加热(Zone3),性能优化
- 新增LED指示:运行时RUN_LED以500ms周期闪烁,无效操作ERR_LED亮1秒
- 操作逻辑改进:所有操作需先设定时间,否则播放"请先设定时间"并亮ERR_LED
- 加热控制由GPIO改为PWM(TIM1_CH1),占空比300
- 调整USART3波特率为9600适配MP3模块
- FreeRTOS任务优化:Motor周期500ms,Screen周期10ms,新增定时器秒Tick处理
- 完善开发文档:MP3集成指南、校验和验证脚本、文件重命名工具等

新增文件:mp3_driver.h/c, 多项开发文档
修改文件:freertos.c, gbk_text.h/c, motor_driver.c, screen.h/c, usart.c, gpio.c等
2026-02-17 23:52:17 +08:00

203 lines
6.2 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file motor_driver.c
* @brief 电机驱动实现 - 双路AT8236-MS H桥驱动
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "motor_driver.h"
#include "elog.h"
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_tim.h"
#include "cmsis_os.h"
#include "tim.h"
/* Private defines -----------------------------------------------------------*/
/* TIM4自动重装载值是99 (100-1)所以PWM值范围是0-99 */
/* Private function prototypes -----------------------------------------------*/
void Motor_StartAll(void);
void Motor_StopAll(void);
/* PWM parameters */
#define PWM_ARR 99
#define PWM_STEPS (PWM_ARR + 1)
/* 三档占空比(百分比),索引为 0..2 对应 档位 1..3档位0为停止 */
static const uint8_t gears_percent[3] = {75, 85, 95};
/* current_gear: 0 = 停止, 1 = 低, 2 = 中, 3 = 高 */
static uint8_t current_gear = 0; /* 0..3 */
static inline uint32_t percent_to_compare(uint8_t percent) {
return ((uint32_t)percent * PWM_STEPS) / 100U;
}
/* 将两个电机都设置为指定占空比(使用 AT8236-MS H桥驱动 */
static void set_both_motors_percent(uint8_t percent) {
uint32_t cmp = percent_to_compare(percent);
/* 电机1: TIM4_CH1->AIN1, TIM4_CH2->AIN2
* 正转AIN1=PWM, AIN2=0
* 反转AIN1=0, AIN2=PWM
* 这里用正转模式CH1输出PWM, CH2为0 */
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, (uint16_t)cmp);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 0);
/* 电机2: TIM4_CH3->BIN1, TIM4_CH4->BIN2
* 正转BIN1=PWM, BIN2=0
* 这里用正转模式CH3输出PWM, CH4为0 */
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, (uint16_t)cmp);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, 0);
}
/* 启动时短暂提升到 100% 并保持 500ms然后降到一档档位1 */
void Motor_StartupBoost(void) {
// 确保PWM通道已启动
Motor_StartAll();
set_both_motors_percent(100); /* 启动提升到 100% */
elog_d("Motor", "启动冲击: 100%%");
osDelay(1500);
current_gear = 1; /* 启动后回到档位1最低速 */
elog_d("Motor", "设置档位: %d, PWM: %d%%", current_gear, gears_percent[current_gear - 1]);
set_both_motors_percent(gears_percent[current_gear - 1]);
}
/* 设置挡位0..30=停止 */
void Motor_SetGear(uint8_t gear) {
if (gear > 3) gear = 3;
current_gear = gear;
if (current_gear == 0) {
// 完全停止所有PWM输出
Motor_Stop();
elog_d("Motor", "Motor_SetGear: 档位0, 停止");
} else {
// 确保PWM通道已启动
Motor_StartAll();
elog_d("Motor", "Motor_SetGear: 档位%d, PWM: %d%%", current_gear, gears_percent[current_gear - 1]);
set_both_motors_percent(gears_percent[current_gear - 1]);
}
}
/* 切换到下一档0->1->2->3->0 循环) */
void Motor_NextGear(void) {
current_gear++;
if (current_gear > 3) current_gear = 0;
if (current_gear == 0) {
// 完全停止所有PWM输出
Motor_Stop();
elog_d("Motor", "Motor_NextGear: 档位0, 停止");
} else {
// 确保PWM通道已启动
Motor_StartAll();
elog_d("Motor", "Motor_NextGear: 档位%d, PWM: %d%%", current_gear, gears_percent[current_gear - 1]);
set_both_motors_percent(gears_percent[current_gear - 1]);
}
}
/* 向上加档(与按键配合使用) */
void Motor_GearUp(void) {
Motor_NextGear();
}
/* 向下减档(循环) */
void Motor_GearDown(void) {
uint8_t old_gear = current_gear;
if (current_gear == 0) {
current_gear = 3;
} else {
current_gear--;
}
elog_d("Motor", "Motor_GearDown: %d -> %d", old_gear, current_gear);
if (current_gear == 0) {
// 完全停止所有PWM输出
Motor_Stop();
elog_d("Motor", "档位0, 停止");
} else {
// 确保PWM通道已启动
Motor_StartAll();
// 如果从2档或3档降到1档需要短暂冲击保持电机转动
if (current_gear == 1 && old_gear >= 2) {
// 短暂提升到100%来维持转动然后降到1档
elog_d("Motor", "降档冲击: 100%%");
set_both_motors_percent(100);
osDelay(800); // 800ms冲击给电机更充裕的适应时间
}
elog_d("Motor", "最终档位%d, PWM: %d%%", current_gear, gears_percent[current_gear - 1]);
set_both_motors_percent(gears_percent[current_gear - 1]);
}
}
uint8_t Motor_GetGear(void) {
return current_gear;
}
/* Exported functions --------------------------------------------------------*/
/**
* @brief 电机驱动初始化
*/
void Motor_Init(void) {
/* 启动TIM4 PWM输出 */
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
// 初始完全停止电机
Motor_Stop();
}
/**
* @brief 完全停止电机并关闭所有PWM通道
*/
void Motor_StopAll(void) {
// 设置所有通道的PWM为0
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 0);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 0);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, 0);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, 0);
// 停止所有PWM通道
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_1);
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_2);
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_3);
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_4);
}
/**
* @brief 重新启动所有PWM通道用于启动电机
*/
void Motor_StartAll(void) {
// 重新启动PWM通道
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
}
void Motor_Stop(void) {
// 所有引脚输出0 - 完全停止
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 0);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 0);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, 0);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, 0);
// 强制停止PWM通道确保电机完全停止
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_1);
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_2);
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_3);
HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_4);
}