本次使用的是核心板上的SW2和SW3分别作为方向和占空比的控制,生成后的工程已经有了20khzpwm的配置以及两个按键引脚的配置,所以直接写一个非常简单的按键逻辑即可
/*
* 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 "pin_mux.h"
#include "fsl_port.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#ifndef CTIMER_MAT_PWM_PERIOD_CHANNEL
#define CTIMER_MAT_PWM_PERIOD_CHANNEL kCTIMER_Match_3
#endif
#define PWM_FREQUENCY_HZ 20000U
#define DUTY_STEP_PERCENT 10U
/*******************************************************************************
* Prototypes
******************************************************************************/
typedef enum _motor_direction
{
kMotorDirectionStop = 0U,
kMotorDirectionForward,
kMotorDirectionReverse
} motor_direction_t;
static void Motor_SetDirection(motor_direction_t direction);
static status_t Motor_UpdateDutyCycle(uint8_t dutyCyclePercent);
static void Buttons_Init(void);
static bool Button_LevelHigh(GPIO_Type *gpio, uint32_t pin);
/*******************************************************************************
* Variables
******************************************************************************/
volatile uint32_t g_pwmPeriod = 0U;
volatile uint32_t g_pulsePeriod = 0U;
static uint8_t s_currentDutyCycle = DUTY_CYCLE;
static motor_direction_t s_currentDirection = kMotorDirectionStop;
static bool s_sw2IdleLevel = true;
static bool s_sw3IdleLevel = true;
/*******************************************************************************
* 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;
}
static void Motor_SetDirection(motor_direction_t direction)
{
s_currentDirection = direction;
switch (direction)
{
case kMotorDirectionForward:
GPIO_PinWrite(BOARD_INITPINS_AIN1_GPIO, BOARD_INITPINS_AIN1_PIN, 1U);
GPIO_PinWrite(BOARD_INITPINS_AIN2_GPIO, BOARD_INITPINS_AIN2_PIN, 0U);
break;
case kMotorDirectionReverse:
GPIO_PinWrite(BOARD_INITPINS_AIN1_GPIO, BOARD_INITPINS_AIN1_PIN, 0U);
GPIO_PinWrite(BOARD_INITPINS_AIN2_GPIO, BOARD_INITPINS_AIN2_PIN, 1U);
break;
case kMotorDirectionStop:
default:
GPIO_PinWrite(BOARD_INITPINS_AIN1_GPIO, BOARD_INITPINS_AIN1_PIN, 0U);
GPIO_PinWrite(BOARD_INITPINS_AIN2_GPIO, BOARD_INITPINS_AIN2_PIN, 0U);
break;
}
}
static status_t Motor_UpdateDutyCycle(uint8_t dutyCyclePercent)
{
status_t status =
CTIMER_UpdatePwmDutycycle(CTIMER, CTIMER_MAT_PWM_PERIOD_CHANNEL, CTIMER_MAT_OUT, dutyCyclePercent);
if (status == kStatus_Success)
{
/* Keep cached values in sync for debugging */
g_pulsePeriod = (g_pwmPeriod + 1U) * (100U - dutyCyclePercent) / 100U;
s_currentDutyCycle = dutyCyclePercent;
}
return status;
}
static void Buttons_Init(void)
{
/* Enable GPIO clock for SW3 (GPIO1) in case it is not already enabled */
CLOCK_EnableClock(kCLOCK_GateGPIO1);
/* Ensure GPIO and PORT clocks are enabled for both switch ports */
CLOCK_EnableClock(kCLOCK_GatePORT1);
CLOCK_EnableClock(kCLOCK_GatePORT3);
CLOCK_EnableClock(kCLOCK_GateGPIO1);
CLOCK_EnableClock(kCLOCK_GateGPIO3);
const port_pin_config_t switch_config = {.pullSelect = kPORT_PullUp,
.pullValueSelect = kPORT_LowPullResistor,
.slewRate = kPORT_FastSlewRate,
.passiveFilterEnable = kPORT_PassiveFilterDisable,
.openDrainEnable = kPORT_OpenDrainDisable,
.driveStrength = kPORT_LowDriveStrength,
.driveStrength1 = kPORT_NormalDriveStrength,
.mux = kPORT_MuxAsGpio,
.inputBuffer = kPORT_InputBufferEnable,
.invertInput = kPORT_InputNormal,
.lockRegister = kPORT_UnlockRegister};
PORT_SetPinConfig(PORT3, BOARD_SW2_GPIO_PIN, &switch_config);
PORT_SetPinConfig(PORT1, BOARD_SW3_GPIO_PIN, &switch_config);
gpio_pin_config_t sw_config = {.pinDirection = kGPIO_DigitalInput, .outputLogic = 0U};
GPIO_PinInit(BOARD_SW2_GPIO, BOARD_SW2_GPIO_PIN, &sw_config);
GPIO_PinInit(BOARD_SW3_GPIO, BOARD_SW3_GPIO_PIN, &sw_config);
s_sw2IdleLevel = Button_LevelHigh(BOARD_SW2_GPIO, BOARD_SW2_GPIO_PIN);
s_sw3IdleLevel = Button_LevelHigh(BOARD_SW3_GPIO, BOARD_SW3_GPIO_PIN);
}
static bool Button_LevelHigh(GPIO_Type *gpio, uint32_t pin)
{
return (GPIO_PinRead(gpio, pin) != 0U);
}
/*!
* @brief Main function
*/
int main(void)
{
ctimer_config_t config;
uint32_t srcClock_Hz;
uint32_t timerClock;
/* Init 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(&config);
timerClock = srcClock_Hz / (config.prescale + 1);
CTIMER_Init(CTIMER, &config);
/* Get the PWM period match value and pulse width match value of PWM_FREQUENCY_HZ PWM signal with DUTY_CYCLE */
CTIMER_GetPwmPeriodValue(PWM_FREQUENCY_HZ, (uint8_t)DUTY_CYCLE, timerClock);
CTIMER_SetupPwmPeriod(CTIMER, CTIMER_MAT_PWM_PERIOD_CHANNEL, CTIMER_MAT_OUT, g_pwmPeriod, g_pulsePeriod, false);
CTIMER_StartTimer(CTIMER);
Motor_SetDirection(s_currentDirection);
Buttons_Init();
PRINTF("SW2: cycle DIR (STOP->FWD->REV), SW3: duty +10%% (wrap 0-100%%)\r\n");
PRINTF("DIR: STOP, DUTY: %u%%\r\n", s_currentDutyCycle);
bool prevSw2 = Button_LevelHigh(BOARD_SW2_GPIO, BOARD_SW2_GPIO_PIN);
bool prevSw3 = Button_LevelHigh(BOARD_SW3_GPIO, BOARD_SW3_GPIO_PIN);
while (1)
{
bool sw2 = Button_LevelHigh(BOARD_SW2_GPIO, BOARD_SW2_GPIO_PIN);
bool sw3 = Button_LevelHigh(BOARD_SW3_GPIO, BOARD_SW3_GPIO_PIN);
if (sw2 != prevSw2)
{
SDK_DelayAtLeastUs(10000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
sw2 = Button_LevelHigh(BOARD_SW2_GPIO, BOARD_SW2_GPIO_PIN);
if (sw2 != prevSw2)
{
prevSw2 = sw2;
if (sw2 != s_sw2IdleLevel)
{
if (s_currentDirection == kMotorDirectionStop)
{
s_currentDirection = kMotorDirectionForward;
}
else if (s_currentDirection == kMotorDirectionForward)
{
s_currentDirection = kMotorDirectionReverse;
}
else
{
s_currentDirection = kMotorDirectionStop;
}
Motor_SetDirection(s_currentDirection);
const char *dirStr = (s_currentDirection == kMotorDirectionForward)
? "FWD"
: ((s_currentDirection == kMotorDirectionReverse) ? "REV" : "STOP");
PRINTF("DIR: %s, DUTY: %u%%\r\n", dirStr, s_currentDutyCycle);
}
}
}
if (sw3 != prevSw3)
{
SDK_DelayAtLeastUs(10000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
sw3 = Button_LevelHigh(BOARD_SW3_GPIO, BOARD_SW3_GPIO_PIN);
if (sw3 != prevSw3)
{
prevSw3 = sw3;
if (sw3 != s_sw3IdleLevel)
{
uint8_t nextDuty = (uint8_t)((s_currentDutyCycle + DUTY_STEP_PERCENT) % 110U);
if (nextDuty > 100U)
{
nextDuty = 0U;
}
if (Motor_UpdateDutyCycle(nextDuty) == kStatus_Success)
{
PRINTF("DUTY: %u%%, DIR: %s\r\n", s_currentDutyCycle,
(s_currentDirection == kMotorDirectionForward) ? "FWD" : "REV");
}
}
}
}
prevSw2 = sw2;
prevSw3 = sw3;
}
}可以在示波器清晰的看到PWM的波形
我要赚赏金
