瑞萨单片机论坛
直播中

jf_07365693

1年用户 380经验值
擅长:嵌入式技术 控制/MCU
私信 关注
[讨论]

【RA4E2开发板评测】步进电机的串口控制

step-motor

【RA-Eco-RA4E2-64PIN-V1.0 开发板】步进电机的串口控制

本文介绍了 RA-Eco-RA4E2-64PIN-V1.0 开发板通过串口指令实现 28BYJ-48 步进电机旋转角度和速度的精确控制的项目设计。

项目介绍

  • 硬件连接:28BYJ-48 步进电机、ULN2003 驱动板、Jlink 调试器、供电电源等;
  • 工程创建:部署 GPIO 、 UART 、串口中断等配置;
  • 工程代码:包括主函数、步进电机驱动代码、串口配置代码等;
  • 测试效果:包括串口发送指令、步进电机旋转控制、串口打印状态信息等。

硬件连接

接线方式如下

ULN2003 驱动板 RA4E2 说明
IN1 P100 步进脉冲 A
IN2 P101 步进脉冲 B
IN3 P104 步进脉冲 C
IN4 P112 步进脉冲 D
VCC 5V 驱动板电源
GND GND 共地

串口通信使用板载 USB 转 TTL 工具,对应 P109 (TXD9) 和 P110 (RXD9) 引脚。

实物图

step-motor-connect.jpg

工程创建

  • 打开 e^2^ studio 软件;
  • 依次点击 文件 - 新建 - 瑞萨 C/C++ 项目 - Renesas RA
  • 依次进行工程命名,路径设置,FSP版本,目标开发板选择,Device 选择 R7FA4E2B93CFM ,工具链选择 GNU ARM Embedded ,调试器选择 J-Link ,完成工程创建 ;

串口配置

  • 进入 FSP 配置界面,打开 Pins 标签页,根据原理图或开发板丝印,将 P109 和 P110 引脚分别配置为 TXD9 和 RXD9 串口模式;
  • 新建串口通信堆栈 New Stack - Connectivity - UART (r_sci_uart)
  • 串口属性配置,General 标签下的 Channel 改为 9,名称改为 g_uart9,中断回调函数命名为 user_uart_callback
  • 进入 BSP 标签页,配置 RA Common 属性,RA Common 标签下的 Heap size 改为 0x1000 ,Main Stack Size 设置为 0x2000 以确保堆栈空间充足;

GPIO 配置

  • 进入 FSP 配置界面,打开 Pins 标签页,选中 P100 引脚,模式配置为初始低电平的输出模式;
  • 同理,将 P101、P104 和 P112 管脚也配置为初始低电平的输出模式;
  • 点击 Generate Project Content 按钮,生成工程代码。

流程图

flowchart_step-motor_uart_control.jpg

工程代码

在左侧的项目目录中,打开 src/hal_entry.c 文件,添加如下关键代码

hal_entry.c

#include "hal_data.h"
#include "stepper_motor.h"
#include <stdio.h>

FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER

fsp_err_t err = FSP_SUCCESS;
volatile bool uart_send_complete_flag = false;

// 你的串口回调函数
void user_uart_callback(uart_callback_args_t * p_args) {
    if (p_args->event == UART_EVENT_TX_COMPLETE) {
        uart_send_complete_flag = true;
    }
    // 添加接收中断处理
    else if (p_args->event == UART_EVENT_RX_CHAR) {
        stepper_motor_uart_callback(p_args); // 调用我们的接收处理函数
    }
}

/*------------- 串口重定向 -------------*/
#ifdef __GNUC__
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#endif

PUTCHAR_PROTOTYPE {
    err = R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);
    if (FSP_SUCCESS != err) __BKPT();
    while(uart_send_complete_flag == false) {}
    uart_send_complete_flag = false;
    return ch;
}

int _write(int fd, char *pBuffer, int size) {
    for (int i = 0; i < size; i++) {
        __io_putchar(*pBuffer++);
    }
    return size;
}

void hal_entry(void)
{
    /* TODO: add your own code here */
    // 初始化UART
    err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
    assert(FSP_SUCCESS == err);

    if (FSP_SUCCESS != err) {
        printf("UART open failed: 0x%x\r\n", err);
        return;
    }

    printf("RA4E2 - Stepper Motor - UART Debug\r\n");
    //printf("UART initialized at 115200 baud\r\n");

    // 初始化步进电机
    stepper_motor_init();

    // 测试直接调用 - 确认电机本身工作正常
    //printf("Testing direct call: rotating 90 degrees...\r\n");
    //stepper_motor_rotate_degrees(90.0f);
    //stepper_motor_stop();
    //R_BSP_SoftwareDelay(2000, BSP_DELAY_UNITS_MILLISECONDS);

    //printf("Direct call test completed.\r\n");
    //printf("Now testing UART reception...\r\n");

    // 启用UART接收
    uint8_t dummy;
    err = R_SCI_UART_Read(&g_uart9_ctrl, &dummy, 1);
    if (err != FSP_SUCCESS) {
        printf("UART read start failed: 0x%x\r\n", err);
    }

    // 设置回调函数
    g_uart9_ctrl.p_callback = user_uart_callback;

    // 启用全局中断
    __enable_irq();

    printf("Ready to receive angle values.\r\n");
    printf("Send numbers like: 90, -45, 180, 360\r\n");
    printf("Waiting for UART data...\r\n");

    uint32_t counter = 0;
    while (1) {
        // 显示系统运行状态
        if (counter % 100 == 0) {
            //printf("System running: %lu, Buffer index: %u\r\n", counter, g_uart_buffer_index);
        }

        // 检查是否有数据接收
        if (g_uart_received) {
            printf("Data received! Processing...\r\n");
            stepper_motor_process_command();
        }

        // 检查缓冲区是否有内容但未完成接收
        if (g_uart_buffer_index > 0 && !g_uart_received) {
            printf("Buffer content: ");
            for (uint16_t i = 0; i < g_uart_buffer_index; i++) {
                printf("%c(0x%02X) ", g_uart_buffer[i], g_uart_buffer[i]);
            }
            printf("\r\n");
        }

        R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS);
        counter++;
    }

    #if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

stepper_motor.h

新建 stepper_motor.h 头文件,添加如下代码

#ifndef STEPPER_MOTOR_H_
#define STEPPER_MOTOR_H_

#include "hal_data.h"
#include <stdbool.h>

// 引脚定义
#define MOTOR_PIN_IN1 BSP_IO_PORT_01_PIN_00
#define MOTOR_PIN_IN2 BSP_IO_PORT_01_PIN_01
#define MOTOR_PIN_IN3 BSP_IO_PORT_01_PIN_04
#define MOTOR_PIN_IN4 BSP_IO_PORT_01_PIN_12

// 每转步数
#define STEPS_PER_REVOLUTION 509.0f
#define UART_BUFFER_SIZE 32

// 全局变量声明
extern char g_uart_buffer[UART_BUFFER_SIZE];
extern volatile uint16_t g_uart_buffer_index;
extern volatile bool g_uart_received;

// 函数声明
void stepper_motor_init(void);
void stepper_motor_rotate_steps(int32_t steps);
void stepper_motor_rotate_degrees(float degrees);
void stepper_motor_set_velocity(uint32_t velocity_ms);
void stepper_motor_stop(void);
void stepper_motor_show_help(void);
void stepper_motor_uart_callback(uart_callback_args_t *p_args);
void stepper_motor_process_command(void);
float parse_angle_command(const char *command);

#endif /* STEPPER_MOTOR_H_ */

stepper_motor.c

新建 stepper_motor.c 源文件,添加如下代码

#include "stepper_motor.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

// 四相八拍序列
const uint8_t STEP_SEQ[8][4] = {
    {1, 0, 0, 1}, {1, 0, 0, 0}, {1, 1, 0, 0}, {0, 1, 0, 0},
    {0, 1, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 1}, {0, 0, 0, 1}
};

// 全局变量
static uint32_t g_step_delay_ms = 1;

void stepper_motor_init(void) {
    // 初始化引脚
    R_IOPORT_PinWrite(&g_ioport_ctrl, MOTOR_PIN_IN1, BSP_IO_LEVEL_LOW);
    R_IOPORT_PinWrite(&g_ioport_ctrl, MOTOR_PIN_IN2, BSP_IO_LEVEL_LOW);
    R_IOPORT_PinWrite(&g_ioport_ctrl, MOTOR_PIN_IN3, BSP_IO_LEVEL_LOW);
    R_IOPORT_PinWrite(&g_ioport_ctrl, MOTOR_PIN_IN4, BSP_IO_LEVEL_LOW);

    printf("Stepper motor initialized.\r\n");
}

static void set_coil_state(uint8_t in1, uint8_t in2, uint8_t in3, uint8_t in4) {
    R_IOPORT_PinWrite(&g_ioport_ctrl, MOTOR_PIN_IN1, in1 ? BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
    R_IOPORT_PinWrite(&g_ioport_ctrl, MOTOR_PIN_IN2, in2 ? BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
    R_IOPORT_PinWrite(&g_ioport_ctrl, MOTOR_PIN_IN3, in3 ? BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
    R_IOPORT_PinWrite(&g_ioport_ctrl, MOTOR_PIN_IN4, in4 ? BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
}

void stepper_motor_rotate_steps(int32_t steps) {
    if (steps == 0) {
        printf("No steps to rotate.\r\n");
        return;
    }

    int8_t direction = (steps >= 0) ? 1 : -1;
    uint32_t absolute_steps = (uint32_t)abs(steps);

    printf("Rotating %s, steps: %lu, delay: %lums\r\n",
           (direction > 0) ? "CW" : "CCW", absolute_steps, g_step_delay_ms);

    for (uint32_t i = 0; i < absolute_steps; i++) {
        if (direction > 0) {
            // 顺时针
            for (int phase = 0; phase < 8; phase++) {
                set_coil_state(STEP_SEQ[phase][0], STEP_SEQ[phase][1],
                              STEP_SEQ[phase][2], STEP_SEQ[phase][3]);
                R_BSP_SoftwareDelay(g_step_delay_ms, BSP_DELAY_UNITS_MILLISECONDS);
            }
        } else {
            // 逆时针
            for (int phase = 7; phase >= 0; phase--) {
                set_coil_state(STEP_SEQ[phase][0], STEP_SEQ[phase][1],
                              STEP_SEQ[phase][2], STEP_SEQ[phase][3]);
                R_BSP_SoftwareDelay(g_step_delay_ms, BSP_DELAY_UNITS_MILLISECONDS);
            }
        }

        // 每100步输出进度
        if ((i + 1) % 100 == 0) {
            printf("Progress: %lu/%lu steps\r\n", i + 1, absolute_steps);
        }
    }

    printf("Rotation completed.\r\n");
}

void stepper_motor_rotate_degrees(float degrees) {
    // 计算步数
    float steps_float = degrees * (STEPS_PER_REVOLUTION / 360.0f);
    int32_t steps = (int32_t)steps_float;

    printf("Angle: %.1f° -> Steps calculation:\r\n", degrees);
    //printf("  Steps/revolution: %.0f\r\n", STEPS_PER_REVOLUTION);
    //printf("  Calculated steps: %.1f\r\n", steps_float);
    //printf("  Rounded steps: %ld\r\n", steps);

    stepper_motor_rotate_steps(steps);
}

void stepper_motor_set_velocity(uint32_t velocity_ms) {
    g_step_delay_ms = velocity_ms;
    //printf("Speed set to: %lums/step\r\n", g_step_delay_ms);
}

void stepper_motor_stop(void) {
    set_coil_state(0, 0, 0, 0);
    printf("Motor stopped.\r\n");
}

void stepper_motor_show_help(void) {
    printf("=== Stepper Motor Simple Control ===\r\n");
    printf("Send angle values via UART:\r\n");
    printf("  Examples:\r\n");
    printf("    90     - Rotate 90 degrees clockwise\r\n");
    printf("    -45    - Rotate 45 degrees counter-clockwise\r\n");
    printf("    180    - Rotate 180 degrees\r\n");
    printf("    360    - Rotate full circle\r\n");
    printf("  Fixed speed: 1ms/step\r\n");
    printf("====================================\r\n");
}

stepper_motor_uart.c

新建 stepper_motor_uart.c 源文件,添加如下代码

#include "stepper_motor.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>

// 全局变量定义
char g_uart_buffer[UART_BUFFER_SIZE];
volatile uint16_t g_uart_buffer_index = 0;
volatile bool g_uart_received = false;

// 固定速度
static uint32_t g_fixed_velocity = 1; // 固定为1ms

// 串口中断回调函数
void stepper_motor_uart_callback(uart_callback_args_t *p_args) {
    if (p_args->event == UART_EVENT_RX_CHAR) {
        uint8_t received_char = (uint8_t)p_args->data;

        // 回车或换行表示命令结束
        if (received_char == '\r' || received_char == '\n') {
            if (g_uart_buffer_index > 0) {
                g_uart_buffer[g_uart_buffer_index] = '\0';
                g_uart_received = true;
            }
            g_uart_buffer_index = 0;
        }
        // 添加到缓冲区
        else if (g_uart_buffer_index < UART_BUFFER_SIZE - 1) {
            g_uart_buffer[g_uart_buffer_index++] = received_char;
        }
        // 缓冲区满
        else {
            g_uart_buffer_index = 0; // 重置缓冲区
        }
    }
}

// 解析角度命令
float parse_angle_command(const char *command) {
    if (command == NULL || strlen(command) == 0) {
        printf("Empty command\r\n");
        return 0.0f;
    }

    printf("Received command: %s\r\n", command);

    // 直接转换为浮点数
    char *endptr;
    float angle = strtof(command, &endptr);

    // 检查转换是否成功
    if (endptr == command) {
        printf("Invalid number format: %s\r\n", command);
        return 0.0f;
    }

    // 检查是否有额外字符
    while (*endptr != '\0') {
        if (!isspace(*endptr)) {
            printf("Extra characters in command: %s\r\n", endptr);
            break;
        }
        endptr++;
    }

    printf("Parsed angle: %.1f°\r\n", angle);
    return angle;
}

// 处理接收到的命令
void stepper_motor_process_command(void) {
    if (g_uart_received) {
        // 复制缓冲区内容
        char local_buffer[UART_BUFFER_SIZE];
        strncpy(local_buffer, g_uart_buffer, UART_BUFFER_SIZE);

        printf("Processing command: %s\r\n", local_buffer);

        // 解析角度
        float angle = parse_angle_command(local_buffer);

        if (fabsf(angle) > 0.1f) {
            printf("Executing: %.1f° at fixed speed: %lums/step\r\n", angle, g_fixed_velocity);

            // 设置固定速度
            stepper_motor_set_velocity(g_fixed_velocity);

            // 执行旋转
            stepper_motor_rotate_degrees(angle);

            // 停止电机
            stepper_motor_stop();
            printf("Execution completed.\r\n");

        } else if (fabsf(angle) > 0.0f) {
            printf("Angle too small: %.1f°\r\n", angle);
        }

        // 重置标志
        g_uart_received = false;
        g_uart_buffer_index = 0;
        memset(g_uart_buffer, 0, sizeof(g_uart_buffer));
    }
}
  • 保存代码,右键项目 - 构建程序;
  • 右键项目 - 调试项目 - 上传固件至开发板。

测试效果

  • 28 BYJ-48 步进电机、ULN2003 驱动板、RA4E2 开发板接线硬件连接完成;
  • TypeC - USB 数据线连接开发板串口和电脑;
  • 打开串口调试助手,配置对应的波特率等参数;
  • 打开串口,即可接收芯片发送的字符串;

step-motor_uart_control_print.jpg

同时串口打印输出步进电机状态

» 90
« Data received! Processing...
Processing command: 90
Received command: 90
Parsed angle: 90.0°
Executing: 90.0° at fixed speed: 1ms/step
Angle: 90.0° -> Steps calculation:
Rotating CW, steps: 127, delay: 1ms
Progress: 100/127 steps
Rotation completed.
Motor stopped.
Execution completed.

动态效果见底部视频。

总结

本文介绍了 RA-Eco-RA4E2-64PIN-V1.0 开发板通过串口指令实现 28BYJ-48 步进电机旋转角度和速度的精确控制的项目设计,包括硬件连接、工程创建、工程代码、测试效果等流程,为 Renesas RA 系列产品在工业自动化、科研仪器控制等相关领域的开发设计和应用提供了参考。

step-motor_uart_control

回帖(1)

无垠的广袤

2025-8-25 11:35:38
666啊,结合串口中断和GPIO,实现步进电机控制,具有很强的实用价值和意义~
1 举报

更多回帖

发帖
×
20
完善资料,
赚取积分