STM32F103C8T6平台实现GRBL移植与G代码解析

一、系统架构设计

核心模块划分

  • 通信模块:USART1(波特率115200)接收G代码
  • 运动控制模块:4路PWM输出(使用TIM1高级定时器)
  • 解析引擎:GRBL 1.1f源码适配
  • 存储模块:SPI Flash存储G代码缓存

二、硬件配置实现

2.1 时钟配置(SystemClock_Config)

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;  // 72MHz
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    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;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}

2.2 定时器配置(TIM1 PWM生成)

void MX_TIM1_Init(void)
{
    TIM_HandleTypeDef htim1;
    
    htim1.Instance = TIM1;
    htim1.Init.Prescaler = 1;
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim1.Init.Period = 20000;  // 1MHz计数频率
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim1.Init.RepetitionCounter = 0;
    HAL_TIM_PWM_Init(&htim1);

    // 配置4路通道
    TIM_OC_InitTypeDef sConfigOC = {0};
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 1000;  // 初始占空比
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    
    HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1); // X轴
    HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2); // Y轴
    HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3); // Z轴
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_ALL);
}

三、GRBL源码移植

3.1 关键修改点

// 修改grbl.h硬件抽象层
#define STEPPER_TIMER TIM1
#define STEP_PORT GPIOA
#define STEP_PIN_X  GPIO_PIN_8
#define STEP_PIN_Y  GPIO_PIN_9
#define STEP_PIN_Z  GPIO_PIN_10

// 重写步进脉冲生成函数
void step_pulse_generate(uint8_t axis) {
    switch(axis) {
        case X_AXIS: HAL_GPIO_TogglePin(STEP_PORT, STEP_PIN_X); break;
        case Y_AXIS: HAL_GPIO_TogglePin(STEP_PORT, STEP_PIN_Y); break;
        case Z_AXIS: HAL_GPIO_TogglePin(STEP_PORT, STEP_PIN_Z); break;
    }
}

3.2 通信协议适配

// USART1中断处理
void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE)) {
        char c = USART_ReceiveData(USART1);
        grbl_rx_buffer[rx_index++] = c;
        if(c == '\n' || rx_index >= RX_BUFFER_SIZE) {
            grbl_parse_command(grbl_rx_buffer); // 调用GRBL解析器
            rx_index = 0;
        }
    }
}

四、G代码解析实现

4.1 解析器核心逻辑

typedef struct {
    float x, y, z;
    float feedrate;
    uint8_t command;
} GCodeCommand;

void grbl_parse_command(char* buffer) {
    GCodeCommand cmd = {0};
    char* token = strtok(buffer, " ");
    
    while(token != NULL) {
        if(strncmp(token, "G", 1) == 0) {
            cmd.command = atoi(token+1);
            parse_gcode_parameters(token+2, &cmd);
        }
        token = strtok(NULL, " ");
    }
    
    execute_gcode_command(&cmd); // 执行解析后的指令
}

void parse_gcode_parameters(char* str, GCodeCommand* cmd) {
    char* param = strtok(str, " ");
    while(param != NULL) {
        if(strncmp(param, "X", 1) == 0) cmd->x = atof(param+1);
        if(strncmp(param, "Y", 1) == 0) cmd->y = atof(param+1);
        if(strncmp(param, "F", 1) == 0) cmd->feedrate = atof(param+1);
        param = strtok(NULL, " ");
    }
}

五、运动控制算法

5.1 加减速控制(Trapezoidal Profile)

void motion_control(GCodeCommand* cmd) {
    static float current_feedrate = 0;
    
    // 加速阶段
    while(current_feedrate < cmd->feedrate) {
        current_feedrate += ACCELERATION * STEP_INTERVAL;
        if(current_feedrate > cmd->feedrate) current_feedrate = cmd->feedrate;
        set_motor_speed(current_feedrate);
    }
    
    // 匀速阶段
    while(distance_remaining > MIN_SEGMENT_LENGTH) {
        step_motor();
        update_position();
    }
    
    // 减速阶段
    while(current_feedrate > 0) {
        current_feedrate -= DECELERATION * STEP_INTERVAL;
        if(current_feedrate < 0) current_feedrate = 0;
        set_motor_speed(current_feedrate);
    }
}

5.2 步进电机驱动

void set_motor_speed(float speed) {
    uint16_t pulse_width = (uint16_t)(1000000 / speed); // 1MHz基准频率
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pulse_width);
}

参考代码 gcode解析、运动控制代码grbl移植于stm32f103c8t6平台 www.youwenfan.com/contentcnh/56183.html

六、调试与优化

6.1 性能监控

// 在main.c中添加性能统计
volatile uint32_t step_count = 0;
volatile uint32_t overflow_count = 0;

void TIM1_UP_TIM10_IRQHandler(void) {
    if(TIM_GetITStatus(TIM1, TIM_IT_UPDATE)) {
        step_count++;
        overflow_count++;
    }
}

// 计算实际运行速度
float calculate_speed() {
    float elapsed = (overflow_count * 0xFFFF + step_count) * TIMER_INTERVAL;
    return (float)step_count / elapsed;
}

6.2 常见问题解决

现象 解决方案
电机丢步 增加细分设置(TIM_CtrlPWMOutputs)
通信丢包 启用USART硬件流控(RTS/CTS)
解析延迟 优化字符串处理算法(状态机)
运动不平滑 实现前瞻算法(Look-ahead)

七、完整工程结构

├── Core/
│   ├── Inc/
│   │   ├── grbl.h
│   │   └── stm32f1xx_hal_conf.h
│   └── Src/
│       ├── main.c
│       └── tim.c
├── Drivers/
│   ├── CMSIS/
│   └── STM32F1xx_HAL_Driver/
├── Middlewares/
│   └── USB_Device/
└── Projects/
    └── STM32F103C8T6/
        └── GRBL_Config.h

八、测试用例

; 测试文件test.gcode
G21                 ; 单位毫米
G90                 ; 绝对坐标
G0 X10 Y10 F1000    ; 快速定位
G1 Z-5 F500         ; 切削进给
G0 Z50              ; 抬刀
M30                 ; 程序结束

通过上述方案,开发者可在STM32F103C8T6平台上实现稳定可靠的GRBL系统。建议优先使用HAL库进行开发,并针对具体硬件特性调整中断优先级和定时器参数。

posted @ 2025-09-18 11:18  吴逸杨  阅读(352)  评论(0)    收藏  举报