我用USART2,PA2PA3引脚,/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usart.c
* @brief This file provides code for the configuration
* of the USART instances.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
/* USER CODE BEGIN 0 */
#include <string.h>
#include <stdio.h>
/* USER CODE END 0 */
UART_HandleTypeDef huart2;
/* USART2 init function */
void MX_USART2_UART_Init(void)
{
/* USER CODE BEGIN USART2_Init 0 */
/* USER CODE END USART2_Init 0 */
/* USER CODE BEGIN USART2_Init 1 */
/* USER CODE END USART2_Init 1 */
huart2.Instance = USART2;
huart2.Init.BaudRate = 9600;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART2_Init 2 */
/* USER CODE END USART2_Init 2 */
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART2)
{
/* USER CODE BEGIN USART2_MspInit 0 */
/* USER CODE END USART2_MspInit 0 */
/* USART2 clock enable */
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN USART2_MspInit 1 */
/* USER CODE END USART2_MspInit 1 */
}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART2)
{
/* USER CODE BEGIN USART2_MspDeInit 0 */
/* USER CODE END USART2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART2_CLK_DISABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);
/* USER CODE BEGIN USART2_MspDeInit 1 */
/* USER CODE END USART2_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
这是我的串口通讯设置,/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "OLED.h"
#include <stdio.h>
#include "Delay.h"
#include <math.h> // 用于fabs函数(浮点数绝对值)
#include <stdlib.h> // 用于abs函数(整数绝对值)
#include <string.h> // 新增:用于字符串处理
uint32_t loop_count = 0;
uint8_t running = 0;
uint8_t direction = 1; // 1 正转,0 反转
void Motor_SetSpeed(uint32_t freq);
void Motor_RunSteps(uint32_t steps);
#define MOTOR_FREQ 3200 //点动速度3200
//持续运动的定义代码
#define MOTOR_FREQ_START 500 // 起始频率(Hz)
#define MOTOR_FREQ_TARGET 2000 // 匀速目标频率(Hz)
#define MOTOR_ACCEL_STEP 100 // 每步加速的频率增量
#define MOTOR_ACCEL_DELAY 30 // 每级加速之间的延时(ms)
#define MOTOR_DECEL_STEP 100 // 每步减速的频率降量
#define MOTOR_DECEL_DELAY 30 // 每级减速之间的延时(ms)
#define MOTOR_RUN_TIME 2000 // 匀速运行时间(ms)
//循环1000次的定义
#define PULSES_PER_MOVE 3200
#define CYCLE_TIMES 1000
volatile uint32_t pulse_count = 0; // 中断脉冲计数
uint16_t cycle_count = 0; // 正反转循环次数
uint8_t cycle_running = 0; // 循环运行状态:0停止,1运行
uint8_t current_dir = 0; // 当前方向 0反转,1正转
#define DIR_PIN GPIO_PIN_1
#define DIR_PORT GPIOA
//增加次数和移动距离的定义
// 增加变量定义
// 动态变量,初始值
uint32_t pulses_per_move = 640; // 初始对应5mm,具体根据你的脉冲/mm计算调整
uint32_t cycle_times = 1000; // 初始循环次数
uint32_t spped = 10;
// 按键状态,避免连发
uint8_t last_PA9_state = 1; // 上次PA9状态,1表示未按下,0表示按下
uint8_t last_PA11_state = 1; // 上次PA11状态,1表示未按下,0表示按下
uint8_t last_PA15_state = 1; // 上次PA15状态,1表示未按下,0表示按下
uint8_t last_PA10_state =1; // 上次PA10状态,1表示未按下,0表示按下
uint8_t last_PB3_state =1; // 上次PB3状态,1表示未按下,0表示按下
uint8_t last_PB5_state =1; // 上次PB5状态,1表示未按下,0表示按下
uint8_t last_PB14_state =1; // 上次PB14状态,1表示未按下,0表示按下
//显示屏定义
volatile uint8_t need_display_update = 0; // OLED是否需要刷新
volatile uint32_t pulse_counter = 0; // 当前脉冲计数,用于显示
#define FAULT_PINS (GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6) // A4/A5/A6故障引脚组合
uint8_t fault_triggered = 0; // 故障触发标志:0无故障,1故障触发(A4/A5/A6断开)
uint8_t fault_processed = 0; // 故障处理标志:0未处理,1已处理(避免重复处理)
uint8_t fault_active = 0; // 实时故障状态:0正常,1故障(断开)
// 编码器相关变量
int32_t encoder_absolute = 0; // 32位绝对计数(支持正负值)
uint16_t encoder_last = 0; // 上一次的TIM1计数值
uint16_t encoder_current = 0; // 当前的TIM1计数值
#define ENCODER_PPR 3200.0f // 1圈脉冲数
#define LEAD 5.0f // 导程(mm/圈)
#define CALIBRATION 0.8015f // 校准系数(根据实际调整)
double encoder_distance = 0.00; // 带2位小数的距离
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
//点动控制
void Motor_Start(uint8_t dir)
{
if(dir) HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
else HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
uint32_t timer_clock = 1000000; // 1MHz 计数频率,与你定时器预分频相关
uint32_t arr = (timer_clock / MOTOR_FREQ) - 1;
__HAL_TIM_SET_AUTORELOAD(&htim2, arr);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, (arr + 1) / 2); // 50% 占空比
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
}
//循环
//方向控制
void Motor_SetDirection(uint8_t dir)
{
if (dir)
HAL_GPIO_WritePin(DIR_PORT, DIR_PIN, GPIO_PIN_SET);
else
HAL_GPIO_WritePin(DIR_PORT, DIR_PIN, GPIO_PIN_RESET);
}
//速度
void Motor_StartPWM(uint32_t freq)
{
uint32_t timer_clock = 1000000; // 1MHz
uint32_t arr = (timer_clock / freq) - 1;
__HAL_TIM_SET_AUTORELOAD(&htim2, arr);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, (arr + 1) / 2);
__HAL_TIM_SET_COUNTER(&htim2, 0);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_Base_Start_IT(&htim2); // 启用中断计数
}
//停止程序
void Motor_StopPWM(void)
{
HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1);
HAL_TIM_Base_Stop_IT(&htim2);
}
// TIM2中断回调
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2)
{
pulse_count++;
need_display_update = 1;
}
}
#define ACCEL_RATIO 0.1 // 加速段占比(10%)
#define DECEL_RATIO 0.1 // 减速段占比(10%)
uint32_t FREQ_MAX = 1500; // 匀速段目标频率(动态计算)
// 主运行函数:含加速-匀速-减速,故障时走完当前单次运行
void Motor_Run_One_Direction(void)
{
uint16_t freq;
uint32_t target_pulse = 0;
// 计算各段脉冲数(单次移动总脉冲数=pulses_per_move)
uint32_t ACCEL_PULSES = (uint32_t)(pulses_per_move * ACCEL_RATIO);
uint32_t DECEL_PULSES = (uint32_t)(pulses_per_move * DECEL_RATIO);
uint32_t CONST_PULSES = pulses_per_move - ACCEL_PULSES - DECEL_PULSES;
// 动态计算最大频率(根据速度和单次脉冲数)
uint32_t FREQ_MIN = 1000; // 起始频率固定
float compensation = 1.02; // 补偿系数(原代码逻辑保留)
FREQ_MAX = (pulses_per_move * spped * 2) / 60;
FREQ_MAX = FREQ_MAX * compensation; // 补偿加减速时间损耗
// -------------------------- 加速段 --------------------------
for (uint32_t i = 0; i < ACCEL_PULSES; i++)
{
// PB6紧急停止或循环停止:中途终止(保留原功能)
if (!cycle_running || HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET)
{
Motor_StopPWM();
return;
}
// // 故障触发时不中途停止,继续走完当前段
// if (fault_triggered) {}
// 计算当前频率(线性加速)
freq = FREQ_MIN + ((FREQ_MAX - FREQ_MIN) * i) / ACCEL_PULSES;
Motor_StartPWM(freq);
// 等待当前脉冲完成
target_pulse = pulse_count + 1;
while (pulse_count < target_pulse)
{
if (!cycle_running || HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET)
{
Motor_StopPWM();
return;
}
}
}
// -------------------------- 匀速段 --------------------------
for (uint32_t i = 0; i < CONST_PULSES; i++)
{
// PB6紧急停止或循环停止:中途终止
if (!cycle_running || HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET)
{
Motor_StopPWM();
return;
}
// // 故障触发时不中途停止
// if (fault_triggered) {}
Motor_StartPWM(FREQ_MAX);
// 等待当前脉冲完成
target_pulse = pulse_count + 1;
while (pulse_count < target_pulse)
{
if (!cycle_running || HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET)
{
Motor_StopPWM();
return;
}
}
}
// -------------------------- 减速段 --------------------------
for (uint32_t i = 0; i < DECEL_PULSES; i++)
{
// PB6紧急停止或循环停止:中途终止
if (!cycle_running || HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET)
{
Motor_StopPWM();
return;
}
// // 故障触发时不中途停止
// if (fault_triggered) {}
// 计算当前频率(线性减速)
freq = FREQ_MAX - ((FREQ_MAX - FREQ_MIN) * i) / DECEL_PULSES;
Motor_StartPWM(freq);
// 等待当前脉冲完成
target_pulse = pulse_count + 1;
while (pulse_count < target_pulse)
{
if (!cycle_running || HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET)
{
Motor_StopPWM();
return;
}
}
}
Motor_StopPWM(); // 单次运行结束后停止PWM
}
// 更新编码器绝对位置(核心函数)
void Encoder_UpdateAbsolute(void)
{
int16_t diff; // 前后两次的差值(16位有符号)
// 读取当前计数值
encoder_current = __HAL_TIM_GET_COUNTER(&htim1);
// 计算差值(处理16位溢出)
diff = encoder_current - encoder_last;
// 若差值超过32767(16位有符号最大值),说明是负溢出(反转)
if (diff > 32767)
{
diff -= 65536; // 修正为负值(如65535→0,实际差值是-1)
}
// 若差值小于-32768,说明是正溢出(正转)
else if (diff < -32768)
{
diff += 65536; // 修正为正值(如0→65535,实际差值是+65535)
}
// 更新绝对位置
encoder_absolute += diff;
// 保存当前值作为下一次的“上一次值”
encoder_last = encoder_current;
}
uint8_t last_PB1_state = 1; // PB1上次状态(1=未按下,0=按下)
uint8_t last_PB10_state = 1; // PB10上次状态
uint8_t single_move_running = 0; // 单次移动状态标记
#define SINGLE_MOVE_PULSES 320 // 0.5mm对应的脉冲数
float total_dist = 0.0f; // 累计移动距离(mm),正转+1,反转-1,初始为0
void Motor_SingleMove1mm(uint8_t dir)
{
if (single_move_running) return; // 防止重复触发
single_move_running = 1; // 标记移动中
// 设置方向
Motor_SetDirection(dir);
// 设置匀速频率(基于当前速度参数)
float compensation = 1.02;
uint32_t move_freq = (SINGLE_MOVE_PULSES * spped * 2) / 60 * compensation;
if (move_freq < 500) move_freq = 500; // 最低频率限制
if (move_freq > 3000) move_freq = 3000; // 最高频率限制
// 启动PWM并计数脉冲
pulse_count = 0;
Motor_StartPWM(move_freq);
// 等待达到目标脉冲数(320 = 0.5mm)
while (pulse_count < SINGLE_MOVE_PULSES);
// 移动完成,停止电机
Motor_StopPWM();
if (dir == 1) // dir=1:正转
total_dist += 1.0f;
else // dir=0:反转
total_dist -= 1.0f;
single_move_running = 0; // 清除移动状态
}
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM2_Init();
MX_I2C1_Init();
MX_TIM1_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
Motor_StopPWM();// 确保电机停止
// 初始化OLED
OLED_Init(); // 初始化显示屏
// === OLED 初始界面清屏与初始化显示 ===
OLED_Clear();
OLED_ShowString(1, 1, "Dist:");
OLED_ShowNum(1, 6, 0, 2);
OLED_ShowString(2, 1, "Cycle:");
OLED_ShowNum(2, 7, 0, 5);
OLED_ShowString(3, 1, "Len:");
OLED_ShowString(3, 8, "spped:");
HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_1 | TIM_CHANNEL_2); // 必须启动,否则计数值为0
#define ENCODER_PULSES_PER_REV 3200 // 假设编码器一圈3200脉冲,需根据实际修改
encoder_last = __HAL_TIM_GET_COUNTER(&htim1); // 记录初始计数值
encoder_absolute = 0; // 初始绝对位置设为0(零点)
//uint32_t last_pulse_display = 0xFFFFFFFF;
uint32_t last_cycle_display = 0xFFFF;
float compensation =1.02;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
//
while (1)
{
// 更新编码器绝对位置和距离
Encoder_UpdateAbsolute();
encoder_distance = (float)encoder_absolute * LEAD * CALIBRATION / ENCODER_PPR;
// 读取数据
__disable_irq();
uint32_t pulse = pulse_count; // 实时脉冲数
uint32_t cycle = cycle_count; // 当前循环次数
uint32_t pulses_move = pulses_per_move; // 单次移动对应脉冲
__enable_irq();
//// 新代码:显示累计距离 total_dist(支持正负、2位小数、不清零)
//OLED_ShowString(1, 1, "Dist:");
//// 拆分整数部分和小数部分(处理正负值)
//int16_t dist_int = (int16_t)total_dist; // 整数部分(如1.99→1,-2.05→-2)
//uint16_t dist_dec = (uint16_t)(fabs(total_dist - dist_int) * 100); // 小数部分(取绝对值,2位)
//// 显示负号或空格(正数值前用空格占位,确保对齐)
//if (total_dist < 0)
//{
// OLED_ShowString(1, 6, "-"); // 负号显示在第1行第6列
// OLED_ShowNum(1, 7, abs(dist_int), 3); // 整数部分取绝对值(3位占位,如-3→003)
//}
//else
//{
// OLED_ShowString(1, 6, " "); // 正数值前用空格占位,与负号对齐
// OLED_ShowNum(1, 7, dist_int, 3); // 整数部分(3位占位,如5→005)
//}
//// 显示小数和单位
//OLED_ShowString(1, 10, "."); // 小数点(第1行第10列)
//OLED_ShowNum(1, 11, dist_dec, 2); // 2位小数(如0.05、1.99)
//OLED_ShowString(1, 13, "mm"); // 单位(第1行第13列)
//编码器距离显示
// 计算修正后的距离
int16_t dist_int = (int16_t)encoder_distance; // 整数部分(可正可负)
uint16_t dist_dec = (uint16_t)(fabs(encoder_distance - dist_int) * 100); // 小数部分
// 拆分整数和小数部分(保留2位小数)
int16_t pos_int = (int16_t)encoder_distance; // 声明并初始化
uint16_t pos_dec = (uint16_t)(fabs(encoder_distance - pos_int) * 100);
OLED_ShowString(1, 1, "Dist:");
if (encoder_distance < 0)
{
OLED_ShowString(1, 6, "-");
OLED_ShowNum(1, 7, abs(pos_int), 3); // 使用dist_int
}
else
{
OLED_ShowString(1, 6, " ");
OLED_ShowNum(1, 7, pos_int, 3); // 使用dist_int
}
OLED_ShowString(1, 10, ".");
OLED_ShowNum(1, 11, pos_dec, 2);
OLED_ShowString(1, 13, "mm");
// 计算单次拉伸距离(mm)
uint32_t single_move_mm = (pulses_move / 640) * 1;
// uint32_t single_mm = pulse / 640; // 每640脉冲=1mm
uint32_t completed_cycles = cycle / 2;
if ((cycle / 2) != last_cycle_display)
{
OLED_ShowString(2, 1, "Cycle:");
OLED_ShowNum(2, 7, cycle / 2, 5);
last_cycle_display = cycle / 2;
}
// 第三行显示单次拉伸距离(不变,显示单次距离)
OLED_ShowString(3, 1, "Len:");
OLED_ShowNum(3, 5, single_move_mm, 3);
OLED_ShowString(3, 8, "spped:");
OLED_ShowNum(3, 15, spped, 2);
// 第四行显示拉伸总次数
OLED_ShowString(4, 1, "Cycles:");
OLED_ShowNum(4, 8, cycle_times, 5);
// PA15增加速度
uint8_t PA15_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15);
if (last_PA15_state == 1 && PA15_state == 0&& spped<30) // 按下检测
{
spped++;
HAL_Delay(200);
}
last_PA15_state = PA15_state;
// PB5减少速度
uint8_t PB5_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5);
if (last_PB5_state == 1 && PB5_state == 0&& spped>10) // 按下检测
{
spped--;
HAL_Delay(200);
}
last_PB5_state = PB5_state;
// PB14增加移动距离(按一次加1mm)
uint8_t PB14_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14);
if (last_PB14_state == 1 && PB14_state == 0) // 下降沿检测,按下
{
compensation+=0.0105;
pulses_per_move += 640; // 假设3200脉冲对应5mm,按需调整
HAL_Delay(200); // 简单消抖
// 计算目标频率:每分钟20次单程(10次往返)
FREQ_MAX = (pulses_per_move * spped*2) / 60;
// 增加补偿加减速时间损耗
FREQ_MAX = FREQ_MAX * compensation;
}
last_PB14_state = PB14_state;
// PB3减少移动距离(按一次减1mm)
uint8_t PB3_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3);
if (last_PB3_state == 1 && PB3_state == 0&& pulses_per_move>640) // 下降沿检测,按下
{
compensation-=0.0105;
pulses_per_move -= 640; // 假设3200脉冲对应5mm,按需调整
HAL_Delay(200); // 简单消抖
// 计算目标频率:每分钟20次单程(10次往返)
FREQ_MAX = (pulses_per_move * spped*2) / 60;
// 增加补偿加减速时间损耗
FREQ_MAX = FREQ_MAX * compensation;
}
last_PB3_state = PB3_state;
// PA11增加循环次数(按一次加1000次)
uint8_t PA11_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11);
if (last_PA11_state == 1 && PA11_state == 0) // 按下检测
{
cycle_times += 1000;
HAL_Delay(200);
}
last_PA11_state = PA11_state;
// PA10减少循环次数(按一次减1000次)
uint8_t PA10_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_10);
if (last_PA10_state == 1 && PA10_state == 0&&cycle_times>1000) // 按下检测
{
cycle_times -= 1000;
HAL_Delay(200);
}
last_PA10_state = PA10_state;
// 点动控制(B0、B11)
if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) // B0按下,正转
{
Motor_Start(1); // 开启PWM和方向
cycle_running = 0; // 关闭循环
running = 1; // 点动标志
}
else if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11) == GPIO_PIN_RESET) // B11按下,反转
{
Motor_Start(0);
cycle_running = 0;
running = 1;
}
else if(running) // 按键释放,点动停止
{
Motor_StopPWM();
running = 0;
}
// PB1和PB10单次1mm控制
// PB1按下:正转1mm
uint8_t PB1_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
if (last_PB1_state == 1 && PB1_state == 0 && !single_move_running)
{
Motor_SingleMove1mm(1); // 正转1mm
HAL_Delay(200); // 消抖,防止一次按下多次触发
}
last_PB1_state = PB1_state;
// PB10按下:反转1mm
uint8_t PB10_state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10);
if (last_PB10_state == 1 && PB10_state == 0 && !single_move_running)
{
Motor_SingleMove1mm(0); // 反转1mm
HAL_Delay(200); // 消抖
}
last_PB10_state = PB10_state;
// 复位按钮 - PB15 被按下时,复位计数器
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_15) == GPIO_PIN_RESET)
{
// 停止PWM输出
HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1); // 停止步进电机脉冲输出
// 复位变量
pulse_count = 0;
cycle_count = 0;
spped =10;
pulses_per_move=640;
cycle_times=1000;
current_dir = 1; // 可以设为初始方向
// last_pulse_display = 0xFFFFFFFF;
last_cycle_display = 0xFFFF;
cycle_running = 0; // 停止循环状态
encoder_absolute = 0; // 当前位置设为零点
encoder_distance = 0.00;
HAL_Delay(500); // 延时一下,避免误触
total_dist=0;
// 清空显示
OLED_Clear();
}
// 当故障消失(重新接上)且之前已处理故障,清零标志允许重启
if (!fault_active && fault_processed)
{
fault_triggered = 0;
fault_processed = 0;
}
// 6.1 PB6紧急停止(保留原功能:直接停止,不回原点)
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == GPIO_PIN_RESET && cycle_running == 1)
{
Motor_StopPWM();
cycle_running = 0;
fault_triggered = 0;
fault_processed = 0;
HAL_Delay(300); // 消抖
}
// 6.2 A4/A5/A6故障检测(断开时触发,仅标记一次)
else if (cycle_running == 1 && fault_triggered == 0)
{
// 任意一个故障引脚为高电平(断开),则触发故障
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_SET ||
HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_SET ||
HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == GPIO_PIN_SET)
{
fault_triggered = 1;
fault_processed = 0;
HAL_Delay(50); // 消抖
}
}
// -------------------------- 7. 循环运行与故障处理 --------------------------
// 7. 循环运行与故障处理(修正流程)
if (cycle_running)
{
// 正常停止条件:循环完成
if (completed_cycles >= cycle_times)
{
Motor_StopPWM();
cycle_running = 0;
}
// 故障处理(核心修改)
else if (fault_triggered && !fault_processed)
{
// 正转时断开:走完当前正转 → 反转回原点
if (current_dir == 0)
{
// 1. 确保走完当前正转脉冲
pulse_count = 0;
Motor_SetDirection(current_dir); // 保持正转方向
Motor_Run_One_Direction(); // 完成当前正转
cycle_count++;
}
// 反转时断开:直接在原点停止(无需额外动作)
else if (current_dir == 1)
{
// 无需走完当前反转,直接停止
Motor_StopPWM();
// cycle_count-=2;
}
// 处理完成,统一停止循环并更新状态
cycle_running = 0;
fault_processed = 1;
}
// 正常运行
else if (!fault_triggered)
{
pulse_count = 0;
Motor_SetDirection(current_dir);
Motor_Run_One_Direction();
current_dir = !current_dir; // 切换方向
cycle_count++;
}
}
// 8. 启动循环(PB4按下,无故障时)
else if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4) == GPIO_PIN_RESET &&
HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET &&
HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_RESET &&
HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == GPIO_PIN_RESET)
{
cycle_running = 1;
pulse_count = 0;
current_dir = 1;
Motor_SetDirection(current_dir);
}
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
这是我的main.c函数,我该怎么让stm32f103c8t6去和H05蓝牙连接,因为我上位机写了点动正转和反转,#include "QtWidgetsApplication1.h"
#include "ui_QtWidgetsApplication1.h"
#include <QMessageBox>
#pragma execution_character_set("utf-8")
QtWidgetsApplication1::QtWidgetsApplication1(QWidget* parent)
: QWidget(parent)
, ui(new Ui::QtWidgetsApplication1Class)
, discoveryAgent(nullptr)
, socket(nullptr)
{
ui->setupUi(this);
// 初始化蓝牙组件
discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol, this);
// 仅保留核心功能的信号连接
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
this, &QtWidgetsApplication1::deviceDiscovered);
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished,
[=]() { ui->statusLabel->setText("扫描完成"); });
connect(socket, &QBluetoothSocket::connected, this, &QtWidgetsApplication1::socketConnected);
connect(socket, &QBluetoothSocket::disconnected, this, &QtWidgetsApplication1::socketDisconnected);
connect(socket, &QBluetoothSocket::readyRead, this, &QtWidgetsApplication1::dataReceived);
// 新增:点动按钮信号连接
connect(ui->pointMoveForwardButton, &QPushButton::clicked,
this, &QtWidgetsApplication1::on_pointMoveForwardButton_clicked);
connect(ui->pointMoveBackwardButton, &QPushButton::clicked,
this, &QtWidgetsApplication1::on_pointMoveBackwardButton_clicked);
// 初始化UI状态
ui->startButton->setEnabled(false);
ui->stopButton->setEnabled(false);
ui->pointMoveForwardButton->setEnabled(false); // 初始禁用
ui->pointMoveBackwardButton->setEnabled(false); // 初始禁用
}
QtWidgetsApplication1::~QtWidgetsApplication1()
{
if (socket && socket->isOpen()) socket->close();
delete socket;
delete discoveryAgent;
delete ui;
}
void QtWidgetsApplication1::on_scanButton_clicked()
{
ui->deviceListWidget->clear();
ui->statusLabel->setText("正在扫描...");
discoveryAgent->start();
}
void QtWidgetsApplication1::deviceDiscovered(const QBluetoothDeviceInfo& info)
{
if (info.name().contains("HC-05", Qt::CaseInsensitive)) {
QString deviceInfo = QString("%1 (%2)")
.arg(info.name().isEmpty() ? "未知HC-05" : info.name())
.arg(info.address().toString());
ui->deviceListWidget->addItem(deviceInfo);
targetDevice = info;
}
}
void QtWidgetsApplication1::on_connectButton_clicked()
{
if (!targetDevice.isValid()) {
QMessageBox::warning(this, "错误", "请先扫描并选择HC-05设备");
return;
}
const QBluetoothUuid serviceUuid(QStringLiteral("00001101-0000-1000-8000-00805F9B34FB"));
socket->connectToService(targetDevice.address(), serviceUuid);
ui->statusLabel->setText("正在连接HC-05...");
}
void QtWidgetsApplication1::socketConnected()
{
ui->statusLabel->setText("已连接到HC-05");
ui->statusLabel->setText("已连接(状态码:" + QString::number(socket->state()) + ")");
ui->connectButton->setEnabled(false);
ui->startButton->setEnabled(true);
ui->stopButton->setEnabled(true);
ui->pointMoveForwardButton->setEnabled(true); // 启用正转点动
ui->pointMoveBackwardButton->setEnabled(true); // 启用反转点动
}
void QtWidgetsApplication1::socketDisconnected()
{
ui->statusLabel->setText("已断开连接");
ui->connectButton->setEnabled(true);
ui->startButton->setEnabled(false);
ui->stopButton->setEnabled(false);
ui->pointMoveForwardButton->setEnabled(false); // 禁用正转点动
ui->pointMoveBackwardButton->setEnabled(false); // 禁用反转点动
}
void QtWidgetsApplication1::on_startButton_clicked()
{
if (socket->state() == QBluetoothSocket::ConnectedState) {
socket->write("START\n");
ui->statusLabel->setText("已发送启动指令");
}
}
void QtWidgetsApplication1::on_stopButton_clicked()
{
if (socket->state() == QBluetoothSocket::ConnectedState) {
socket->write("STOP\n");
ui->statusLabel->setText("已发送停止指令");
}
}
void QtWidgetsApplication1::dataReceived()
{
QByteArray data = socket->readAll();
ui->recvTextEdit->append("单片机回传:" + data);
}
// 正转点动按钮槽函数
void QtWidgetsApplication1::on_pointMoveForwardButton_clicked()
{
if (socket->state() == QBluetoothSocket::ConnectedState) {
QByteArray cmd = "POINT_FWD\n"; // 必须带换行符
qint64 bytesSent = socket->write(cmd);
ui->statusLabel->setText("发送正转指令:" + QString(cmd) + "(" + QString::number(bytesSent) + "字节)");
}
else {
ui->statusLabel->setText("未连接蓝牙");
}
}
// 反转点动按钮槽函数(类似修改)
void QtWidgetsApplication1::on_pointMoveBackwardButton_clicked()
{
if (socket->state() == QBluetoothSocket::ConnectedState) {
QByteArray cmd = "POINT_BWD\n";
qint64 bytesSent = socket->write(cmd);
ui->statusLabel->setText("发送反转指令:" + QString(cmd) + "(" + QString::number(bytesSent) + "字节)");
}
else {
ui->statusLabel->setText("未连接蓝牙");
}
}但是上位机按下没反应