STM32F103C8T6-基于FreeRTOS系统实现步进电机控制
引言
上一篇文章讲述了如何使用蓝牙连接stm32进行数据收发控制步进电机,这篇在之前的基础上通过移植操作系统(FreeRTOS或者其他的也可以,原理操作都类似)实现步进电机控制。
上篇博客指路:STM32蓝牙连接Android实现云端数据通信(电机控制-开源)_从蓝牙获取信息 发送到云端-CSDN博客https://blog.csdn.net/m0_74325713/article/details/146500274?spm=1011.2124.3001.6209
FreeRTOS介绍
(简单讲一下)
FreeRTOS 是一款开源的实时操作系统(Real-Time Operating System, RTOS),专为嵌入式系统和微控制器(MCU)设计。
核心特性
轻量级:内核代码仅需几 KB 内存,适合资源受限的微控制器(如 ARM Cortex-M、ESP32、AVR 等)。
可移植性:支持 40+ 种处理器架构,通过抽象层适配不同硬件平台。
实时性:提供确定性的任务调度机制,满足硬实时(Hard Real-Time)或软实时(Soft Real-Time)需求。
模块化设计:核心功能简洁,可通过插件扩展(如 TCP/IP 协议栈、文件系统、低功耗支持等)。
核心功能模块
任务(Tasks)
多任务并发执行,每个任务是一个独立的线程。
任务优先级可配置,支持抢占式调度(Preemptive)或协作式调度(Cooperative)。
调度器(Scheduler)
抢占式调度:高优先级任务可中断低优先级任务。
时间片轮转:同优先级任务按时间片分配 CPU。
支持协程(Coroutines,轻量级任务)。
同步与通信
队列(Queues):任务间传递数据的 FIFO 缓冲区,支持阻塞式读写。
信号量(Semaphores):二进制/计数信号量,用于资源管理和任务同步。
互斥量(Mutexes):防止资源竞争的互斥锁。
事件组(Event Groups):任务间事件通知机制。
内存管理
提供动态内存分配算法(如 heap_1 到 heap_5),支持不同场景的需求。
可自定义内存分配策略以适配硬件。
中断管理
中断服务程序(ISR)与任务间的高效通信。
延迟中断处理(Deferred Interrupt Handling)机制,减少中断延迟。
软件定时器
基于任务调度的软件定时器,支持单次或周期性触发回调函数。
功能实现
主要涉及以下五点功能:
1. 蓝牙通信:通过 USART 接收蓝牙指令,解析指令并执行相应的操作。
2. 步进电机控制:根据接收到的指令控制电机的启动、停止、转动方向和速度。
3. OLED 显示:实时显示电机的状态,如当前速度、运行模式等。
4. FreeRTOS 任务管理:使用 RTOS 管理不同的任务,即蓝牙数据处理和电机控制。
5. 中断处理:利用 TIM 定时器中断驱动步进电机的步进操作,确保精确的时序控制。
CubeMAX配置
这里只展示新增部分,其他部分配置和上篇博客中配置基本一致。
STM32蓝牙连接Android实现云端数据通信(电机控制-开源)_从蓝牙获取信息 发送到云端-CSDN博客
时钟基
选择 FREERTOS 系统 CMSIS_V2 版本。
列表添加对应蓝牙、电机控制的任务,主要优先级问题。(OLED也可以添加,感兴趣的朋友可以都加进去)
Keil函数添加
加入oled,motor相关函数,在usart.c补充回调函数。主函数中补充中断回调函数。基本把上篇博客的代码复制粘贴过去就可以用。oled.c、oled.h、oledfont.h 上篇全部给出,这里就不在重复写了。
motor.c 和 motor.h
#include "motor.h"const uint16_t step_sequence[] = {GPIO_PIN_8, // Step 1: IN1GPIO_PIN_8 | GPIO_PIN_9, // Step 2: IN1+IN2GPIO_PIN_9, // Step 3: IN2GPIO_PIN_9 | GPIO_PIN_12, // Step 4: IN2+IN3GPIO_PIN_12, // Step 5: IN3GPIO_PIN_12 | GPIO_PIN_13, // Step 6: IN3+IN4GPIO_PIN_13, // Step 7: IN4GPIO_PIN_13 | GPIO_PIN_8 // Step 8: IN4+IN1
};volatile uint8_t current_step = 0; // 当前步序号(volatile确保中断中可见)
volatile int8_t direction = 1; // 方向(1正转,-1反转)
volatile int32_t steps_remaining = 0; // 剩余步数
volatile uint8_t continuous_mode = 0; // 连续旋转模式标志 1-持续 0-停止
uint32_t current_speed = 100; // 当前速度(步/秒)volatile uint32_t steps_divider = 1; // 步进分频系数(实际速度=1000Hz/steps_divider)
volatile uint32_t step_counter = 0; // 步进计数器// 速度控制---PSC=72-1 ARR=999 HCLK=72MHZvoid Set_Stepper_Speed(uint32_t speed_steps)
{// 限速if(speed_steps < 10) speed_steps = 10; // 最低10步/秒if(speed_steps > 1000) speed_steps = 1000; // 最高1000步/秒// 更新当前速度current_speed = speed_steps;// 计算分频系数uint32_t new_divider = (1000 + speed_steps / 2) / speed_steps;if(new_divider < 1) new_divider = 1; // 允许最大速度steps_divider = new_divider;// 显示更新uint8_t speed_str[5];snprintf((char*)speed_str, sizeof(speed_str), "%4lu", speed_steps);OLED_show_string(4,1, speed_str);printf("Speed: %lu\n", speed_steps);
}
#ifndef _MOTOR_H_
#define _MOTOR_H_#include <stdint.h>
#include "stm32f1xx_hal.h"
#include "stdio.h"
#include "oled.h"extern const uint16_t step_sequence[8];extern volatile uint8_t current_step;
extern volatile int8_t direction;
extern volatile int32_t steps_remaining;
extern volatile uint8_t continuous_mode;
extern uint32_t current_speed;
extern volatile uint32_t steps_divider;
extern volatile uint32_t step_counter;#define SPEED_STEP 100 // 设定固定步长void Set_Stepper_Speed(uint32_t speed_steps);#endif
usart.c(结尾添加回调函数) usart.h(声明变量)
/* USER CODE BEGIN 1 */
volatile uint8_t rdata;
volatile uint8_t rflag = 0;void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {if (huart == &huart1) {rflag = 1;HAL_UART_Receive_IT(&huart1, (uint8_t*)&rdata, 1);}
}/* USER CODE END 1 */
// UART接收缓存
extern volatile uint8_t rdata;
extern volatile uint8_t rflag;void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
主函数中,中断回调函数补充内容。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{/* USER CODE BEGIN Callback 0 *//* USER CODE END Callback 0 */if (htim->Instance == TIM4) {HAL_IncTick();}/* USER CODE BEGIN Callback 1 */if (htim->Instance == TIM2) {step_counter++;if (step_counter >= steps_divider && (steps_remaining > 0 || continuous_mode)) {step_counter = 0;GPIOB->ODR &= ~(GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_12 | GPIO_PIN_13);GPIOB->ODR |= step_sequence[current_step];current_step = (current_step + direction + 8) % 8;if (!continuous_mode) steps_remaining--;if (!continuous_mode && steps_remaining <= 0) {HAL_TIM_PWM_Stop_IT(&htim2, TIM_CHANNEL_1);GPIOB->ODR &= ~(GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_12 | GPIO_PIN_13);}}}/* USER CODE END Callback 1 */
}
freertos.c 中补充任务函数调用。
void StartBluetoothTask(void *argument)
{/* USER CODE BEGIN StartBluetoothTask *//* Infinite loop */OLED_show_string(1, 1, "28BYJ-48:");HAL_UART_Receive_IT(&huart1, (uint8_t *)&rdata, 1);for (;;){if (rflag == 1){rflag = 0;if (rdata == 'm') {continuous_mode = 1;direction = 1;printf("START\n");OLED_show_string(2, 1, "START ");}else if (rdata == 'n') {continuous_mode = 0;steps_remaining = 0;printf("STOP\n");OLED_show_string(2, 1, "STOP ");}else if (rdata == 'j' || rdata == 'k') {if (rdata == 'j') {current_speed += SPEED_STEP;} else {current_speed = (current_speed > SPEED_STEP) ? current_speed - SPEED_STEP : 10;}Set_Stepper_Speed(current_speed);}else {int16_t angle = 0;switch (rdata){case 'a': angle = 90; break;case 'b': angle = 180; break;case 'c': angle = 270; break;case 'd': angle = 360; break;case 'x': angle = -90; break;case 'y': angle = -180; break;case 'z': angle = -270; break;case 'w': angle = -360; break;}if (angle != 0){steps_remaining = abs(angle) * 4096 / 360;direction = (angle > 0) ? 1 : -1;char angle_str[6];snprintf(angle_str, sizeof(angle_str), "%4d", angle);OLED_show_string(3, 1, (uint8_t *)angle_str);printf("angle: %d\n", angle);}}HAL_UART_Receive_IT(&huart1, (uint8_t *)&rdata, 1);}osDelay(10);}/* USER CODE END StartBluetoothTask */
}/* USER CODE BEGIN Header_StartMotorTask */
/**
* @brief Function implementing the MotorTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartMotorTask */
void StartMotorTask(void *argument)
{/* USER CODE BEGIN StartMotorTask *//* Infinite loop */step_counter = 0;for (;;){// 模拟PWM节拍(每 steps_divider 次循环走一步)step_counter++;if (step_counter >= steps_divider){step_counter = 0;if (steps_remaining > 0 || continuous_mode){GPIOB->ODR &= ~(GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_12 | GPIO_PIN_13);GPIOB->ODR |= step_sequence[current_step];current_step = (current_step + direction + 8) % 8;if (!continuous_mode) {steps_remaining--;}}else if (!continuous_mode && steps_remaining <= 0){GPIOB->ODR &= ~(GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_12 | GPIO_PIN_13);}}osDelay(1); }/* USER CODE END StartMotorTask */
}
完整代码
【免费】STM32F103C8T6-基于FreeRTOS系统实现步进电机控制资源-CSDN文库