数控直流电源DIY — RA6E2 + INA226 + XL4015 + OLED旋转编码器
一、项目概述
本文介绍如何制作一台小型数控直流电源,具有以下特点:
- 输出电压:1.0V ~ 5.0V 可调
- 显示方式:OLED 屏幕,旋转编码器设置
- 控制方式:PI 闭环自动调节
- 硬件平台:瑞萨 RA6E2 + TI INA226 电流监测 + XL4015 DC-DC
硬件架构

硬件清单
| 器件 |
说明 |
| RA6E2 |
瑞萨 32 位 MCU,12-bit DAC |
| INA226 |
TI 双向电流/功率监测,I2C 地址 0x40 |
| XL4015 |
降压 DC-DC 芯片,FB 基准约 0.6V |
| 100mΩ 分流电阻 |
INA226 电流采样 |
| 1N4007 二极管 |
串联在 DAC 和 FB 之间 |
| SSD1306 OLED |
128x64 I2C OLED 屏幕 |
| EN11 旋转编码器 |
带按钮,用于设置电压 |
二、硬件连接
2.1 引脚连接
| 功能 |
RA6E2 引脚 |
说明 |
| DAC 输出 |
P014 |
连接二极管 → XL4015 FB |
| I2C SCL |
P109 |
SCI9 → OLED / INA226 |
| I2C SDA |
P110 |
SCI9 → OLED / INA226 |
| 编码器 A |
P301 |
旋转编码器 A 相 |
| 编码器 B |
P302 |
旋转编码器 B 相 |
| 编码器 BTN |
P303 |
旋转编码器按钮 |
2.2 控制原理
DAC 输出电压 → 二极管(压降0.7V) → XL4015 FB 引脚
↓
XL4015 内部基准 ≈ 0.6V ← FB 引脚期望电压
↓
DAC = 0.6V + 0.7V ≈ 1.3V 对应 DAC 值 1613
通过 PI 控制器调节 DAC 电压,从而控制 XL4015 输出稳定在设定值。
三、软件架构
3.1 目录结构
app/ra6e2_dac_ina226/
├── CMakeLists.txt # 构建配置
├── prj.conf # Kconfig 配置
├── boards/
│ └── fpb_ra6e2.overlay # 设备树覆盖
└── src/
├── main.c # 主程序 + PI 控制器
├── encoder.c/h # 旋转编码器驱动
├── ina226.c/h # INA226 I2C 驱动
├── oled.c/h # SSD1306 OLED 驱动
└── gui.c/h # GUI 绘图函数
3.2 系统任务
┌─────────────────────────────────────────────────────────┐
│ control_thread (优先级5, 10ms周期) │
│ - 读取 INA226 电压/电流/功率 │
│ - PI 计算误差并调节 DAC │
│ - 更新全局共享变量 │
└─────────────────────────────────────────────────────────┘
↑ g_vbus, g_current, g_power, g_dac_val, g_error
↓
┌─────────────────────────────────────────────────────────┐
│ encoder_poll (5ms轮询) │
│ - 读取编码器 A/B 相状态 │
│ - 检测旋转方向 CW/CCW │
│ - 检测按钮按下/释放/长按 │
└─────────────────────────────────────────────────────────┘
↓ 事件回调
┌─────────────────────────────────────────────────────────┐
│ encoder_callback │
│ - CW/CCW: 调节 g_set_temp_mv (SET模式下) │
│ - RELEASE: 切换 VIEW↔SET,SET时提交目标电压 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ display_timer (200ms周期) │
│ - display_work_handler │
│ - 显示 DC Power / Set电压 / Vout / [SET] / OK │
└─────────────────────────────────────────────────────────┘
3.3 菜单状态机
┌─────────────┐
│ MENU_VIEW │◄────────────────┐
│ 正常显示 │ │
│ PI调节中 │ │
└──────┬──────┘ │
│ │
按下按钮 │
│ │
▼ │
┌─────────────┐ │
┌───►│ MENU_SET │─────────────────┘
│ │ 设置电压 │ 按下按钮(退出)
│ │ 可调节目标 │
│ └─────────────┘
│ │
│ 旋转编码器
│ │
│ ±50mV/格
│ │
└───────────┘
四、关键代码
4.1 PI 控制器
#define TARGET_MV 3300 // 目标电压 3.3V
#define KP 80 // 比例系数
#define KI 8 // 积分系数
#define DAC_MIN 500 // DAC 最小值
#define DAC_MAX 3500 // DAC 最大值
#define HYSTERESIS_MV 50 // 滞环 ±25mV
static int dac_val = DAC_INIT_VAL;
static int integral = 0;
static int pi_control(int error_mv)
{
int p = error_mv * KP;
integral += error_mv * KI;
// 积分限幅,防止积分饱和
if (integral > 500000) integral = 500000;
if (integral < -500000) integral = -500000;
int delta = (p + integral) / 1000;
int new_dac = dac_val + delta;
if (new_dac < DAC_MIN) new_dac = DAC_MIN;
if (new_dac > DAC_MAX) new_dac = DAC_MAX;
return new_dac;
}
4.2 旋转编码器驱动
使用 GPIO 轮询方式(5ms 间隔),兼容不支持 GPIO 中断的平台:
/* encoder.h */
struct encoder {
const struct device *gpio_dev;
gpio_pin_t pin_a, pin_b, pin_btn;
encoder_callback_t callback;
void *user_data;
int8_t last_state;
int last_btn;
uint32_t btn_press_time;
struct k_timer poll_timer;
};
/* 编码器事件 */
enum encoder_event {
ENCODER_EVENT_CW, // 顺时针旋转
ENCODER_EVENT_CCW, // 逆时针旋转
ENCODER_EVENT_PRESS, // 按钮按下
ENCODER_EVENT_RELEASE, // 按钮释放(短按)
ENCODER_EVENT_LONG_PRESS, // 按钮长按(>1s)
};
4.3 编码器回调
static void encoder_callback(enum encoder_event evt, void *user_data)
{
switch (evt) {
case ENCODER_EVENT_CW:
if (g_menu_state == MENU_SET) {
g_set_temp_mv += 50; // SET模式下 ±50mV/格
if (g_set_temp_mv > 5000) g_set_temp_mv = 5000;
}
break;
case ENCODER_EVENT_CCW:
if (g_menu_state == MENU_SET) {
g_set_temp_mv -= 50;
if (g_set_temp_mv < 1000) g_set_temp_mv = 1000;
}
break;
case ENCODER_EVENT_RELEASE:
// 短按切换 VIEW ↔ SET 模式
if (g_menu_state == MENU_VIEW) {
g_menu_state = MENU_SET;
g_set_temp_mv = g_target_mv; // 复制当前目标
} else if (g_menu_state == MENU_SET) {
g_target_mv = g_set_temp_mv; // 提交新目标
g_menu_state = MENU_VIEW;
}
break;
}
}
4.4 OLED 显示
VIEW 模式(正常显示):
┌─────────────────────────────┐
│ RA6E2 DC Power │ ← 标题居中 (16pt)
│ Vout: 3.298V │ ← 输出电压 (16pt)
│ Current: 125mA │ ← 电流 (16pt)
└─────────────────────────────┘
SET 模式(设置电压):
┌─────────────────────────────┐
│ RA6E2 DC Power │ ← 标题居中 (16pt)
│ Vout: 3.298V │ ← 输出电压 (16pt)
│ Current: 125mA │ ← 电流 (16pt)
│ Set: 3.500V │ ← 目标电压 (16pt, 反白)
└─────────────────────────────┘
显示布局:
| 行 |
Y坐标 |
内容 |
| 0 |
y=0 |
标题 "RA6E2 DC Power" 居中显示 |
| 1 |
y=16 |
Vout: X.XXXV (实测输出电压) |
| 2 |
y=30 |
Current: XXXmA (输出电流) |
| 3 |
y=48 |
Set: X.XXXV (SET模式下显示, 16pt) |
五、INA226 驱动
5.1 寄存器配置
// CONFIG: Shunt+Bus 连续模式, 1100μs 转换时间
INA226_Write_Reg(INA226_REG_CONFIG, 0x4527);
// CAL: Rshunt=100mΩ, Current_LSB=20μA
// CAL = 5120000000 / (20 × 100000) = 2560 = 0x0A00
INA226_Write_Reg(INA226_REG_CALIB, 0x0A00);
5.2 读取函数
// 总线电压: LSB=1.25mV
int INA226_Read_Voltage_mV(i2c_dev);
// 电流: LSB=20μA
int INA226_Read_Current_mA(i2c_dev);
// 功率: LSB=0.5mW
int INA226_Read_Power_mW(i2c_dev);
六、操作说明
6.1 正常使用时
- 打开电源,OLED 显示当前输出电压和电流
- PI 控制器自动调节,保持输出稳定
6.2 调节电压
- 按一下按钮 → 进入设置模式,底部显示 "Set: X.XXXV"
- 旋转编码器 → 调节目标电压(±50mV/格)
- 再按一下按钮 → 退出设置,新电压生效
6.3 参数调优
| 现象 |
调整 |
| 响应太慢 |
↑ KI |
| 电压振荡 |
↓ KP, ↓ KI |
| 超调过大 |
↓ KP |
| 频繁调节 |
↑ HYSTERESIS_MV |
七、总结
本文实现了一个完整的数控电源系统:
- ✅ DAC + PI 闭环控制输出电压
- ✅ INA226 实时监测电压/电流
- ✅ OLED 显示 Vout、Current、设置值
- ✅ 旋转编码器交互控制
- ✅ 退出设置时电压才生效(防误触)
八、实验效果

设置界面:

设置后的效果:
