你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32H5 评测】基于NUCLEO_H5E5ZJ+Zephyr数字电源

[复制链接]
lugl 发布时间:2026-10-18 11:31
前面几篇的试用文章我驱动了lcd屏,spi等外设,这一篇我将分享Zephyr来实现一个数字电源,用到的是EVL4248-QV-00A评估板,通过I2C与ADC来实现。3 T5 I  j9 p) j2 k& R; j
) P% N; l, ]3 P( U# k

+ y7 H* Y8 Q  N" G8 V' S( v9 X4 z一、EVL4248-QV-00A 评估板简介
: E$ g& E. P8 h1 G' m0 j; pEVL4248-QV-00A 是 MPS 的数字电源评估板,核心是一片 MP4248GQV:四开关 Buck-Boost 变换器 + I2C(PMBus)数字接口。 ScreenShot_2026-10-18_111706_057.png ' K" d  P$ @) ~+ ~/ W$ Z
- h6 Z( A, A9 N) \
evl4248参数介绍.png
: F3 S, s$ s  E( O9 T8 D+ p0 M. v二、控制引脚与反馈引脚2 J$ m  C2 ]/ e# h3 [9 j' Y# M
控制引脚.png
4 @5 h- V5 p. n4 ^9 LI2C 关键寄存器(PMBus):9 V, v; [0 _  a- J; r" q
数据电源寄存器.png # r2 P5 D0 L. z9 B4 |7 m: r. {' K
三、与开发板的接法
+ H; b; _& v+ T) w 开发板与ev4248接法.png ( x& z/ ~6 W/ t) X2 x$ K
四、系统框图
0 ^. c: S( J1 W dps_block_diagram.png " M& X) b$ n9 Z# R& C
* G: L# \8 l4 ~! b6 i/ G
功率通路:直流输入 → EVL4248(MP4248 升降压)→ 输出端子 → 负载。
. J' N7 \2 ?: a控制/反馈通路:I2C4 下发调压限流;IMON(电流)与 VOUT 分压(电压)进 ADC 实测回读;摇杆+LCD 做人机交互。
. N- `- u6 o7 @界面用 lcd_bare 裸驱动文本渲染(不用 LVGL,轻量直接),160×128 屏按行组织,按行覆盖刷新(无整屏闪烁):
& r4 c1 f. A* {" \$ f4 R 数字电源.jpg ; d8 p+ E, K" W2 g8 v( ^) B8 V
六、系统控制逻辑
+ H+ A9 p0 D/ }; t) H& |9 f' ]( Z* z 数字电源控制逻辑.png
4 j+ ?; o' d3 B! j5 Z  g0 {# k/ b$ {; |& `2 C
设计要点:  @+ W# B( `8 {: D0 X
• 写后即读:SET/ILIM 行显示"设定值/读回值",写没生效一眼看出;
9 R% K7 R/ f' y3 `% O1 \. a# ~• 故障锁存语义:PMBus 状态位锁存,CLEAR_FAULTS 在开输出时自动发——历史故障与当前状态分离;
5 D+ @9 \  u& g2 d! g3 n• CC 是调节不是故障:进恒流时芯片降压维持电流,VOUT 实测会掉,ST 记录 OC 事件,这些都如实上屏。: N# v% b0 G- h
七、Zephyr 主要代码2 ?/ P. N$ c' ]
7.1 prj.conf
9 g" P! ^( [# z0 }) t2 A5 F
  1. CONFIG_GPIO=y& L' F& G' J5 F' ?
  2. CONFIG_SPI=y
    ) J/ t" ]+ x- h2 s, Y3 y
  3. CONFIG_ADC=y% J, B$ b+ o' _6 C1 E/ e& [
  4. CONFIG_INPUT=y& P& v* C+ F- K1 f
  5. CONFIG_I2C=y! ^  E( l7 ?' T# B
复制代码
板级 CONFIG_FPU=y + CONFIG_FPU_SHARING=y(BSP 里已开,调压计算用浮点)。
& m* x$ U' J4 K' E' Q& R" R. y9 |0 \0 B7.2 设备树 overlay(boards/nucleo_h5e5zj.overlay,节选)
/ ]9 `) P$ @4 u
  1. /* MP4248:Arduino I2C(D15=SCL=PF5 / D14=SDA=PG6),从机地址 0x67 */1 D( B% i* _4 T, I, n' \) R
  2. &i2c4 {
    4 [2 w9 d% g# p$ p8 T
  3.         pinctrl-0 = <&i2c4_scl_pf5 &i2c4_sda_pg6>;
    " x1 r5 h$ z3 Y+ P
  4.         clock-frequency = <I2C_BITRATE_FAST>;   /* 400kHz(MP4248 最高 1MHz) */
    . E, y7 U- H" j9 S- d+ O, ?
  5.         status = "okay";
    8 Q# j% ?- N1 [! w+ @* ]. n. V4 g0 e
  6. };
    8 P& n/ Z4 x7 x& ~% E

  7. : _9 W$ `& Q5 k/ F% m" D
  8. /* 摇杆:adc-keys 输入驱动(电阻分压式五向摇杆,阈值实测校准) */
    4 P( R3 p' s6 d& J+ O7 T/ D0 f/ v4 Z
  9. joystick: joystick {
    , R/ |. w+ h# p
  10.         compatible = "adc-keys";9 k# [9 j$ b+ j0 q
  11.         io-channels = <&adc1 9>;
    2 y* ]- M% e  l3 T* f2 p8 J
  12.         sample-period-ms = <50>;
    " G, w. E2 e/ |2 T
  13.         keyup-threshold-mv = <3300>;
    0 K, W. D( L2 c
  14.         key_up     { press-thresholds-mv = <595>;  zephyr,code = <INPUT_KEY_UP>; };  d+ k/ b; X% I, s
  15.         /* ... 其余方向同理 ... */5 T( N' N% E* Q# o  a
  16. };7 l' K+ {" I# O1 C  v

  17. 2 d3 B: o' v  v' d: J
  18. /* ADC 通道:IMON=PC2(INP12)、VOUT 分压=PC3(INP13)
    5 @, n7 p; w3 v3 Z& e
  19. * ⚠️ 通道号 ≥10 时子节点名必须写十六进制(unit address 按 hex 解析),+ v5 i1 b) q" h) v& ~& B
  20. * channel@12 会被当成 0x12=18 号!写成 channel@c 才对。 */4 @) P. b: H3 T; \
  21. &adc1 {, [' O1 x3 M' u! Q, f7 }
  22.         pinctrl-0 = <&adc1_inp9_pb0 &adc1_inp12_pc2 &adc1_inp13_pc3>;
    % b' a" x- n4 \  X. I! g7 J& }
  23.         /* ... *// h9 e& ]- d- O) Z* ]0 G& ?* N3 j
  24.         channel@c { reg = <12>; /* IMON */ };
    2 j8 ~* m, t# X5 @0 v! l
  25.         channel@d { reg = <13>; /* VOUT */ };
    " q+ e* G9 O) w. m% L$ ~3 |5 ^
  26. };
复制代码
7.3 MP4248 驱动核心(src/mp4248.c)
9 b% E. p1 e2 c  M& z
  1. /* V = ceil(VOUT × 1024 × 10 / FB_RATIO),手册要求非整数向上取整 */
    $ S8 e; m( f/ k
  2. int mp4248_set_vout(float vout_v)
    5 A+ j3 v3 R+ h4 V
  3. {
    5 D# ^) A: B3 i5 A# i( y+ A
  4.         uint16_t reg = (uint16_t)ceilf(vout_v * 1024.0f * 10.0f / MP4248_FB_RATIO);, ^4 y6 J- P5 M$ a
  5.         uint8_t buf[3] = { MP4248_CMD_VOUT, (uint8_t)(reg & 0xFF), (uint8_t)(reg >> 8) };" W' G, T# `! A- E

  6. 2 Y0 d/ T$ \' ^: s3 ?
  7.         return i2c_write(i2c_dev, buf, sizeof(buf), MP4248_ADDR);
    / s9 g  @0 p( ~% U" F# r5 I
  8. }. y: v; F$ w7 h/ @% _# }
  9. 6 y- E" X8 Q  p( f
  10. /* IOUT_OC(A) = IOUT_LIM × 0.05,读改写保留 bit7(LDC_DISABLE) */
    7 c6 {/ Y6 O0 w
  11. int mp4248_set_ilimit(float amps)5 I2 J8 ^9 U6 w& t1 p
  12. {$ Q+ h0 o9 V" A1 z1 J+ |3 B+ ?) p% s
  13.         /* ...钳位 0.05~5.4A... */. _9 D5 I9 t2 l5 C8 ]9 P0 e3 R
  14.         uint8_t reg = (uint8_t)(amps / 0.05f + 0.5f);* V" S( P$ a& |: _5 J( f; E
  15.         uint8_t buf[2] = { MP4248_CMD_ILIMIT, (uint8_t)((cur & 0x80) | reg) };
    ; K4 w+ h) M( Q  _! d: o( h
  16.         /* ... */3 B: h) Y. d6 ^& h: `
  17. }
复制代码
7.4 实测反馈回路(src/main.c)
5 z, Y, T) S6 M
  1. /*
    + p# d: Z; [3 u8 r6 t0 i
  2. * dps —— NUCLEO-H5E5ZJ 数字电源(M2:调压 + 限流 + 故障状态显示)1 V4 f. ]) ~7 V' f1 f7 [$ K: V
  3. *! F1 D" o0 ^* @) ?, g' K
  4. * 操作:摇杆左/右 = 切换编辑项(SET 电压 / ILIM 限流);上/下 = 调整
    & n7 R  m' Q. \# d" v* X; [4 p$ R* y
  5. *       (电压 0.1V 步进,限流 0.1A 步进);按下 = 输出开/关。% F1 L4 s, ~, `
  6. * 显示:lcd_bare 文本(不用 LVGL)。
    $ J6 Z9 }. C5 T! i  Y
  7. *8 j" i0 N* Z% G& d5 e
  8. * 硬件:EVL4248-QV-00A(MP4248,I2C 地址 0x67)- X7 X* g! L/ Y
  9. *   CN2 SCL → Arduino D15(PF5)   CN2 SDA → Arduino D14(PG6)   CN2 GND → GND, w" \. y* }- k2 r3 B) n: R
  10. *   注意:评估板须先接 VIN(I2C 在 VIN+EN 都有效时才工作);
    4 n# g9 g/ W4 L8 [; V
  11. *         上电芯片自动输出约 5V(OTP 行为,软件拦不住),负载侧请自行断电管理。
    ( h$ P1 r! t, I, ^5 m3 K* T3 K
  12. *
    . e1 l. }; u, M" U8 I( o  G
  13. * SPDX-License-Identifier: Apache-2.0
    / x6 M3 J& x' c1 f
  14. */- S! s( e8 j+ x% x. Z/ r3 F# @

  15. - ^/ ~7 f% O" y* _
  16. #include <stdarg.h>
    3 g8 u5 r7 `% ^1 U
  17. #include <stdio.h>. P/ n. I( V9 O$ a
  18. #include <string.h>
    / A8 }7 u! L2 ?6 a$ I
  19. $ a$ ~3 E5 T9 N7 O7 Z. @
  20. #include <zephyr/kernel.h>: J, m6 i: c% l7 {0 F4 |! l
  21. #include <zephyr/drivers/adc.h># s1 E# d& U3 ?  V8 [
  22. #include <zephyr/input/input.h># \. F. L3 x( i
  23. #include <zephyr/sys/printk.h>  i7 k& v. _: ], g
  24. 6 p0 i! h% }1 @$ r' K6 Q
  25. #include "lcd_bare.h"
    / A7 Y. k: o  ~: d; T& R
  26. #include "mp4248.h"9 O2 S0 Q" ~; ?7 F: _

  27. ! d# T% U' J7 b6 u; d0 K* L
  28. static float set_volt = 5.0f;        /* 目标电压(0.1V 步进) */+ z1 G! e* P+ k& @
  29. static float set_ilim = 5.4f;        /* 目标限流(0.1A 步进,≤5.4A) */
    - w' A7 Z3 O% k$ [$ }, {* U
  30. static float rb_ilim;                /* 限流读回值(验证写入生效) */
    ' Z* `0 x, }- R" ]$ A" g# U/ P
  31. static int edit_target;                /* 0=电压 1=限流 */5 o1 L4 B5 P; o; g
  32. static bool output_on;. _4 i& m& g3 a. S! V
  33. static bool mp4248_online;
    + t# ^6 J8 y% t) B0 l9 o
  34. static bool ui_dirty = true;
    ' t1 x* ?$ ]; F& d1 q% A
  35. static uint16_t status_word;
    6 n( c" i9 m7 c. L0 g

  36. $ O7 l0 P' i. ]9 I. u4 O" [- O
  37. /* 摇杆按键事件(adc-keys 驱动,输入子系统回调) */
    3 S. A1 a: \4 p* Z& N$ F- S% J
  38. static volatile int pending_key;* j1 h7 t# O$ m( w" @
  39. $ D2 U! W% s" X6 Q- |; l( m) L
  40. /* IMON 电流反馈:EVL4248 IMON 脚 → PC2(ADC1_INP12),IOUT = V_IMON / 0.34 */5 `% w' Q" B8 a& n) Y7 O
  41. static const struct adc_dt_spec imon_adc =* ?: T  U# ]  P
  42.         ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 0);
    ; S' a7 z# s2 P% Y
  43. /* VOUT 分压(101.1k/5.05k)→ PC3(ADC1_INP13),VOUT = V_ADC × VOUT_DIV_RATIO */6 v+ S9 G8 f/ }/ y
  44. #define VOUT_DIV_RATIO        ((101.1f + 5.05f) / 5.05f)
    % W+ J- }0 ?3 K) ]' L
  45. static const struct adc_dt_spec vout_adc =8 ^7 O4 T& Z1 t6 N
  46.         ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 1);# D3 w4 @* D' c4 y
  47. static float iout_amps;# ?* T. w$ ?* b' u
  48. static float vout_volts;        /* VOUT 实测值 */: n% y, w7 @% J3 q
  49. static int16_t imon_raw = -1;        /* 调试:ADC 原始值(-1=读失败) */
    3 ?5 y# ]' F" r$ I+ z
  50. 7 h: `* a* F" f  J! Q
  51. static void joy_cb(struct input_event *evt, void *user_data)% s2 M9 \; Z! [9 F
  52. {
    ' B/ n  g- E5 _, B. l3 m8 ?5 X5 V
  53.         ARG_UNUSED(user_data);
    - v* Y, Y1 w4 Y  S
  54.         if (evt->value) {        /* 只处理按下 */( i8 P. ~  }1 {9 O' `4 h) m
  55.                 pending_key = evt->code;
    / y  [: w+ G- [" O  ?; d
  56.         }, H# k$ X& E: Z# C2 G3 g0 H
  57. }, u/ \; s  Y! `" R5 J
  58. INPUT_CALLBACK_DEFINE(NULL, joy_cb, NULL);
    ! M, N) ~8 J& K: W- Y. M
  59.   M2 C8 [$ Z1 a1 H9 W" x5 @# ~/ a
  60. /* 每行补空格到满宽(20 列),行内覆盖刷新,不再整屏清屏 */
    * Y2 w5 l( E3 t; Y" B
  61. /* 读一路 ADC 并转为 mV,失败返回负 errno */
    7 G; N3 K5 ~6 ^' j3 }1 S
  62. static int adc_read_mv(const struct adc_dt_spec *spec, int32_t *mv_out)4 v. b( |- K+ e
  63. {  w" k: r3 U) N: I- w; R; d( t1 c
  64.         int16_t raw;
    $ y# _2 H9 K3 Y8 u+ d/ |: n' q( ]
  65.         struct adc_sequence seq = {0};
    8 m. R) `1 R- T+ v# n) F4 n
  66.         int ret = adc_sequence_init_dt(spec, &seq);! e0 Z" A, b% D. l9 `  l4 C8 @
  67.   R+ D3 O8 o# T1 `% P# x$ e& q- }% |/ ^
  68.         if (ret != 0) {+ S% @( m. u6 z) t2 `7 p
  69.                 return ret;
    ( Y4 z- ~+ ?$ s
  70.         }
    ( {1 c/ C0 L# E# ]5 S
  71.         seq.buffer = &raw;9 S8 O( G5 O4 v5 t' h; t
  72.         seq.buffer_size = sizeof(raw);" F  {0 c! Z6 e* z
  73.         ret = adc_read_dt(spec, &seq);
    # ~5 V5 h: M9 y" R1 a( o' t
  74.         if (ret == 0) {
    , I1 I5 u( g' S+ G! I
  75.                 int32_t mv = raw;
    5 I5 _7 Y& l/ f# _# U
  76. 0 H6 ?; o/ X6 _5 E3 ~
  77.                 ret = adc_raw_to_millivolts_dt(spec, &mv);* P( J- r  K' |% L
  78.                 if (ret == 0) {- k$ N- ?1 e& Q2 E0 X3 a
  79.                         *mv_out = mv;
    . J2 A1 u, o3 r5 q* _
  80.                 }
    0 k( u1 u2 s# G  [
  81.         }
    3 J6 X- X) M5 [! d- g5 K3 V* G
  82.         return ret;1 C# t# V* R+ K( l
  83. }/ c9 z2 Y& c- e, i7 X4 ^) |
  84. % K$ W. }( Z! h  h: u
  85. static void ui_line(uint8_t row, uint16_t fg, const char *fmt, ...)3 g2 O8 a) A5 S4 p5 W3 |
  86. {
    : e% R* I1 o. A' s$ W2 a* R
  87.         char line[24];$ V, l/ H! x. E
  88.         va_list ap;
    / o4 {' @: ~' D& E
  89. " i: u  y$ N, L
  90.         va_start(ap, fmt);3 h4 I8 Q0 b# B+ |+ U! n1 R
  91.         vsnprintf(line, sizeof(line), fmt, ap);
    0 `, k7 c' @( X7 _
  92.         va_end(ap);
    3 @" n( i2 A/ V
  93.         size_t n = strlen(line);
    ; Z/ k! v' s0 [1 X: E
  94. ( R$ c& w* y' r9 B( ]
  95.         while (n < 20) {
    ; b' }. q9 S7 Y, K( ~7 O
  96.                 line[n++] = ' ';) ^' `- |; l5 m: q( h" @1 ]  B2 |! n
  97.         }# ]  G7 ~2 W- W. Q: ]/ q" n
  98.         line[n] = '\0';% p. [! q5 g2 }" u) }
  99.         lcd_bare_text(0, row * 8, line, fg, LCD_BLACK);1 o# n' Q7 n7 c/ F7 H, y( i2 x
  100. }
    7 L- a' ?0 f+ K& K

  101. ! ]7 T; w; L) Z2 \8 m3 B
  102. static void ui_redraw(void)
    0 r, v9 c0 |) A! n
  103. {! i# K6 g1 Y# a) h; h" _
  104.         float rb;4 m# r4 [# o) }
  105.         uint16_t st = status_word;; z2 q# A; \* T# J$ N

  106. % g6 b) I- I) }! t. _+ }; Y) V6 A
  107.         ui_line(0, LCD_WHITE, "DPS MP4248  I2C:%s", mp4248_online ? "OK" : "ERR");7 |/ B7 o4 y8 g7 s/ a! e
  108.         ui_line(1, LCD_BLUE, "--------------------");0 D  P; m  s4 M1 j8 Z7 G
  109. 8 n: _6 E2 e7 e
  110.         ui_line(3, LCD_YELLOW, "%cSET: %5.2f V", edit_target == 0 ? '>' : ' ',
    ) D; U1 S& ?( p( O3 P- D5 Z
  111.                 (double)set_volt);" e% x. Q& S$ R) j8 s' |9 h8 W2 n
  112.         ui_line(5, LCD_YELLOW, "%cILIM:%4.2f/%4.2fA", edit_target == 1 ? '>' : ' ',# M( @3 E) H& `+ }
  113.                 (double)set_ilim, (double)rb_ilim);" V+ V' R8 |, \1 g- R) `

  114.   w% N( {8 [0 I! Z3 P+ o
  115.         if (mp4248_get_vout(&rb) == 0) {
    , h' X0 o9 G/ G0 z; m
  116.                 ui_line(7, LCD_GREEN, "VCMD: %5.2f V", (double)rb);0 b; b$ e. c! m! X( w1 a* ~
  117.         } else {$ \; R' r5 j( D9 Y
  118.                 ui_line(7, LCD_RED, "VCMD: --.-- V");" S% A* C! q6 M0 H/ n
  119.         }
    5 y) p/ q/ K* t& |) U
  120. 1 M/ {/ T$ `3 a8 v! Z
  121.         ui_line(8, LCD_GREEN, "VOUT:%5.2f V", (double)vout_volts);4 D4 K1 P3 U% d2 S/ x" a: V* C" A, ^
  122.         ui_line(9, LCD_GREEN, "IOUT:%5.2f A", (double)iout_amps);% B5 |. b* d  E2 {2 X$ {  x+ }

  123. $ H$ N/ D* T: d8 b
  124.         ui_line(11, output_on ? LCD_GREEN : LCD_RED, "OUT:%s ST:%04X",
    2 L3 Y6 X. x, I. k: {- S% C
  125.                 output_on ? "ON " : "OFF", st);- G7 V; r- |6 ]7 s) E& f
  126. ; c4 W- u# c) C* o
  127.         ui_line(13, LCD_WHITE, "LR:item UD:adj OK:out");
    " I/ _5 D7 ?' i
  128.         ui_dirty = false;' L! m3 t2 m0 ?1 \0 a4 ~: C
  129. }
    " A7 |" g( j. W% Z4 V

  130. 6 `8 h( c7 k& x
  131. int main(void)# _* f3 d, |- ^, }+ R$ G5 g
  132. {
    : B) ^$ l. R8 I6 I
  133.         printk("dps: NUCLEO-H5E5ZJ digital power supply (M2)\n");
    - e0 f1 ]0 r" s) \3 z2 T5 `
  134. 8 x, y/ I# `3 t7 C. V
  135.         if (lcd_bare_init() != 0) {7 V/ X& `+ t* w6 Z% @2 F
  136.                 printk("dps: lcd init failed\n");
    / R' o0 i: c: D
  137.         }# X% a- w7 p" B' T! B& O
  138.         lcd_bare_fill(LCD_BLACK);        /* 只在开机整屏清一次,之后按行覆盖刷新 */
    2 h+ g6 m' p4 A% x$ I& z
  139.         if (mp4248_init() == 0) {5 j: ^1 M! n. H4 A% |0 g& l& `2 o
  140.                 mp4248_online = (mp4248_probe() == 0);
    - C1 U/ R% F$ `* |/ N' ]7 m
  141.                 if (mp4248_online) {
    ; Y/ v' Q- D( s  o  {* X1 E' |
  142.                         mp4248_get_ilimit(&set_ilim);        /* 读回芯片当前限流作为初值 */
    , _! L; t! A! i0 A. G: g
  143.                 }
    4 h% ~0 t9 }8 B; b
  144.         }4 {- R9 N0 d( t* K* }* w
  145.         printk("dps: mp4248 %s\n", mp4248_online ? "online" : "NOT FOUND");( A: M- p, w# `) Y

  146. + B8 k9 V) Q, ]$ N
  147.         if (adc_is_ready_dt(&imon_adc) && adc_is_ready_dt(&vout_adc)) {, e- s3 x8 Y9 R1 F
  148.                 int rc1 = adc_channel_setup_dt(&imon_adc);( }/ G+ D' `3 T+ z7 N
  149.                 int rc2 = adc_channel_setup_dt(&vout_adc);
    " ]4 Q; @/ o) n" _& J' W8 C6 i' Y
  150. 3 D1 v+ @3 W/ N6 ~! D7 k2 r
  151.                 printk("dps: adc setup imon=%d vout=%d\n", rc1, rc2);
    # A; F' \' Y7 D
  152.         } else {
    ' D) o8 U' W1 @! s+ \
  153.                 printk("dps: adc not ready\n");
    6 m( D) z- H. Q
  154.         }0 z% l+ C7 |/ ]: m# g
  155. 2 ?% b- s* J" t
  156.         uint32_t last_poll = 0;
    0 F4 v( c5 b- H# R. L2 ?

  157. 4 I0 B, Z7 k: ]6 ^6 R
  158.         while (1) {
    6 j& Q  r) x- g5 o! Y+ }
  159.                 int key = pending_key;
    9 l4 Z/ \2 M* n# k

  160. ) O$ [# H8 V- z' O2 ]4 \2 t
  161.                 pending_key = 0;
    2 n+ P" d0 Y& [) v
  162.                 switch (key) {
    : Y) [+ }9 w+ r3 G0 D' c
  163.                 case INPUT_KEY_LEFT:* s; D/ Q2 y, A" g4 E
  164.                 case INPUT_KEY_RIGHT:
    5 S! D1 p- e0 z+ v
  165.                         edit_target ^= 1;        /* 电压 <-> 限流 */( I/ |: o$ O% ]1 j  a
  166.                         break;
    ' d) ^% T: w5 J. v
  167.                 case INPUT_KEY_UP:" N! J8 z1 E0 z) }% B
  168.                         if (edit_target == 0) {, ~* Q/ d1 p" C! h8 \( m
  169.                                 set_volt += 0.1f;6 T( G: e" z; d- e2 J
  170.                                 if (set_volt > MP4248_VOUT_MAX) {6 I4 d! W  p# G: \* b6 n" C
  171.                                         set_volt = MP4248_VOUT_MAX;
    1 [! O/ u7 b; ?: V+ ?4 u
  172.                                 }5 ]' ]' w# x0 Q( _4 l9 P
  173.                                 if (mp4248_set_vout(set_volt) != 0) {( `+ F, Q  k* J2 _4 A
  174.                                         mp4248_online = false;
    % }( Z' e1 b& y6 C6 ]- L! I
  175.                                 }$ y, C1 u7 e5 n( H: I$ Q" S* `9 B
  176.                         } else {; ^* ~- Y. b+ V9 N  n( x
  177.                                 set_ilim += 0.1f;0 O* O9 b7 L9 o5 u6 H/ S8 X3 ]
  178.                                 if (set_ilim > 5.4f) {* l- ~+ p3 _8 x
  179.                                         set_ilim = 5.4f;: [7 X& F8 D& \2 u
  180.                                 }. h$ Y8 Q( N3 t+ J; T( r
  181.                                 if (mp4248_set_ilimit(set_ilim) != 0) {
    % D$ z0 ~  u8 L. J, Z
  182.                                         mp4248_online = false;. O" ^: ~0 r" M; t4 E# i
  183.                                 }
    # s. w- J& ?. e! J% B( T
  184.                         }
    % P  E1 R7 c/ g2 t$ q' L
  185.                         break;
    ) X  Z+ m! |: F# `4 e
  186.                 case INPUT_KEY_DOWN:( [$ W4 p3 J# Q
  187.                         if (edit_target == 0) {
    ! y+ R0 _, ]; `8 e8 c8 R
  188.                                 set_volt -= 0.1f;  x2 T5 C* ]; z3 H
  189.                                 if (set_volt < MP4248_VOUT_MIN) {) Z6 `/ n! F" w3 V; x# F6 B
  190.                                         set_volt = MP4248_VOUT_MIN;
    1 p+ u; A1 O! z0 @* X$ L
  191.                                 }
    9 Z2 o1 b. A6 k, G8 `' z+ ]7 C
  192.                                 if (mp4248_set_vout(set_volt) != 0) {8 q1 u+ V( k3 U- z, a0 K2 T
  193.                                         mp4248_online = false;+ {$ a4 B$ ~' j, x
  194.                                 }4 B% E& H; P: V% z: w2 s8 [  j
  195.                         } else {; Y0 h% E3 v4 _  n, L
  196.                                 set_ilim -= 0.1f;6 q. V( s3 u" Z9 ~7 ^) M$ e. b: O
  197.                                 if (set_ilim < 0.5f) {9 t  d" `0 B5 [- L, Y1 x
  198.                                         set_ilim = 0.5f;% x& _* q- B% S$ X! B0 i" Z. J5 |& @
  199.                                 }
    " Z& ^# s6 f" p: J% I! g  _2 d/ h8 T
  200.                                 if (mp4248_set_ilimit(set_ilim) != 0) {9 g/ }, L  \9 D. ~! X4 L
  201.                                         mp4248_online = false;) ^: [& m. ~" x+ |/ C
  202.                                 }
    5 `, r1 ^% b( `2 g; z
  203.                         }
    8 m* Z( _3 U3 N' e1 h2 N/ ]% h
  204.                         break;
    8 c( b- g# D8 B5 _6 q. b
  205.                 case INPUT_KEY_ENTER:
    ! Q: `( h- c+ q' R7 \1 _
  206.                         output_on = !output_on;7 v( x7 X4 R  j" P$ z7 W4 B
  207.                         if (output_on) {. |) r( V" `, t
  208.                                 /* 开输出前清掉历史故障锁存(PMBus 状态位需 CLEAR_FAULTS 才复位) */
    ; u* z" {- H, n9 Y5 ^7 d, h
  209.                                 (void)mp4248_clear_faults();
    ) g# }8 ?/ s) q0 D5 S: h
  210.                         }% ?" D) u5 I0 V5 w" `
  211.                         if (mp4248_output(output_on) != 0) {, i( ]6 n2 y0 t0 s& b
  212.                                 mp4248_online = false;% B! k" C8 C$ r8 g
  213.                         }$ [5 ~2 I) c, A  c1 o
  214.                         printk("dps: output %s\n", output_on ? "ON" : "OFF");* _9 r; U8 |. V: _' d. ^7 Y
  215.                         break;, b8 F- O% D7 t/ C5 j
  216.                 default:4 K9 m3 P& h8 C7 j1 C7 w; W$ t
  217.                         break;, s. ^, x& I. }/ D
  218.                 }! P, |5 ?, W3 ]

  219. + P, _" p) ?1 y* g& p! k
  220.                 if (key != 0) {
    . o! E8 G& }- _
  221.                         ui_dirty = true;5 k: d2 e" d* n( v6 A2 P# S
  222.                 }
    & I$ y- Y! M! n1 V: t4 {8 ?
  223. 8 m# l( t9 X4 a. M% ~; V2 F# a7 }
  224.                 /* 500ms 轮询读回电压 + 限流读回 + 状态字 + IMON + VOUT 实测 */
    6 i$ a( S: o* G  a
  225.                 if (k_uptime_get_32() - last_poll > 500) {' C, G/ g* n2 s+ K$ d% y
  226.                         last_poll = k_uptime_get_32();
    8 m, ^2 i# ^( e( h1 c2 y* `. x" K
  227.                         if (!mp4248_online) {# a& A) ]/ u5 M: }, r
  228.                                 /* 离线时每 2 秒重试 probe(评估板后上电/接线恢复也能上线) */4 W. m) M; z7 y- [$ P
  229.                                 static uint32_t last_probe;6 @  K$ B, v! W0 v! e$ g
  230. + X+ R4 k) R: W0 X: [- ~
  231.                                 if (k_uptime_get_32() - last_probe > 2000) {
    1 ?9 ]5 q7 ^; W% B5 p7 {: }3 W  _
  232.                                         last_probe = k_uptime_get_32();
    / I) b  ~9 z7 T6 S. E$ X
  233.                                         if (mp4248_probe() == 0) {
    0 L) W  A* H8 \$ a* [
  234.                                                 mp4248_online = true;
    $ D6 F# R) _/ z
  235.                                                 mp4248_get_ilimit(&set_ilim);
    ; ?7 A7 m: Y9 q$ e1 m
  236.                                                 printk("dps: mp4248 back online\n");
    / `/ Z8 F2 d8 Y  t5 e
  237.                                         }
    . m# \& C0 F( g) T0 V% m
  238.                                 }
    ( [' ?, ^# A4 |8 G
  239.                         } else {6 U) S" A7 W6 K. X4 {( G1 j
  240.                                 (void)mp4248_status_word(&status_word);5 L. g' a; m0 {9 u* N
  241.                                 (void)mp4248_get_ilimit(&rb_ilim);
    9 V) i1 F. L) h- W" u
  242.                         }
      o, K1 N  l- t1 q
  243.                         /* IMON:IOUT = V_IMON / 0.34(5mΩ×68V/V) */( q8 }% ^9 U. q8 j- h7 Q. _2 s  v
  244.                         int32_t mv;1 w, I1 t& O  R, v8 q+ k9 F) Z, Q- u* ~
  245.                         int rr = adc_read_mv(&imon_adc, &mv);, G6 @2 K; R3 b3 d

  246. ) l1 A( x1 x8 k( J8 O6 H# L5 b
  247.                         if (rr == 0) {( l% S" q+ }9 F) N3 V+ l# W/ T! V
  248.                                 imon_raw = (int16_t)(mv * 4096 / 3300);
    4 Z; T% _2 K$ c& Y( j9 ?: B
  249.                                 iout_amps = (float)mv / 1000.0f / 0.34f;
    0 f. Q+ h, E( z, R
  250.                         } else {
    6 A& ~( n5 E% C* ~% f* U" r
  251.                                 imon_raw = (int16_t)rr;        /* 负 errno 直接上屏 */
    ! i1 m) p/ H9 }$ l2 L  j
  252.                                 printk("dps: adc read err %d\n", rr);- |* l) y- f' ]: b/ x
  253.                         }* J# F, d; u5 `% ], K5 \$ Y" C
  254.                         /* VOUT 分压:VOUT = V_ADC × VOUT_DIV_RATIO */
    , u# _0 r. s0 b* F0 n. G% e* P
  255.                         if (adc_read_mv(&vout_adc, &mv) == 0) {
    / x6 |& F4 H  c3 ]
  256.                                 vout_volts = (float)mv / 1000.0f * VOUT_DIV_RATIO;
    6 H: b% ^; j- `* A
  257.                         }
    # X- \: b4 j2 [8 C
  258.                         ui_dirty = true;7 c" @3 ~9 E- E0 C
  259.                 }/ ^6 V; i; q3 o9 L/ r! R
  260.                 if (ui_dirty) {& x& t( w1 }" F$ r
  261.                         ui_redraw();% F' d4 d6 w# l$ Y, J2 e
  262.                 }
    + E9 @5 w) o: }3 ]
  263.                 k_msleep(50);# H6 N& o2 p0 J
  264.         }
    ! _# M( A7 I& `& g" ~
  265.         return 0;0 h7 ~- e' i4 k/ a: Q% l/ Q
  266. }
    % I6 N0 a$ F7 ^( Y) S: s* _
复制代码
八、项目展示  C8 b( d3 ?# |; }1 `9 W6 b& l
数字电源整体项目.jpg 3 G8 Q7 @4 {$ E0 N% @) q, C
通过按键可以实时调节输出电压、电流限值等。0 X2 s' G: y# |" Z# F
2 x& i, C$ v) q) y3 {6 V- e

$ ?' `* S+ V( {7 ]* Q* s
3 n4 x+ B" o" f% h/ F
8 @" |( ~' y  d. Q/ a% {: ]8 [
; A" O# k5 r$ a6 p* g$ w
( Y3 p* ^) j! a9 Q' j
赞 收藏 评论0 发布时间:2026-10-18 11:31

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版