本期我们要谈的是如何控制电机的正反转以及调速
首先我们先简单介绍一下电机驱动模块

我们控制电机的正反转,只需要改变ain1ain2的高低电平组合就可以
举例ain1输出高 ,ain2输出低 电机正转
ain1输出低 ,ain2输出高 电机反转转
电机转速快慢是由PWMA进行控制的,100%占空比时电机全速运行
0%占空比时电机停止运行
下面shi一些手册描述内容:

大概原理就是这样
我们需要两路gpio输出高低电平组合信号
一路gpio输出占空比可调的PWM信号
同时使用开发板上两个按键用于输入采集
一个按键控制电机正反转
一个按键控制PWM信号是否输出以实现电机启停的控制
或不多说,接下来开始编写代码
我们本次基础工程使用的是frdmmcxa153_freertos_hello
以下是两个按键所连接的引脚


接下来通过RGB等的两个引脚去控制电机正反转,这样可以通过灯的颜色轻松辨别电机控制信号引脚状态

接下来在放上一张引脚布局图,后面从这里边找一个引脚用于输出pwm信号

首先我们导入工程

根据上述原理图配置引脚关系

至于如何实现按键输入检测及pwm波形控制可参考如下工程

接下来我们添加代码
/*
* Copyright 2023 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _APP_H_
#define _APP_H_
/*******************************************************************************
* Definitions
******************************************************************************/
/*${macro:start}*/
#define AIN_1_GPIO BOARD_LED_RED_GPIO
#define AIN_1_GPIO_PIN BOARD_LED_RED_GPIO_PIN
#define AIN_2_GPIO BOARD_LED_GREEN_GPIO
#define AIN_2_GPIO_PIN BOARD_LED_GREEN_GPIO_PIN
#define KEY_1_GPIO BOARD_SW2_GPIO
#define KEY_1_GPIO_PIN BOARD_SW2_GPIO_PIN
#define KEY_1_NAME BOARD_SW2_NAME
#define KEY_1_IRQ BOARD_SW2_IRQ
#define KEY_1_IRQ_HANDLER BOARD_SW2_IRQ_HANDLER
#define KEY_2_GPIO BOARD_SW3_GPIO
#define KEY_2_GPIO_PIN BOARD_SW3_GPIO_PIN
#define KEY_2_NAME BOARD_SW3_NAME
#define KEY_2_IRQ BOARD_SW3_IRQ
#define KEY_2_IRQ_HANDLER BOARD_SW3_IRQ_HANDLER
#define CTIMER CTIMER1 /* Timer 1 */
#define CTIMER_MAT_OUT kCTIMER_Match_2 /* Match output 2 */
#define CTIMER_CLK_FREQ CLOCK_GetCTimerClkFreq(1U)
/*${macro:end}*/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*${prototype:start}*/
void BOARD_InitHardware(void);
/*${prototype:end}*/
#endif /* _APP_H_ *//*
* Copyright 2023 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*${header:start}*/
#include "pin_mux.h"
#include "fsl_clock.h"
#include "fsl_reset.h"
#include "board.h"
#include <stdbool.h>
/*${header:end}*/
/*${function:start}*/
void BOARD_InitHardware(void)
{
CLOCK_EnableClock(kCLOCK_GateGPIO3);
/* CTimer functional clock needs to be greater than or equal to SYSTEM_CLK */
CLOCK_SetClockDiv(kCLOCK_DivCTIMER1, 1u);
CLOCK_AttachClk(kFRO_HF_to_CTIMER1);
BOARD_InitPins();
BOARD_InitBootClocks();
BOARD_InitDebugConsole();
}
/*${function:end}*//* * Copyright 2025 NXP * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _MCUX_CONFIG_H_ #define _MCUX_CONFIG_H_ #define DUTY_CYCLE 20U #define CONFIG_CPU_CORTEX_M 1 #define CONFIG_FLASH_BASE_ADDRESS 0x0 #define CONFIG_FLASH_DEFAULT_APP_OFFSET 0x0 #define CONFIG_HAS_FLASH_LOAD_OFFSET 1 #define CONFIG_FLASH_LOAD_OFFSET 0x0 #define CONFIG_UART_RETRY_TIMES 0 // #define CONFIG_FLASH_DRIVER_EXECUTES_FROM_RAM 0 // #define CONFIG_ENABLE_QUICKACCESS_SECTION_IN_XSPI_DRIVER 0 // #define CONFIG_STREAM_FLASH 0 // #define LIB_JPEG_USE_HW_ACCEL 0 // #define USE_PNGDEC_DRIVER 0 // #define CONFIG_BOOT_CUSTOM_DEVICE_SETUP 0 // #define CONFIG_FREERTOS_USE_CUSTOM_CONFIG_FRAGMENT 0 // #define MPU_SUPPORT 0 // #define USE_PERCEPIO_TRACELYZER 0 #endif /* _MCUX_CONFIG_H_ */
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* FreeRTOS kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "timers.h"
/* Freescale includes. */
#include "fsl_device_registers.h"
#include "fsl_debug_console.h"
#if defined(FSL_FEATURE_SOC_PORT_COUNT) && (FSL_FEATURE_SOC_PORT_COUNT)
#include "fsl_port.h"
#endif
#include "fsl_gpio.h"
#include "fsl_common.h"
#include "pin_mux.h"
#include "board.h"
#include "app.h"
#include "fsl_ctimer.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/* Task priorities. */
#define hello_task_PRIORITY (configMAX_PRIORITIES - 1)
#ifndef CTIMER_MAT_PWM_PERIOD_CHANNEL
#define CTIMER_MAT_PWM_PERIOD_CHANNEL kCTIMER_Match_3
#endif
#define MAX_MOTOR_SPEED 50U
#define MIN_MOTOR_SPEED 0U
#define APP_DELAY_TICK 33U
/*******************************************************************************
* Prototypes
******************************************************************************/
static void hello_task(void *pvParameters);
/*******************************************************************************
* Variables
******************************************************************************/
/* Whether the SW button is pressed */
volatile bool g_Button_1_Press = true;
volatile bool g_motor_dir = false;
volatile bool g_Button_2_Press = false;
volatile bool g_motor_run_flag = true;
volatile bool g_motor_speed_dir = true;
volatile uint8_t g_motor_speed = MIN_MOTOR_SPEED;
volatile uint32_t g_timerClock= 0U;
volatile uint32_t g_pwmPeriod = 0U;
volatile uint32_t g_pulsePeriod = 0U;
/*******************************************************************************
* Code
******************************************************************************/
/*!
* @brief Interrupt service fuction of switch.
*
* This function toggles the LED
*/
void KEY_1_IRQ_HANDLER(void)
{
#if (defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) || \
(!defined(FSL_FEATURE_SOC_PORT_COUNT))
/* Clear external interrupt flag. */
GPIO_GpioClearInterruptFlags(KEY_1_GPIO, 1U << KEY_1_GPIO_PIN);
#else
/* Clear external interrupt flag. */
GPIO_PortClearInterruptFlags(KEY_1_GPIO, 1U << KEY_1_GPIO_PIN);
#endif
/* Change state of button. */
g_Button_1_Press = true;
SDK_ISR_EXIT_BARRIER;
}
void KEY_2_IRQ_HANDLER(void)
{
#if (defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) || \
(!defined(FSL_FEATURE_SOC_PORT_COUNT))
/* Clear external interrupt flag. */
GPIO_GpioClearInterruptFlags(KEY_2_GPIO, 1U << KEY_2_GPIO_PIN);
#else
/* Clear external interrupt flag. */
GPIO_PortClearInterruptFlags(KEY_2_GPIO, 1U << KEY_2_GPIO_PIN);
#endif
/* Change state of button. */
g_Button_2_Press = true;
SDK_ISR_EXIT_BARRIER;
}
status_t CTIMER_GetPwmPeriodValue(uint32_t pwmFreqHz, uint8_t dutyCyclePercent, uint32_t timerClock_Hz)
{
/* Calculate PWM period match value */
g_pwmPeriod = (timerClock_Hz / pwmFreqHz) - 1U;
/* Calculate pulse width match value */
g_pulsePeriod = (g_pwmPeriod + 1U) * (100 - dutyCyclePercent) / 100;
return kStatus_Success;
}
void motor_speed_set(uint8_t u8speed)
{
CTIMER_GetPwmPeriodValue(20000, u8speed, g_timerClock);
CTIMER_SetupPwmPeriod(CTIMER, CTIMER_MAT_PWM_PERIOD_CHANNEL, CTIMER_MAT_OUT, g_pwmPeriod, g_pulsePeriod, false);
}
/*!
* @brief Application entry point.
*/
int main(void)
{
ctimer_config_t pwm_config;
uint32_t srcClock_Hz;
/* Define the init structure for the input switch pin */
gpio_pin_config_t sw_config = {
kGPIO_DigitalInput,
0,
};
/* Define the init structure for the output LED pin*/
gpio_pin_config_t ain_config = {
kGPIO_DigitalOutput,
1,
};
/* Init board hardware. */
BOARD_InitHardware();
PRINTF("MCUX SDK version: %s\r\n", MCUXSDK_VERSION_FULL_STR);
/* CTimer0 counter uses the AHB clock, some CTimer1 modules use the Aysnc clock */
srcClock_Hz = CTIMER_CLK_FREQ;
PRINTF("CTimer example to generate a PWM signal\r\n");
CTIMER_GetDefaultConfig(&pwm_config);
g_timerClock = srcClock_Hz / (pwm_config.prescale + 1);
CTIMER_Init(CTIMER, &pwm_config);
/* Get the PWM period match value and pulse width match value of 20Khz PWM signal with 20% dutycycle */
CTIMER_GetPwmPeriodValue(20000, (uint8_t)DUTY_CYCLE, g_timerClock);
CTIMER_SetupPwmPeriod(CTIMER, CTIMER_MAT_PWM_PERIOD_CHANNEL, CTIMER_MAT_OUT, g_pwmPeriod, g_pulsePeriod, false);
CTIMER_StartTimer(CTIMER);
/* Init input switch GPIO. */
#if (defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) || \
(!defined(FSL_FEATURE_SOC_PORT_COUNT))
GPIO_SetPinInterruptConfig(KEY_1_GPIO, KEY_1_GPIO_PIN, kGPIO_InterruptFallingEdge);
#else
PORT_SetPinInterruptConfig(KEY_1_GPIO, KEY_1_GPIO_PIN, kPORT_InterruptFallingEdge);
#endif
EnableIRQ(KEY_1_IRQ);
GPIO_PinInit(KEY_1_GPIO, KEY_1_GPIO_PIN, &sw_config);
/* Init input switch GPIO. */
#if (defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT) || \
(!defined(FSL_FEATURE_SOC_PORT_COUNT))
GPIO_SetPinInterruptConfig(KEY_2_GPIO, KEY_2_GPIO_PIN, kGPIO_InterruptFallingEdge);
#else
PORT_SetPinInterruptConfig(KEY_2_GPIO, KEY_2_GPIO_PIN, kPORT_InterruptFallingEdge);
#endif
EnableIRQ(KEY_2_IRQ);
GPIO_PinInit(KEY_2_GPIO, KEY_2_GPIO_PIN, &sw_config);
/* Init output AIN GPIO. */
GPIO_PinInit(AIN_1_GPIO, AIN_1_GPIO_PIN, &ain_config);
GPIO_PinInit(AIN_2_GPIO, AIN_2_GPIO_PIN, &ain_config);
if (xTaskCreate(hello_task, "Hello_task", configMINIMAL_STACK_SIZE + 100, NULL, hello_task_PRIORITY, NULL) !=
pdPASS)
{
PRINTF("Task creation failed!.\r\n");
while (1)
;
}
vTaskStartScheduler();
for (;;)
;
}
/*!
* @brief Task responsible for printing of "Hello world." message.
*/
static void hello_task(void *pvParameters)
{
for (;;)
{
//PRINTF("Hello world.\r\n");
if (g_Button_1_Press)
{
PRINTF(" %s is pressed \r\n", KEY_1_NAME);
g_Button_1_Press = false;
g_motor_dir = g_motor_dir ? false : true;
PRINTF(" motor dir is %d \r\n", g_motor_dir);
if (g_motor_dir)
{
GPIO_PinWrite(AIN_1_GPIO, AIN_1_GPIO_PIN, LOGIC_LED_ON);
GPIO_PinWrite(AIN_2_GPIO, AIN_2_GPIO_PIN, LOGIC_LED_OFF);
}
else
{
GPIO_PinWrite(AIN_1_GPIO, AIN_1_GPIO_PIN, LOGIC_LED_OFF);
GPIO_PinWrite(AIN_2_GPIO, AIN_2_GPIO_PIN, LOGIC_LED_ON);
}
}
if (g_Button_2_Press)
{
PRINTF(" %s is pressed \r\n", KEY_2_NAME);
/* Reset state of button. */
g_Button_2_Press = false;
g_motor_run_flag ^= 1;
}
if (g_motor_speed_dir)
{
g_motor_speed++;
if (g_motor_speed >= MAX_MOTOR_SPEED)
{
g_motor_speed_dir = false;
}
}
else
{
g_motor_speed--;
if (g_motor_speed <= MIN_MOTOR_SPEED)
{
g_motor_speed_dir = true;
}
}
if (g_motor_run_flag)
{
motor_speed_set(g_motor_speed);
PRINTF(" motor speed is %d \r\n", g_motor_speed);
}
else
{
motor_speed_set((uint8_t) 0);
PRINTF(" motor speed is %d \r\n", 0);
}
vTaskDelay(APP_DELAY_TICK);
}
}最后烧录程序

以上是程序调试运行结果

这个是电机启动停止模式切换打印

这个是方向控制状态切换的打印信息
至此已完成基础任务部分
基础任务:
1.电机启停与方向控制:通过程序实现电机的启动、停止、正转和反转。
2.电机调速控制:编写一个函数,可以通过输入参数(如0-100)来改变PWM的占空比,从而控制速度。
实物展示

电机正转,状态灯红色

电机反转,状态灯绿色
我要赚赏金
