GRBL 1.1 移植到 STM32 (HAL库)

1. 硬件映射文件 (cpu_map.h)

这个文件定义了 GRBL 抽象的引脚(如 STEP, DIR, LIMIT)对应到 STM32 的具体 GPIO 引脚。

c 复制代码
// cpu_map.h
#ifndef cpu_map_h
#define cpu_map_h

#include "stm32f4xx_hal.h" // 根据你的芯片修改 (如 stm32f1xx_hal.h)

// --- 步进电机引脚定义 (X, Y, Z 轴) ---
#define STEP_PORT       GPIOA
#define X_STEP_PIN      GPIO_PIN_0
#define Y_STEP_PIN      GPIO_PIN_1
#define Z_STEP_PIN      GPIO_PIN_2

#define DIR_PORT        GPIOA
#define X_DIR_PIN       GPIO_PIN_3
#define Y_DIR_PIN       GPIO_PIN_4
#define Z_DIR_PIN       GPIO_PIN_5

#define ENABLE_PORT     GPIOA
#define STEPPERS_ENABLE_PIN GPIO_PIN_6

// --- 限位开关引脚定义 ---
#define LIMIT_PORT      GPIOB
#define X_LIMIT_PIN     GPIO_PIN_12
#define Y_LIMIT_PIN     GPIO_PIN_13
#define Z_LIMIT_PIN     GPIO_PIN_14

// --- 控制引脚 (复位, 急停等) ---
#define CONTROL_PORT    GPIOB
#define RESET_PIN       GPIO_PIN_15

// --- 主轴控制 (PWM/继电器) ---
#define SPINDLE_PORT    GPIOC
#define SPINDLE_PWM_PIN GPIO_PIN_6 // 假设使用 TIM3_CH1

// --- 宏定义:简化 GPIO 操作 ---
#define STEP_PORT_SET(x)    HAL_GPIO_WritePin(STEP_PORT, x, GPIO_PIN_SET)
#define STEP_PORT_CLR(x)    HAL_GPIO_WritePin(STEP_PORT, x, GPIO_PIN_RESET)
#define DIR_PORT_SET(x)     HAL_GPIO_WritePin(DIR_PORT, x, GPIO_PIN_SET)
#define DIR_PORT_CLR(x)     HAL_GPIO_WritePin(DIR_PORT, x, GPIO_PIN_RESET)

#endif

2. 步进定时器中断 (stepper.c 修改部分)

GRBL 的核心是一个高频定时器中断,用于计算加减速并输出脉冲。这是移植最难的部分。

需要配置一个 STM32 定时器(如 TIM1) 产生 1ms 或更高频率的中断,然后在中断里调用 GRBL 的步进函数。

c 复制代码
// stepper.c (仅展示移植相关的修改)
#include "stm32f4xx_hal.h"
#include "grbl.h"

extern TIM_HandleTypeDef htim1; // CubeMX 生成的定时器句柄

// 定时器中断回调函数 (在 stm32f4xx_it.c 中会被调用)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim->Instance == TIM1) {
        // 这里是 GRBL 的心跳
        // 原 AVR 代码中的 ISR(TIMER1_COMPA_vect) 逻辑放在这里
        st_isr(); // GRBL 内部的步进中断处理函数
    }
}

// 初始化步进定时器
void st_init() {
    // 使用 CubeMX 初始化 TIM1
    // 配置预分频器,使得定时器频率为 1MHz (1us 计数)
    // 配置周期为 1000 (即 1ms 进入一次中断)
    HAL_TIM_Base_Start_IT(&htim1);
    
    // 初始化 GPIO (调用上面的 cpu_map)
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    GPIO_InitStruct.Pin = X_STEP_PIN | Y_STEP_PIN | Z_STEP_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(STEP_PORT, &GPIO_InitStruct);
}

3. 串口重定向 (serial.c)

GRBL 通过串口与 PC 通信。你需要将 AVR 的 USART_Receive 改为 STM32 的 UART。

c 复制代码
// serial.c
#include "serial.h"
#include "usart.h" // CubeMX 生成的 USART 头文件

// 接收缓冲区
#define RX_RING_BUFFER 256
volatile uint8_t rx_buffer[RX_RING_BUFFER];
volatile uint8_t rx_head = 0;
volatile uint8_t rx_tail = 0;

// UART 接收中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart->Instance == USART1) {
        rx_buffer[rx_head] = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
        rx_head = (rx_head + 1) % RX_RING_BUFFER;
    }
}

// GRBL 调用的读字节函数
uint8_t serial_read() {
    if (rx_head == rx_tail) {
        return SERIAL_NO_DATA;
    } else {
        uint8_t data = rx_buffer[rx_tail];
        rx_tail = (rx_tail + 1) % RX_RING_BUFFER;
        return data;
    }
}

// GRBL 调用的写字节函数
void serial_write(uint8_t data) {
    HAL_UART_Transmit(&huart1, &data, 1, 10);
}

void serial_init() {
    // CubeMX 会自动初始化 UART1
    // 开启接收中断
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
}

4. EEPROM 模拟 (eeprom.c)

STM32 没有硬件 EEPROM,通常使用 Flash 模拟。

c 复制代码
// eeprom.c
#include "eeprom.h"
#include "stm32f4xx_hal_flash.h"

#define EEPROM_START_ADDR 0x0800F000 // 使用 Flash 最后一页

void memcpy_to_flash(uint32_t addr, void *src, uint32_t len) {
    HAL_FLASH_Unlock();
    uint32_t *p = (uint32_t *)src;
    for(uint32_t i=0; i<len; i+=4) {
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr+i, *p++);
    }
    HAL_FLASH_Lock();
}

void memcpy_from_flash(void *dst, uint32_t addr, uint32_t len) {
    uint8_t *p = (uint8_t *)dst;
    for(uint32_t i=0; i<len; i++) {
        p[i] = *(__IO uint8_t*)(addr + i);
    }
}

5. 主函数 (main.c)

将 GRBL 的主循环嵌入到 STM32 的 main 函数中。

c 复制代码
// main.c
#include "main.h"
#include "grbl.h"

int main(void) {
    HAL_Init();
    SystemClock_Config();
    
    // CubeMX 初始化外设
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_TIM1_Init(); // 步进定时器
    
    // 初始化 GRBL 核心
    serial_init();
    settings_init(); // 加载参数
    st_init();       // 初始化步进电机
    plan_init();     // 初始化运动规划
    
    // 启动 GRBL 协议解析器
    protocol_main_loop();
    
    while (1) {
        // GRBL 已经在 protocol_main_loop 中死循环了
    }
}

参考代码 GRBL 移植stm32 www.youwenfan.com/contentcsu/70177.html

移植关键注意事项

  1. 定时器频率 :GRBL 对时间极其敏感。原版 AVR 是 16MHz,STM32 是 72/168MHz。你需要调整 config.h 中的 F_CPU 宏定义,或者在定时器预分频器中做等效换算,否则会导致 进给速度(Feed Rate)快 10 倍
  2. 中断优先级 :STM32 的中断有抢占优先级。串口中断 的优先级必须高于 定时器中断,否则在发送大量状态时可能会阻塞步进脉冲,导致丢步。
  3. 引脚电平反转 :如果你的驱动器是高电平有效,而 GRBL 默认是低电平有效(或反之),记得在 cpu_map.h 中修改宏定义,或者在 settings.c 中设置 $3 参数(方向取反)。
相关推荐
某林2122 小时前
ROS2 机器人底盘调试避坑指南:从 `/odom` 丢失到彻底跑通的硬核排障实录
stm32·机器人·人机交互
芯岭技术郦2 小时前
集成 2.4G 射频收发器、MCU 及丰富外设的XL2417D透传模组
单片机·嵌入式硬件
进击的小头3 小时前
第7篇:MOS 管最全入门:原理、关键参数、选型、驱动与典型应用
经验分享·科技·嵌入式硬件·学习
zlinear数据采集卡3 小时前
定时器电路深度解析:从经典555到STM32定时器,从ZLinear采集卡的工程化设计实战
stm32·单片机·嵌入式硬件·fpga开发·自动化
y.Ghost3 小时前
FreeRTOS-基础知识
嵌入式硬件
m0_377108143 小时前
stm32-USART
stm32·单片机·嵌入式硬件
szxinmai主板定制专家4 小时前
基于 ARM+FPGA精密多轴实时运动控制卡设计方案,适用于半导体设备等高精度领域(一)
arm开发·人工智能·嵌入式硬件·fpga开发·架构·语音识别
不做无法实现的梦~6 小时前
常见工程分析软件
stm32·嵌入式硬件·算法
国产电子元器件7 小时前
电流检测信号漂移问题分析
单片机·嵌入式硬件
YangWeiminPHD7 小时前
单片机AI边缘计算发展之路:从M0的开局到三足鼎立的智能革命
人工智能·单片机·边缘计算