当前位置: 首页 > news >正文

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文库

相关文章:

  • GD32裸机程序-SFUD接口文件记录
  • 用 C++ 模拟客户端渲染中的分步数据加载
  • CVFSNet:一种用于端到端脑梗塞溶栓治疗后改良脑梗死溶栓分级(mTICI)评分的跨视图融合评分网络|文献速递-深度学习医疗AI最新文献
  • 使用CubeMX新建SysTick延时函数工程——使用中断,不使用HAL_Delay
  • 【QT入门到晋级】QT打动态库包及引入动态库包
  • std visit
  • centos部署的openstack发布windows虚拟机
  • 卷积神经网络 CNN 模型介绍
  • 使用DeepSeek如何提升课题申报书中研究内容的专业性?25个进阶DeepSeek指令
  • QT —— 信号和槽(自定义信号和槽函数)
  • 《Timer: Generative Pre-trained Transformers Are Large Time Series Models》
  • C++Cherno 学习笔记day20 [81]-[85] 可视化基准测试、单例模式、小字符串优化sso、跟踪内存分配、左值与右值
  • 蓝桥杯B组Java省赛强化
  • Cribl (实验) vpc-flow 数据抽样
  • 中科院1区顶刊Expert Systems with Applications ESO:增强型蛇形算法,性能不错
  • LeetCode -- Flora -- edit 2025-04-16
  • Numpy常用库方法总结
  • Langchain + Gemini API调用基本操作
  • MGR实现mysql高可用性
  • JVM:垃圾回收
  • 想找私人做网站/win10优化大师官网
  • 网站软件设计/seo知识培训
  • 惠州开发做商城网站建设哪家好/培训计划方案模板
  • 当地政府网站建设问卷调查/青岛seo推广
  • 成都网站建设门户/竞价网官网
  • 做网站编辑大专可以吗/sem代运营