Arduino IDE下使用STM32开发板脉冲控制步进电机(二)按钮控制
改用按钮(常开,脉冲)控制
接线和代码如下:
-
每个按钮一端接 3.3V
-
另一端分别接 PB0、PB1、PB5(无PB2,实际上是Boot1非普通IO,PB3 默认是 JTDO,调试引脚)
/* * CA-4022M 步进电机驱动器控制程序 * 功能:通过串口命令或物理按钮控制电机 * 硬件:STM32F103C8T6 + CA-4022M驱动器 * * 按钮定义: * Button A (PB0) - 低速往复5次(脉冲触发) * Button B (PB1) - 高速往复5次(脉冲触发) * Button C (PB2) - 停止运动(脉冲触发) */ // ==================== 引脚定义 ==================== #define PUL_PIN PA0 // 脉冲输出引脚 #define DIR_PIN PA1 // 方向控制引脚 #define LED_PIN PC13 // 板载LED引脚 // ==================== 按钮引脚定义 ==================== #define BTN_A_PIN PB0 // 按钮A - 低速往复 #define BTN_B_PIN PB1 // 按钮B - 高速往复 #define BTN_C_PIN PB5 // 按钮C - 停止 // ==================== 按钮状态变量 ==================== bool lastBtnAState = LOW; bool lastBtnBState = LOW; bool lastBtnCState = LOW; unsigned long lastDebounceTimeA = 0; unsigned long lastDebounceTimeB = 0; unsigned long lastDebounceTimeC = 0; #define DEBOUNCE_DELAY 50 // 消抖延时50ms // ==================== LED状态枚举 ==================== enum LEDState { LED_OFF, LED_BLINK_FAST, LED_ON }; LEDState currentLEDState = LED_OFF; unsigned long lastLEDUpdate = 0; bool ledBlinkState = false; // ==================== 运动控制变量 ==================== String inputString = ""; boolean stringComplete = false; int currentFreq = 0; bool motorRunning = false; // 往复运动相关变量 volatile long pulseCount = 0; int targetPulses = 0; bool isReversing = false; bool needReverse = false; // 往复次数控制变量 int totalCycles = 0; int currentCycle = 0; bool cycleComplete = false; // 暂停控制变量 bool isPausing = false; unsigned long pauseStartTime = 0; #define PAUSE_DURATION_MS 500 // ==================== 运动模式枚举 ==================== enum MotionMode { MODE_IDLE, MODE_LOW_SPEED, MODE_HIGH_SPEED, MODE_MANUAL }; MotionMode currentMode = MODE_IDLE; // ==================== 运动参数定义 ==================== #define LOW_SPEED_PULSES 1600 #define HIGH_SPEED_PULSES 500 #define MOTION_TIME_MS 3000 #define LOW_SPEED_FREQ (LOW_SPEED_PULSES * 1000 / MOTION_TIME_MS) #define HIGH_SPEED_FREQ (HIGH_SPEED_PULSES * 1000 / MOTION_TIME_MS) // ==================== 硬件定时器对象 ==================== HardwareTimer *pwmTimer; // ==================== 定时器中断服务函数 ==================== void onPulseCompare() { pulseCount++; if (pulseCount >= targetPulses) { needReverse = true; } } // ==================== LED控制函数 ==================== void setLEDState(LEDState newState, const char* reason) { if (currentLEDState != newState) { currentLEDState = newState; Serial.print("[LED] "); switch(newState) { case LED_OFF: Serial.println("熄灭 - 电机空闲或停止"); break; case LED_BLINK_FAST: Serial.println("快速闪烁(300ms) - 电机正在运行"); break; case LED_ON: Serial.println("常亮 - 到达正向终点"); break; } if (strlen(reason) > 0) { Serial.print(" 原因: "); Serial.println(reason); } } } // ==================== 更新LED物理状态 ==================== void updateLED() { unsigned long currentMillis = millis(); switch(currentLEDState) { case LED_OFF: digitalWrite(LED_PIN, HIGH); break; case LED_ON: digitalWrite(LED_PIN, LOW); break; case LED_BLINK_FAST: if (currentMillis - lastLEDUpdate >= 300) { ledBlinkState = !ledBlinkState; digitalWrite(LED_PIN, ledBlinkState ? LOW : HIGH); lastLEDUpdate = currentMillis; } break; } } // ==================== 按钮处理函数 ==================== // ==================== 极简按钮处理(专门用于导线测试)==================== void checkButtons() { static unsigned long lastBtnTime = 0; // 每500ms最多检测一次,避免连续触发 if (millis() - lastBtnTime < 500) return; if (digitalRead(BTN_A_PIN) == HIGH) { lastBtnTime = millis(); Serial.println("\n[按钮] PB0 高电平 - 启动低速往复"); currentMode = MODE_LOW_SPEED; startOscillation(LOW_SPEED_PULSES, LOW_SPEED_FREQ, 5, "低速(按钮)"); } if (digitalRead(BTN_B_PIN) == HIGH) { lastBtnTime = millis(); Serial.println("\n[按钮] PB1 高电平 - 启动高速往复"); currentMode = MODE_HIGH_SPEED; startOscillation(HIGH_SPEED_PULSES, HIGH_SPEED_FREQ, 5, "高速(按钮)"); } if (digitalRead(BTN_C_PIN) == HIGH) { lastBtnTime = millis(); Serial.println("\n[按钮] PB2 高电平 - 停止"); stopMotion(); } } // ==================== 初始化设置 ==================== void setup() { Serial.begin(115200); Serial.println(); Serial.println("========================================"); Serial.println(" CA-4022M 电机控制程序 - 按钮控制版"); Serial.println("========================================"); pinMode(DIR_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT); // ===== 初始化按钮引脚(启用下拉电阻)===== pinMode(BTN_A_PIN, INPUT_PULLDOWN); pinMode(BTN_B_PIN, INPUT_PULLDOWN); pinMode(BTN_C_PIN, INPUT_PULLDOWN); // 对于PB3/PB4,需要禁用JTAG功能 //GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); digitalWrite(DIR_PIN, LOW); digitalWrite(LED_PIN, HIGH); // 初始化PWM pwmTimer = new HardwareTimer(TIM2); pwmTimer->setPrescaleFactor(1); pwmTimer->setOverflow(1000, HERTZ_FORMAT); pwmTimer->setCaptureCompare(1, 50, PERCENT_COMPARE_FORMAT); pwmTimer->setMode(1, TIMER_OUTPUT_COMPARE_PWM1, PUL_PIN); pwmTimer->setCaptureCompare(1, 50, PERCENT_COMPARE_FORMAT); pwmTimer->attachInterrupt(1, onPulseCompare); pwmTimer->pause(); Serial.println("[信息] 硬件PWM中断初始化完成"); Serial.println("[信息] 按钮已初始化:A-低速 B-高速 C-停止"); setLEDState(LED_OFF, "系统初始化完成"); printMenu(); inputString.reserve(64); } // ==================== 设置PWM频率 ==================== void setPWMFrequency(uint32_t freqHz) { if (freqHz == 0) { pwmTimer->pause(); return; } if (freqHz < 10) freqHz = 10; if (freqHz > 100000) freqHz = 100000; pwmTimer->pause(); pwmTimer->setOverflow(freqHz, HERTZ_FORMAT); pwmTimer->setCaptureCompare(1, 50, PERCENT_COMPARE_FORMAT); pwmTimer->resume(); } // ==================== 开始往复运动 ==================== void startOscillation(int pulsesPerCycle, int freqHz, int cycles, const char* modeName) { stopMotion(); currentFreq = freqHz; targetPulses = pulsesPerCycle; totalCycles = cycles; currentCycle = 0; pulseCount = 0; needReverse = false; isReversing = false; isPausing = false; cycleComplete = false; digitalWrite(DIR_PIN, LOW); setPWMFrequency(freqHz); motorRunning = true; currentMode = (freqHz == LOW_SPEED_FREQ) ? MODE_LOW_SPEED : MODE_HIGH_SPEED; setLEDState(LED_BLINK_FAST, "开始运动"); Serial.print("[信息] 开始"); Serial.print(modeName); Serial.print("往复运动 ("); Serial.print(pulsesPerCycle); Serial.print("脉冲/单程,"); Serial.print(cycles); Serial.println("次往复后自动停止)"); } // ==================== 停止所有运动 ==================== void stopMotion() { setPWMFrequency(0); motorRunning = false; currentMode = MODE_IDLE; targetPulses = 0; totalCycles = 0; currentCycle = 0; pulseCount = 0; needReverse = false; isPausing = false; cycleComplete = false; setLEDState(LED_OFF, "运动停止"); Serial.println("[信息] 运动停止"); } // ==================== 主循环 ==================== void loop() { // 处理串口命令 if (stringComplete) { processCommand(inputString); inputString = ""; stringComplete = false; } // ===== 新增:检查按钮状态 ===== checkButtons(); // 处理往复运动的方向切换和次数控制 if (motorRunning && (currentMode == MODE_LOW_SPEED || currentMode == MODE_HIGH_SPEED)) { if (isPausing) { if (millis() - pauseStartTime >= PAUSE_DURATION_MS) { isPausing = false; if (currentCycle >= totalCycles) { stopMotion(); Serial.println("[信息] 已完成指定次数,运动结束"); } else { isReversing = true; digitalWrite(DIR_PIN, HIGH); pulseCount = 0; needReverse = false; setPWMFrequency(currentFreq); setLEDState(LED_BLINK_FAST, "暂停结束,开始反向运动"); Serial.println("[信息] 暂停结束,开始反向运动"); } } } if (needReverse && !isPausing) { needReverse = false; if (!isReversing) { Serial.println("[提示] 正向单程终点到达"); setLEDState(LED_ON, "到达正向终点"); setPWMFrequency(0); isPausing = true; pauseStartTime = millis(); Serial.println("[信息] 暂停500ms..."); } else { currentCycle++; Serial.print("[信息] 已完成 "); Serial.print(currentCycle); Serial.print("/"); Serial.print(totalCycles); Serial.println(" 次往复"); if (currentCycle >= totalCycles) { stopMotion(); Serial.println("[信息] 已完成指定次数,运动结束"); } else { isReversing = false; digitalWrite(DIR_PIN, LOW); pulseCount = 0; setLEDState(LED_BLINK_FAST, "开始下一个正向运动"); } } } } updateLED(); } // ==================== 串口接收事件 ==================== void serialEvent() { while (Serial.available()) { char inChar = (char)Serial.read(); Serial.print(inChar); if (inChar == '\n' || inChar == '\r') { if (inputString.length() > 0) { stringComplete = true; Serial.println(); } } else { inputString += inChar; } } } // ==================== 处理用户命令 ==================== void processCommand(String cmd) { cmd.trim(); cmd.toLowerCase(); Serial.println(); Serial.print("[收到] "); Serial.println(cmd); if (cmd.length() == 0) { printMenu(); return; } char cmdType = cmd.charAt(0); switch (cmdType) { case 'a': case 'b': { int spaceIndex = cmd.indexOf(' '); int cycles = 5; if (spaceIndex != -1) { String numStr = cmd.substring(spaceIndex + 1); int num = numStr.toInt(); if (num > 0) { cycles = num; } } if (cmdType == 'a') { startOscillation(LOW_SPEED_PULSES, LOW_SPEED_FREQ, cycles, "低速"); } else { startOscillation(HIGH_SPEED_PULSES, HIGH_SPEED_FREQ, cycles, "高速"); } break; } case 'f': case 'r': stopMotion(); currentMode = MODE_MANUAL; handleManualCommand(cmd); if (motorRunning) { setLEDState(LED_BLINK_FAST, "手动模式运行"); } break; case 's': stopMotion(); break; case 'p': printStatus(); break; case 'h': case '?': printMenu(); break; default: Serial.println("[错误] 未知命令"); printMenu(); } } // ==================== 处理手动F/R命令 ==================== void handleManualCommand(String cmd) { char dir = cmd.charAt(0); int spaceIndex = cmd.indexOf(' '); if (spaceIndex == -1) { Serial.println("[错误] 格式错误,正确格式: f 1000 或 r 1000"); return; } String freqStr = cmd.substring(spaceIndex + 1); int freq = freqStr.toInt(); if (freq < 0) { Serial.println("[错误] 频率不能为负数"); return; } digitalWrite(DIR_PIN, (dir == 'f') ? LOW : HIGH); Serial.print("[信息] 手动模式 - 方向: "); Serial.println(dir == 'f' ? "正转" : "反转"); setPWMFrequency(freq); motorRunning = (freq > 0); currentFreq = freq; } // ==================== 打印帮助菜单 ==================== void printMenu() { Serial.println("\n********** 可用命令 **********"); Serial.println(" a - 低速往复5次"); Serial.println(" a 10 - 低速往复10次"); Serial.println(" b - 高速往复5次"); Serial.println(" b 8 - 高速往复8次"); Serial.println(" s - 停止运动"); Serial.println(" f 1000 - 手动正转"); Serial.println(" r 500 - 手动反转"); Serial.println(" p - 显示状态"); Serial.println(" h 或 ? - 帮助"); Serial.println("\n物理按钮:"); Serial.println(" Button A - 低速往复5次"); Serial.println(" Button B - 高速往复5次"); Serial.println(" Button C - 停止"); Serial.println("\nLED指示:"); Serial.println(" 熄灭 - 空闲/停止"); Serial.println(" 快闪 - 运行中"); Serial.println(" 常亮 - 正向终点"); Serial.println("********************************\n"); } // ==================== 打印当前状态 ==================== void printStatus() { Serial.println("\n********** 当前状态 **********"); Serial.print("运行模式: "); switch(currentMode) { case MODE_IDLE: Serial.println("空闲"); break; case MODE_LOW_SPEED: Serial.println("低速往复"); break; case MODE_HIGH_SPEED: Serial.println("高速往复"); break; case MODE_MANUAL: Serial.println("手动"); break; } Serial.print("方向: "); Serial.println(digitalRead(DIR_PIN) ? "反转" : "正转"); Serial.print("频率: "); Serial.print(currentFreq); Serial.println(" Hz"); Serial.print("LED状态: "); switch(currentLEDState) { case LED_OFF: Serial.println("熄灭"); break; case LED_BLINK_FAST: Serial.println("快闪(300ms)"); break; case LED_ON: Serial.println("常亮"); break; } if (currentMode == MODE_LOW_SPEED || currentMode == MODE_HIGH_SPEED) { Serial.print("往复次数: "); Serial.print(currentCycle); Serial.print("/"); Serial.println(totalCycles); Serial.print("已发送脉冲: "); Serial.println(pulseCount); Serial.print("目标脉冲/单程: "); Serial.println(targetPulses); Serial.print("当前行程: "); Serial.println(isReversing ? "反向" : "正向"); Serial.print("暂停状态: "); Serial.println(isPausing ? "暂停中" : "运行中"); if (isPausing) { Serial.print("剩余暂停: "); Serial.print(PAUSE_DURATION_MS - (millis() - pauseStartTime)); Serial.println("ms"); } } Serial.print("电机状态: "); Serial.println(motorRunning ? "运行中" : "停止"); Serial.println("********************************\n"); }

浙公网安备 33010602011771号