电子网首页 > 开源与设计

[Let'sdo第4期-基于单片机的直流电机控制]--成果贴

2026-02-07 01:10 | 来源:电子世界报

完成了对电机的控制,下面来简单介绍一下


  1.连线

TB6612MCXA153
PWMA
P3_6
AIN1P3_13
AIN2P3_12
GNDGND
VCC3.3V

电机
MOT.A电机两端

TXN50-112
VMV+
GND
V-

  2.功能

实现了电机的正反转,停止。

通过led颜色反馈当前电机状态。

通过串口发送给单片机,实现控制电机。


  3.代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <board.h>
#include <peripherals.h>
#include <pin_mux.h>
#include <clock_config.h>
#include <MCXA153.h>
#include <fsl_debug_console.h>
#include "fsl_lpuart.h" 
#include <MCXA153_COMMON.h>
#include "app.h"
#include "fsl_pwm.h"

/*******************************************************************************
 * 定义部分
 ******************************************************************************/
#define CTIMER CTIMER1
#define CTIMER_MAT_OUT kCTIMER_Match_2
#define CTIMER_CLK_FREQ CLOCK_GetCTimerClkFreq(1U)
#define CMD_BUFFER_SIZE 64
#define MAX_PARAMS 4
#define MAX_TASKS 2

/* 命令解析结构体(保留定义但不再使用) */
typedef struct
{
    char cmd[32];
    char params[MAX_PARAMS][16];
    int paramCount;
} parsed_cmd_t;

#define APP_DEFAULT_PWM_FREQUENCY (1000UL)

/*******************************************************************************
 * 函数原型声明
 ******************************************************************************/
void Debug_SysTick_Configuration(void);
void task1(void);
void task2(uint8_t direction, int speed);

/*******************************************************************************
 * 变量定义
 ******************************************************************************/
volatile uint32_t g_Milliseconds = 0U; 
volatile uint32_t g_pwmPeriod = 0U;
volatile uint32_t g_pulsePeriod = 0U;
volatile bool g_MotorRunningState = false; 

/*******************************************************************************
 * 代码实现
 ******************************************************************************/
static void PWM_DRV_InitSinglePwm(void)
{
    pwm_signal_param_t pwmSignal;
    uint32_t pwmSourceClockInHz;
    uint32_t pwmFrequencyInHz = APP_DEFAULT_PWM_FREQUENCY;

    pwmSourceClockInHz = PWM_SRC_CLK_FREQ;

    pwmSignal.pwmChannel = kPWM_PwmA;
    pwmSignal.level = kPWM_HighTrue;
    pwmSignal.dutyCyclePercent = 0;
    pwmSignal.deadtimeValue = 0;
    pwmSignal.faultState = kPWM_PwmFaultState0;
    pwmSignal.pwmchannelenable = true;

    PWM_SetupPwm(BOARD_PWM_BASEADDR, kPWM_Module_0, &pwmSignal, 1,
                 kPWM_SignedCenterAligned, pwmFrequencyInHz, pwmSourceClockInHz);
}

/**
 * @brief SysTick中断处理函数
 */
void SysTick_Handler(void)
{
    g_Milliseconds++;
}

void task1(void)
{
    PRINTF("\nTesting Motor Control...\r\n");
    task2(0, 0);
    SDK_DelayAtLeastUs(1 * 1000000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
    task2(1, 30);
    SDK_DelayAtLeastUs(2 * 1000000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
    task2(1, 60);
    SDK_DelayAtLeastUs(2 * 1000000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
    task2(0, 0);
    SDK_DelayAtLeastUs(1 * 1000000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
    task2(2, 30);
    SDK_DelayAtLeastUs(2 * 1000000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
    task2(2, 60);
    SDK_DelayAtLeastUs(2 * 1000000U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
    PRINTF("\nMotor Stop...\r\n");
    task2(0, 0);
}

void task2(uint8_t direction, int speed)
{
    if (direction == 1)
    {
        GPIO_PinWrite(BOARD_LED_RED_GPIO, BOARD_LED_RED_GPIO_PIN, 1);
        GPIO_PinWrite(BOARD_LED_GREEN_GPIO, BOARD_LED_GREEN_GPIO_PIN, 0);
    }
    else if (direction == 2)
    {
        GPIO_PinWrite(BOARD_LED_RED_GPIO, BOARD_LED_RED_GPIO_PIN, 0);
        GPIO_PinWrite(BOARD_LED_GREEN_GPIO, BOARD_LED_GREEN_GPIO_PIN, 1);
    }
    else
    {
        GPIO_PinWrite(BOARD_LED_RED_GPIO, BOARD_LED_RED_GPIO_PIN, 1);
        GPIO_PinWrite(BOARD_LED_GREEN_GPIO, BOARD_LED_GREEN_GPIO_PIN, 1);
    }

    if (speed >= 0 && speed <= 100)
    {
        PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA,
                               kPWM_SignedCenterAligned, speed);
    }
    else
    {
        PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA,
                               kPWM_SignedCenterAligned, 0);
    }
    PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0, true);
}

int main(void)
{
    gpio_pin_config_t p_config = {kGPIO_DigitalOutput, 1U};
    pwm_config_t pwmConfig;
    pwm_fault_param_t faultConfig;
    char cmdBuffer[CMD_BUFFER_SIZE] = {0};
    int cmdIndex = 0;
    uint8_t receivedChar;

    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitBootPeripherals();
#ifndef BOARD_INIT_DEBUG_CONSOLE_PERIPHERAL
    BOARD_InitDebugConsole();
#endif

    // 初始化SysTick定时器 (1ms)
    if (SysTick_Config(SystemCoreClock / 1000))
    {
        PRINTF("SysTick配置失败!\r\n");
        while (1)
            ;
    }

    // 初始化LED引脚
    GPIO_PinInit(BOARD_LED_RED_GPIO, BOARD_LED_RED_GPIO_PIN, &p_config);
    GPIO_PinInit(BOARD_LED_GREEN_GPIO, BOARD_LED_GREEN_GPIO_PIN, &p_config);

    // 初始化PWM
    PWM_GetDefaultConfig(&pwmConfig);
    pwmConfig.prescale = DEMO_PWM_CLOCK_DEVIDER;
    pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
    pwmConfig.pairOperation = kPWM_Independent;
    pwmConfig.enableDebugMode = true;

    if (PWM_Init(BOARD_PWM_BASEADDR, kPWM_Module_0, &pwmConfig) == kStatus_Fail)
    {
        PRINTF("PWM initialization failed\n");
        return 1;
    }

    PWM_FaultDefaultConfig(&faultConfig);
    faultConfig.faultLevel = DEMO_PWM_FAULT_LEVEL;
    PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_0, &faultConfig);
    PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_1, &faultConfig);
    PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_2, &faultConfig);
    PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_3, &faultConfig);

    PWM_DRV_InitSinglePwm();
    PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0, true);
    PWM_StartTimer(BOARD_PWM_BASEADDR, kPWM_Control_Module_0);

    task1();


    PRINTF("\r\n=== Motor Control Ready ===\r\n");
    PRINTF("Enter speed (-100 to 100) or 'stop':\r\n");
    PRINTF("Speed: ");

    while (1)
    {
        if (LPUART_GetStatusFlags((LPUART_Type *)BOARD_DEBUG_UART_BASEADDR) & kLPUART_RxDataRegFullFlag)
        {
            receivedChar = LPUART_ReadByte((LPUART_Type *)BOARD_DEBUG_UART_BASEADDR);
            LPUART_WriteByte((LPUART_Type *)BOARD_DEBUG_UART_BASEADDR, receivedChar);

            if (receivedChar == '\r' || receivedChar == '\n')
            {
                // 处理命令:支持 -100~100 数值 或 "stop"
                if (cmdBuffer[0] != '\0')
                {
                    // 转换为小写判断stop
                    char temp[CMD_BUFFER_SIZE];
                    strncpy(temp, cmdBuffer, CMD_BUFFER_SIZE - 1);
                    temp[CMD_BUFFER_SIZE - 1] = '\0';
                    for (int i = 0; temp[i]; i++)
                    {
                        if (temp[i] >= 'A' && temp[i] <= 'Z')
                            temp[i] = temp[i] - 'A' + 'a';
                    }

                    if (strcmp(temp, "stop") == 0)
                    {
                        task2(0, 0);
                        PRINTF("Motor stopped.\r\n");
                    }
                    else
                    {
                        char *endptr;
                        long val = strtol(cmdBuffer, &endptr, 10);
                        // 跳过尾部空格
                        while (*endptr == ' ') endptr++;

                        if (*endptr != '\0' || val < -100 || val > 100)
                        {
                            PRINTF("Invalid input. Use -100~100 or 'stop'.\r\n");
                        }
                        else
                        {
                            if (val > 0)
                            {
                                task2(1, (int)val);
                                PRINTF("Forward %ld%%\r\n", val);
                            }
                            else if (val < 0)
                            {
                                task2(2, (int)(-val));
                                PRINTF("Backward %ld%%\r\n", -val);
                            }
                            else
                            {
                                task2(0, 0);
                                PRINTF("Motor stopped.\r\n");
                            }
                        }
                    }
                }
                // 清空缓冲区并显示新提示符
                memset(cmdBuffer, 0, CMD_BUFFER_SIZE);
                cmdIndex = 0;
                PRINTF("Speed: ");
            }
            else if (receivedChar == '\b' || receivedChar == 127)
            {
                // 退格处理(同步更新显示)
                if (cmdIndex > 0)
                {
                    cmdIndex--;
                    cmdBuffer[cmdIndex] = '\0';
                    // 重绘当前行:回车 + 提示符 + 当前内容
                    PRINTF("\rSpeed: %s", cmdBuffer);
                    // 擦除残留字符
                    int len = strlen(cmdBuffer);
                    for (int i = len; i < CMD_BUFFER_SIZE - 1; i++)
                    {
                        PRINTF(" ");
                    }
                    PRINTF("\rSpeed: %s", cmdBuffer);
                }
            }
            else
            {
                if (cmdIndex < CMD_BUFFER_SIZE - 1)
                {
                    cmdBuffer[cmdIndex++] = (char)receivedChar;
                }
            }
        }
    }
    return 0;
}

该代码主要参考了下面这位大佬的帖子

【2025Let'sdo第4期】基于单片机的直流电机控制-开箱和过程帖-电子产品世界论坛

image.png

视频




阅读全文

推荐技术

返回顶部