设置好了开发环境,就着手开始开发控制电机的代码。
一、 硬件接线
首先要弄清楚驱动板 TB6612FNG 的接线要求,如下图所示。

PWMA ---- 控制第1路电机的 PWM调速信号
AIN1、AIN2 ---- 依次为LH为反转,为HL是正转(控制方向的)。
VM ---- 要接 电机的动力电源。
VCC、GND -----接控制的 3.3V 和 0V
STBY ------ 接高电平,才能输出,否则电机都不输出
AO1、AO2--------接到电机上,没有正负极,接反电机会反转。
根据以上要求,我将开发板上的信号分配如下:
P1_4 : 调速用PWM信号
P3_9 和 P3_10:控制方向的 AIN1 和 AIN2
P3_6 和 P3_7: OLED屏的I2C通讯线,SDA 和 SCL
P3_12: 板载的LED 红色灯。
实际的接线情况如下:

二、 软件开发
从下载的 SDK 中 \boards\frdmmcxa153\driver_examples\ctimer\ 目录下有一个 PWM的例子工程:simple_pwm。 将此工程导入到 VSCode 中,编译运行下载,会在 P1_4 产生一个占空比 20% 的PWM信号,正是我想要的。
测试下PWM有没有输出,手头没有示波器,用万用表量了下,有0.65V左右电压,刚好是 3.3V 的 20%,看来PWM输出正常!
接下来需要做的,就是:
(1)添加 GPIO 控制2个AIN1 和 AIN2 输出,用于控制电机的方向。
(2)添加两个GPIO 开漏输出,用于驱动I2C的OLED屏幕显示。
(3)添加板载的LED_RED 红色小灯的输出。
打开 config 工具,添加以下5个针脚并配置好功能:

代码里封装一个控制电机的文件 pwm_motor.c 文件, 代码如下:
#include "fsl_gpio.h"
#include "fsl_port.h"
#include "fsl_ctimer.h"
#include "fsl_clock.h"
#include "fsl_common.h"
#define MOTOR_CTL_PORT PORT3
#define MOTOR_CTL_GPIO GPIO3
#define MOTOR_CTL_CLOCK kCLOCK_GateGPIO3
#define MOTOR_IN1_PIN 9U //针脚定义
#define MOTOR_IN2_PIN 10U //针脚定义
#define MOTOR_PWM_PIN 11U //针脚定义
/* PWM 常量*/
#define MOTOR_PWM_CTIMER CTIMER1
#define MOTOR_PWM_MATCH_PERIOD kCTIMER_Match_0 // 周期
#define MOTOR_PWM_MATCH_DUTY kCTIMER_Match_1 // MAT1 输出
#define MOTOR_PWM_MUX kPORT_MuxAlt3 // PWM 功能复用
#define PWM_FREQ_HZ 20000U // 20 kHz
#define PWM_RESOLUTION 100U // 0–99/
//保存PWM周期
volatile static uint32_t g_pwmPeriodCount = 0;
// 设置占空比 0-99
void MotorPwm_SetDuty(uint8_t duty)
{
if (duty > 99) duty = 99;
CTIMER1->MR[1] = (CTIMER1->MR[0] + 1) * duty / 100; // 更新占空比
// 不需要 LER
}
void motor_pwm_init();
//motor控制线3根:初始化
void motor_ctl_init()
{
/* ---------------------------
* 方向控制:两个输出
* ---------------------------*/
//初始化电机 MOTOR_IN1_PIN 和 MOTOR_IN2_PIN 为推挽输出
//CLOCK_EnableClock(MOTOR_CTL_CLOCK);
gpio_pin_config_t motor_pin_config = {
kGPIO_DigitalOutput, 0,
};
GPIO_PinInit(MOTOR_CTL_GPIO, MOTOR_IN1_PIN, &motor_pin_config);
GPIO_PinInit(MOTOR_CTL_GPIO, MOTOR_IN2_PIN, &motor_pin_config);
//输出IN1 和 IN2 初始值
GPIO_PinWrite(MOTOR_CTL_GPIO, MOTOR_IN1_PIN, 0);
GPIO_PinWrite(MOTOR_CTL_GPIO, MOTOR_IN2_PIN, 1);
/* ---------------------------
* 速度控制:1个PWM输出
* ---------------------------*/
//motor_pwm_init();
}
//设置电机的速度,speed范围0~100
//方向用正负表示,IN1和IN2控制方向:LH=反转,HL=正转
void motor_set_speed(int8_t speed)
{
//限位到 -100 到 100
if(speed < -100) speed = -100;
if(speed > 100) speed = 100;
//设置方向
if(speed >= 0) {
GPIO_PinWrite(MOTOR_CTL_GPIO, MOTOR_IN1_PIN, 1);
GPIO_PinWrite(MOTOR_CTL_GPIO,MOTOR_IN2_PIN, 0);
} else if(speed < 0) {
GPIO_PinWrite(MOTOR_CTL_GPIO,MOTOR_IN1_PIN, 0);
GPIO_PinWrite(MOTOR_CTL_GPIO,MOTOR_IN2_PIN, 1);
speed = -speed; //取正值用于占空比计算
}
//设置PWM占空比
CTIMER_UpdatePwmDutycycle(
MOTOR_PWM_CTIMER,
kCTIMER_Match_3,
kCTIMER_Match_2,
speed
);
}
头文件也导出下 pwm_motor.h, 代码如下:
#pragma once #include <stdint.h> void motor_set_speed(int8_t speed); void motor_ctl_init();
主函数里加上 对OLED初始化和 输出string的函数,并且在 while(1) 循环中加入 LED红灯闪烁的代码,和 设置占空比的函数,完整代码如下:
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2020, 2025 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* Includes
******************************************************************************/
#include "fsl_debug_console.h"
#include "board.h"
#include "app.h"
#include "fsl_ctimer.h"
#include "hardware/OLED.h"
#include "hardware/pwm_motor.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#ifndef CTIMER_MAT_PWM_PERIOD_CHANNEL
#define CTIMER_MAT_PWM_PERIOD_CHANNEL kCTIMER_Match_3
#endif
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
volatile uint32_t g_pwmPeriod = 0U;
volatile uint32_t g_pulsePeriod = 0U;
/*******************************************************************************
* Code
******************************************************************************/
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;
}
/*!
* @brief Main function
*/
int main(void)
{
ctimer_config_t config;
uint32_t srcClock_Hz;
uint32_t timerClock;
/* Init hardware*/
BOARD_InitHardware();
__disable_irq();
OLED_Init();
OLED_ShowString(1,1,"Hello OLED~~~");
__enable_irq();
// /* 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(&config);
timerClock = srcClock_Hz / (config.prescale + 1);
CTIMER_Init(CTIMER, &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, timerClock);
CTIMER_SetupPwmPeriod(CTIMER, CTIMER_MAT_PWM_PERIOD_CHANNEL, CTIMER_MAT_OUT, g_pwmPeriod, g_pulsePeriod, false);
CTIMER_StartTimer(CTIMER);
while (1)
{
SDK_DelayAtLeastUs(2000 * 1000, CLOCK_GetCoreSysClkFreq());
GPIO_PortToggle(BOARD_LED_RED_GPIO, 1u << BOARD_LED_RED_GPIO_PIN);
//更改占空比(最大45)
motor_set_speed(-15);
}
}
最后测试一下,刚开始占空比10%,小风扇居然不转。是不是阻力太大了?直接改为占空比30%,小风扇就呼呼呼的转起来了~~~~~ 速度改成负数,方向输出也相应的改变,风扇风向果然就不一样了!开心~
至此,基础任务已完成。后面想办法让风声占空比 自动变化起来。
我要赚赏金
