1. 前言
該項目是基于瑞薩 VisionBoard 主控芯片開發的多功能電機驅動器,核心通過 485 串口協議實現外部設備與驅動器的通訊,進而控制電機啟停等動作。開發過程中為豐富功能,臨時新增了通用隔離輸入輸出、步進電機驅動等硬件電路,目前已完成電源模塊、無刷電機驅動模塊、485 通訊模塊的功能驗證。
這次開發是實踐學習的過程:不僅接觸了新的 PCB 制圖工具完成電路布局與走線(雖布局走線仍有待優化),還學習了 RT-Thread 操作系統的基礎使用,同時初步掌握了瑞薩 VisionBoard 芯片及配套開發工具的操作邏輯。(我的這個作品項目主要是我個人學習一下第一次參加比較懵所以整體是一團亂的所以希望大家見諒哈謝謝)


(實力有限我只是把我想嘗試的部分先添加進去了看上去很雜后面會重新畫板打樣,然后功能這次就都一個模塊一個模塊去實現并沒有進行整合,然后另外的BTB拓展板是后面發現RPI的PWM口正常來說應該是三個可以實現PWM互補然后用六步換相吧好像但是工具不是很會用所以就麻煩了點然后不夠用所以就臨時打樣的有加LED數碼管和OLED并且把BTB的IO口用排針再引出來)
2. 設計方案
2.1電機模塊
2.1.1 電機選擇
選用兩類電機覆蓋不同場景:
無刷電機:用于持續運轉的場景;
步進電機:用于高精度位置控制的場景。
2.1.2 無刷電機控制
基于硬件電路實現驅動與監測:
核心驅動:采用 EG2123A 無刷電機驅動芯片(U29),輸出電機相驅動信號;
電流監測:通過 INA240 雙向電流檢測芯片(U25、U26),實時監測無刷電機的相電流;
功率輸出:由 NMOS 管組成的功率電路(Q4、Q5 等),放大驅動信號后連接無刷電機(接口 J8)。
這個是驅動波形(電機轉起來好像還是有點問題還得再測一下看看但是電路能正常的驅動電機)
2.1.3 步進電機控制
基于 A4988 芯片實現細分驅動:
驅動核心:采用 A4988 雙步進電機驅動芯片(U1、U2),支持 DIR(方向)、STEP(脈沖)控制;
電流監測:通過 INA219 電流檢測芯片(U3、U4),監測步進電機工作電流;
接口:通過 J10、J13 接口連接步進電機,傳輸驅動信號。

2.2 主控板及其按鍵模塊
2.2.1 主控芯片選擇
選用瑞薩 VisionBoard 系列芯片作為主控核心,負責:解析 485 通訊指令、輸出電機驅動信號、管理各功能模塊的邏輯調度。
2.2.2 無線通信模塊的選取(調整為:通訊模塊(485 串口通訊))
采用 “隔離 + 獨立供電” 的 485 通訊方案:
信號隔離:通過 TJA121M31 芯片(U13)實現主控與 485 總線的信號隔離;
總線收發:通過 GM485E 收發器(U16)完成 485 差分信號的轉換;
電源隔離:通過 B0505S-1WR3 模塊(U14)為 485 電路單獨供電,避免共地干擾;
接口:通過 J15 接口連接外部 485 設備。



這些主要是485測試到的波形能夠使用但是波形可能不太正常峰值沒有到3.3V還得修改。
2.2.3 通用隔離輸入輸出模塊
通過 EL357N 光耦實現信號隔離:
隔離輸入:外部信號經 2.2K 電阻限流、1N4148W 防反后,通過光耦(U18、U19)傳輸至主控(MCU_IN1~IN4,接口 U40);
隔離輸出:主控信號(MCU_OUT1~OUT2)經光耦(U20、U21)隔離后輸出(接口 U42、U7),配合 4.7K 上拉電阻增強驅動能力。
2.3.5 電源模塊
設計多級穩壓電路,為各模塊供電:
+12V 輸入:經 U54 芯片穩壓后,供給無刷電機驅動等高壓模塊;
+12V 轉 + 5V:經 U35 芯片轉換,供給 485 通訊、無刷驅動電路;
+5V 轉 + 3.3V:經 RT90L3-33GB LDO(U36)轉換,供給主控、光耦、電流檢測芯片等低壓模塊;
濾波:各電源支路搭配 10uF/0.1uF 電容,實現穩壓濾波。

下面這張圖是電源的紋波還可以個人感覺可能有機會再調試下電阻電容



下面的這幾張是降壓后的波形


3. 代碼工程
3.1源碼分享
分享 RT-Thread 在瑞薩 VisionBoard 的適配代碼;
提供 485 驅動、無刷電機驅動、電源監測等模塊的源碼(含初始化、指令解析邏輯)。
rasc配置以及部分代碼
PWM參數死區時間波形方式以及頻率等需要按照實際去調
可參考RT-Thread指南
《RA8D1 Vision Board開發實踐指南》上線啦
十三、RA8D1 Vision Board上的IIC實踐(歐小龍)
(https://club.rt-thread.org/ask/article/ee39d1a9067b6ca0.html)
RT-Thread-【Vision Board 創客營】Vision Board上的ADC實踐RT-Thread問答社區 - RT-Thread
(https://club.rt-thread.org/ask/article/921f3b1452d1d203.html)
[RT-Thread-Vision Board創客營] PWM模塊實踐RT-Thread問答社區 - RT-Thread
(https://club.rt-thread.org/ask/article/921f3b1452d1d203.html)
motor_ctrl.c
#include"FOC.h"#include"rtdevice.h"
#defineMOTOR_THREAD_STACK_SIZE 2048
#defineMOTOR_THREAD_PRIORITY 8
#defineMOTOR_THREAD_TIMESLICE 10
#defineMAX_TARGET_SPEED_RPM 2400.0f
#defineSPEED_RAMP_RATE 100.0f
static float current_target_speed = 0.0f;
static rt_bool_t motor_enabled = RT_FALSE;
static rt_uint16_t motor_pole_pairs = 7;
static float rpm_to_radps(float rpm) {
return rpm 2.0f PI / 60.0f;
}
static float radps_to_rpm(float radps) {
return radps 60.0f / (2.0f PI);
}
static float speed_ramp(float target_speed, float current_speed, float dt) {
float max_delta = SPEED_RAMP_RATE * dt;
if (target_speed > current_speed) {
current_speed += max_delta;
if (current_speed > target_speed) current_speed = target_speed;
} else {
current_speed -= max_delta;
if (current_speed < target_speed) current_speed = target_speed;?
} return current_speed;
}
static void motor_thread_entry(void *parameter) {
static rt_tick_t last_time = 0;
static float current_speed_rpm = 0.0f;
foc_init(); foc_start(); motor_enabled = RT_TRUE;
while (1) { rt_tick_t current_time = rt_tick_get(); float dt = (current_time - last_time) * 0.001f; if (dt <= 0) dt = 0.001f;
if (motor_enabled) {
float target_velocity = get_target_velocity();
float target_speed_rpm = radps_to_rpm(target_velocity);
target_speed_rpm = target_speed_rpm > MAX_TARGET_SPEED_RPM ? MAX_TARGET_SPEED_RPM : target_speed_rpm;
target_speed_rpm = target_speed_rpm < -MAX_TARGET_SPEED_RPM ? -MAX_TARGET_SPEED_RPM : target_speed_rpm;
current_speed_rpm = speed_ramp(target_speed_rpm, current_speed_rpm, dt);
float target_mech_radps = rpm_to_radps(current_speed_rpm);
FOC_M0_SET_VEL(target_mech_radps);
foc_loop();
if (current_time - last_time > RT_TICK_PER_SECOND) {
float actual_vel = getVelocity();
float actual_rpm = radps_to_rpm(actual_vel);
rt_kprintf("Motor: Target=%.1fRPM, Actual=%.1fRPM\n", current_speed_rpm, actual_rpm);
last_time = current_time;
}
} else {
current_speed_rpm = 0;
FOC_M0_SET_VEL(0);
}
rt_thread_mdelay(1);
last_time = current_time;
}
}
void motor_start(void) {
rt_thread_t tid = rt_thread_create("motor", motor_thread_entry, RT_NULL, MOTOR_THREAD_STACK_SIZE, MOTOR_THREAD_PRIORITY, MOTOR_THREAD_TIMESLICE);
if (tid) { rt_thread_startup(tid);
}
}
void motor_enable(rt_bool_t enable) {
motor_enabled = enable;
if (!enable) {
set_target_velocity(0);
}
}
rs485.c
#include"bsp_rs485.h"
#include"hal_data.h"
#defineRS485_RX_BUF_SIZE 100
#defineRS485_SWITCH_DELAY 10
static uint8_t rs485_rx_data[RS485_RX_BUF_SIZE];
static volatile uint16_t rs485_rx_datalen;
static volatile bool rs485_rx_complete;
static volatile bool rs485_tx_complete;
fsp_err_t RS485_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_SCI_B_UART_Open(&g_uart2_rs485_ctrl, &g_uart2_rs485_cfg);
if(FSP_SUCCESS != err) return err;
err = R_SCI_B_UART_Read(&g_uart2_rs485_ctrl, rs485_rx_data, RS485_RX_BUF_SIZE);
return err;
}
void RS485_Print(uint8_t *str, uint32_t strlen)
{
RS485_TX_EN;
R_BSP_SoftwareDelay(RS485_SWITCH_DELAY, BSP_DELAY_UNITS_MILLISECONDS);
rs485_tx_complete = false;
R_SCI_B_UART_Write(&g_uart2_rs485_ctrl, str, strlen);
while(false == rs485_tx_complete);
R_BSP_SoftwareDelay(RS485_SWITCH_DELAY, BSP_DELAY_UNITS_MILLISECONDS);
RS485_RX_EN;
}
uint16_t RS485_GetRxData(uint8_t *buf, uint16_t len)
{
uint16_t copy_len = (rs485_rx_datalen < len) ? rs485_rx_datalen : len;
R_BSP_InterruptsDisable();
memcpy(buf, rs485_rx_data, copy_len);
rs485_rx_datalen = 0;
rs485_rx_complete = false;
R_BSP_InterruptsEnable();
R_SCI_B_UART_Read(&g_uart2_rs485_ctrl, rs485_rx_data, RS485_RX_BUF_SIZE);
return copy_len;
}
bool RS485_GetRxComplete(void)
{
return rs485_rx_complete;
}
void rs485_uart2_callback(uart_callback_args_t *p_args)
{
switch(p_args->event)
{
case UART_EVENT_RX_COMPLETE:
rs485_rx_complete = true;
break;
case UART_EVENT_RX_CHAR:
R_BSP_InterruptsDisable();
if(rs485_rx_datalen < RS485_RX_BUF_SIZE)
{
rs485_rx_data[rs485_rx_datalen] = (uint8_t)p_args->data;
rs485_rx_datalen++;
}
R_BSP_InterruptsEnable();
break;
case UART_EVENT_TX_COMPLETE:
rs485_tx_complete = true;
break;
default:
break;
}
}
-
瑞薩
+關注
關注
37文章
22481瀏覽量
90847 -
電機驅動器
+關注
關注
16文章
860瀏覽量
66429 -
RT-Thread
+關注
關注
32文章
1613瀏覽量
44818
發布評論請先 登錄
【瑞薩RA4系列開發板體驗】+RT-thread5.0.0
RT-Thread Studio驅動SD卡
RT-Thread大會:瑞薩e- AI成功案例及部署
瑞薩電子正式成為RT-Thread金牌會員:進一步加速RA生態發展
【線下培訓】上海臨港: RT-Thread × 瑞薩 工業監視器 RA6M3 HMI Board解決方案
【議程發布】10月上海線下培訓:RT-Thread × 瑞薩 工業監視器+HMI解決方案!
【好書推薦】RT-Thread設備驅動開發指南
基于RT-Thread與瑞薩 VisionBoard 的多功能電機驅動器開發 | 技術集結





評論