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

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

[复制链接]
lugl 发布时间:2026-10-18 11:31
前面几篇的试用文章我驱动了lcd屏,spi等外设,这一篇我将分享Zephyr来实现一个数字电源,用到的是EVL4248-QV-00A评估板,通过I2C与ADC来实现。
& Z0 H+ X# Q1 y1 p
# P4 Y% Z2 d: q! p3 O- S6 {0 j! d) j% ]0 {3 U3 u# n( q
一、EVL4248-QV-00A 评估板简介9 l0 W: m8 x' `* A
EVL4248-QV-00A 是 MPS 的数字电源评估板,核心是一片 MP4248GQV:四开关 Buck-Boost 变换器 + I2C(PMBus)数字接口。 ScreenShot_2026-10-18_111706_057.png
7 `0 ~( G/ G4 J/ X  O  o9 [9 h# J1 D, \7 k
evl4248参数介绍.png + M* y3 F- \; e  ?# Z
二、控制引脚与反馈引脚8 R2 T6 _) ^; v6 Z% ~% G
控制引脚.png 3 X7 h& o$ W7 e4 R
I2C 关键寄存器(PMBus):
1 d  M, h$ f% Y# Y 数据电源寄存器.png
8 `' I* r- R4 d) b4 h! i三、与开发板的接法
, X) o& [% r5 y3 J: k1 k: O! R 开发板与ev4248接法.png
( p  M9 }# J  x3 c) N! \8 ^四、系统框图
* }+ _* W- Y" U) N  B dps_block_diagram.png ' @/ Q+ G) x1 [3 [$ K6 \, ~1 h
2 K7 ~2 x+ U. V" S' z) M5 ?
功率通路:直流输入 → EVL4248(MP4248 升降压)→ 输出端子 → 负载。
. ?# Z, m' L7 o: G# |7 h3 S' A控制/反馈通路:I2C4 下发调压限流;IMON(电流)与 VOUT 分压(电压)进 ADC 实测回读;摇杆+LCD 做人机交互。3 @9 D% W9 k0 j8 i. o7 j. {
界面用 lcd_bare 裸驱动文本渲染(不用 LVGL,轻量直接),160×128 屏按行组织,按行覆盖刷新(无整屏闪烁):% x$ W  D+ O# C' `6 X
数字电源.jpg + A% J$ c1 @1 g5 P4 `& V
六、系统控制逻辑
( g2 }; L; g3 [# i 数字电源控制逻辑.png
0 X" X1 `0 T. U+ l! V0 A" {" }8 T8 F5 f; x" Q
设计要点:& f; `3 l% k2 k
• 写后即读:SET/ILIM 行显示"设定值/读回值",写没生效一眼看出;
. K* o  _, B- h! U• 故障锁存语义:PMBus 状态位锁存,CLEAR_FAULTS 在开输出时自动发——历史故障与当前状态分离;2 N" ]; h* J3 \* F
• CC 是调节不是故障:进恒流时芯片降压维持电流,VOUT 实测会掉,ST 记录 OC 事件,这些都如实上屏。
  N! H& M! ]3 x6 g. m# [七、Zephyr 主要代码5 O+ b7 Q* r' Z$ X% ^- M6 |1 }" v
7.1 prj.conf6 c9 \+ R/ ?% W7 h2 d8 Q! p3 \
  1. CONFIG_GPIO=y$ @; P& |! G8 D& R+ E# z! r
  2. CONFIG_SPI=y0 Q; i0 G( W1 C* Y' {& a- ]# X
  3. CONFIG_ADC=y* t3 G( t8 w2 _& n8 z. m3 W5 o
  4. CONFIG_INPUT=y
    . E  w9 ]- J* f0 W+ _4 N
  5. CONFIG_I2C=y
    # t; e& n2 @5 ]: f- o6 B
复制代码
板级 CONFIG_FPU=y + CONFIG_FPU_SHARING=y(BSP 里已开,调压计算用浮点)。$ v9 @( v2 f4 ~# D* C0 l
7.2 设备树 overlay(boards/nucleo_h5e5zj.overlay,节选)
2 I9 W+ c3 s5 C, I4 _  a
  1. /* MP4248:Arduino I2C(D15=SCL=PF5 / D14=SDA=PG6),从机地址 0x67 */. e  u( X9 \& Y. q; J" n6 E& q
  2. &i2c4 {
    ' u7 e1 j- J" a8 y3 o
  3.         pinctrl-0 = <&i2c4_scl_pf5 &i2c4_sda_pg6>;+ }" t3 ]3 ]" U& c+ ?
  4.         clock-frequency = <I2C_BITRATE_FAST>;   /* 400kHz(MP4248 最高 1MHz) */
    $ v2 K' P6 r- e- Z4 o6 \8 M
  5.         status = "okay";
    6 c2 {7 l/ f1 m! g# \
  6. };1 ~1 w4 S3 S  F3 K" e

  7. 6 J# B0 g8 T6 d0 I
  8. /* 摇杆:adc-keys 输入驱动(电阻分压式五向摇杆,阈值实测校准) */5 ]& m- @! X- L7 M( @7 L: ~
  9. joystick: joystick {4 Q6 B6 @3 `" J" o$ t/ j* `% C
  10.         compatible = "adc-keys";
    8 x$ G1 D, S) y9 j$ P9 V4 [
  11.         io-channels = <&adc1 9>;
    9 J% J! F% ^) f, F/ Y" C0 T# j
  12.         sample-period-ms = <50>;
    7 w' [& L& n- M8 o5 ]* j) i
  13.         keyup-threshold-mv = <3300>;
    ; Z( V7 D1 X& D+ f) g% M+ o0 J
  14.         key_up     { press-thresholds-mv = <595>;  zephyr,code = <INPUT_KEY_UP>; };
    9 Q: x. q$ H2 P# r! b. m6 D
  15.         /* ... 其余方向同理 ... */
    $ u+ t- b. e2 z6 ?8 K
  16. };
    9 s9 O7 f9 F' J) L( N8 j( z6 ]# U

  17. 4 m9 `) w8 k% M) J% Y+ D
  18. /* ADC 通道:IMON=PC2(INP12)、VOUT 分压=PC3(INP13)
    & ]8 S8 Q  X6 |/ N2 S+ @/ b
  19. * ⚠️ 通道号 ≥10 时子节点名必须写十六进制(unit address 按 hex 解析),6 L. s2 b9 ^, D' ~; j$ c" m
  20. * channel@12 会被当成 0x12=18 号!写成 channel@c 才对。 */& Y4 b* u: R, r! D5 x# Y
  21. &adc1 {3 j1 Q" H. t# ]1 U' ~7 ]
  22.         pinctrl-0 = <&adc1_inp9_pb0 &adc1_inp12_pc2 &adc1_inp13_pc3>;
    6 B" W1 ]3 w4 Z9 \; Y' q/ q
  23.         /* ... */
    7 `( Z1 S2 O# o; b7 G5 D
  24.         channel@c { reg = <12>; /* IMON */ };
    1 B9 C! e. Y) r) L
  25.         channel@d { reg = <13>; /* VOUT */ };
    : f/ O. W! a: T
  26. };
复制代码
7.3 MP4248 驱动核心(src/mp4248.c)
& C6 q, w! `+ e, }. z  h( i
  1. /* V = ceil(VOUT × 1024 × 10 / FB_RATIO),手册要求非整数向上取整 */4 l) e8 Z3 T. n8 e4 [8 O! ?
  2. int mp4248_set_vout(float vout_v)
      @& K6 V6 j! G# v
  3. {6 h+ s  n1 O. W# a) u1 ]( Z1 q! `
  4.         uint16_t reg = (uint16_t)ceilf(vout_v * 1024.0f * 10.0f / MP4248_FB_RATIO);
    : O) H1 ^! L5 [3 z/ ?
  5.         uint8_t buf[3] = { MP4248_CMD_VOUT, (uint8_t)(reg & 0xFF), (uint8_t)(reg >> 8) };+ j4 C; [, P& F0 c
  6. 7 q+ r/ z: a0 m3 H5 R# e9 y( M
  7.         return i2c_write(i2c_dev, buf, sizeof(buf), MP4248_ADDR);9 z; @3 S# @, z5 Z
  8. }
    - `; B: E' L0 S( Q4 G; M. c( o
  9. $ ?* g% M' M) f0 h  R/ h/ k* m
  10. /* IOUT_OC(A) = IOUT_LIM × 0.05,读改写保留 bit7(LDC_DISABLE) */
    ; N; k, f1 x5 Z5 z! i% ~
  11. int mp4248_set_ilimit(float amps)
    3 I; ^7 A, O3 R4 t. D) m
  12. {% I" w8 }( V+ Q" x2 Z/ e2 Z5 V2 d/ X
  13.         /* ...钳位 0.05~5.4A... */
    ( a" R% @# s" g, {4 n8 y
  14.         uint8_t reg = (uint8_t)(amps / 0.05f + 0.5f);
    - y5 @' h+ i$ }5 Y0 m
  15.         uint8_t buf[2] = { MP4248_CMD_ILIMIT, (uint8_t)((cur & 0x80) | reg) };6 Y# E- ?* r! X! B( j: |) Q
  16.         /* ... */
    8 ~9 _! H; |$ w' f0 e
  17. }
复制代码
7.4 实测反馈回路(src/main.c)8 L/ d/ V1 ^7 ^  \/ w7 u5 _
  1. /*( {: O* Q1 Q0 W. V7 g6 I, V* |
  2. * dps —— NUCLEO-H5E5ZJ 数字电源(M2:调压 + 限流 + 故障状态显示)1 S- d% }2 y, E' c: ]
  3. *
      u) w) r) e. S
  4. * 操作:摇杆左/右 = 切换编辑项(SET 电压 / ILIM 限流);上/下 = 调整
    + S( \8 D2 T1 m- J6 a# e8 W
  5. *       (电压 0.1V 步进,限流 0.1A 步进);按下 = 输出开/关。* m& F  j# a2 E, X% ^
  6. * 显示:lcd_bare 文本(不用 LVGL)。8 O& c+ S( o7 e- v
  7. *
    4 w; S" k! M/ _
  8. * 硬件:EVL4248-QV-00A(MP4248,I2C 地址 0x67)6 g2 _* c8 Q9 F6 d7 l
  9. *   CN2 SCL → Arduino D15(PF5)   CN2 SDA → Arduino D14(PG6)   CN2 GND → GND
    : K6 q2 q" Z. P
  10. *   注意:评估板须先接 VIN(I2C 在 VIN+EN 都有效时才工作);
    * d& |% K" n* U  _& S. L( q$ m
  11. *         上电芯片自动输出约 5V(OTP 行为,软件拦不住),负载侧请自行断电管理。4 \- d1 ~+ w, }) j4 O& W
  12. *5 p& A& s& `' ], k# S1 T4 s
  13. * SPDX-License-Identifier: Apache-2.0( G  \6 U5 u2 O3 u0 \
  14. */; I: R0 v. S1 r

  15. / M3 m8 z! @0 g
  16. #include <stdarg.h>9 N* i1 ]! m& f" P/ ]
  17. #include <stdio.h>
    7 S' `: J" C0 \' E5 y' \7 p( ?
  18. #include <string.h>0 T- T2 I/ W# H3 _  c: I

  19. 6 ]# O  N! k  {: O
  20. #include <zephyr/kernel.h>
    ) K, v1 Y" q5 x
  21. #include <zephyr/drivers/adc.h>7 o" }: Q3 j/ l! p' e2 K! ?) _5 w5 x1 \
  22. #include <zephyr/input/input.h># V' ~8 v! i) _( r/ e
  23. #include <zephyr/sys/printk.h>- f2 W* |! X- q" O+ r9 w

  24. 1 ?5 R. C+ k* L3 D4 F$ B+ c
  25. #include "lcd_bare.h"
    - A# |; {8 o$ b3 T/ T1 h
  26. #include "mp4248.h"
    " P7 B) e# Q& k, K% E) V7 i
  27. ( U3 X9 W3 w! M$ ]2 R( m: S0 w
  28. static float set_volt = 5.0f;        /* 目标电压(0.1V 步进) */- C" d+ h, [# b
  29. static float set_ilim = 5.4f;        /* 目标限流(0.1A 步进,≤5.4A) */
    + F' @$ O4 J/ |& V& ]; X
  30. static float rb_ilim;                /* 限流读回值(验证写入生效) */8 _9 Y+ U/ k( o0 Y+ j7 L. }8 c8 Q
  31. static int edit_target;                /* 0=电压 1=限流 */
    & c( J# d; C2 d; s) e
  32. static bool output_on;+ Z; j8 c4 v, ?: t4 M
  33. static bool mp4248_online;
    : p" o) _" S$ F- g& Z" }. C
  34. static bool ui_dirty = true;
      F( k, y- F4 r/ B5 {! Z6 |* |
  35. static uint16_t status_word;
    , |: }" ~2 b1 g1 ^% l/ B! s

  36. ' I% v5 Y2 k6 E3 p# E/ w
  37. /* 摇杆按键事件(adc-keys 驱动,输入子系统回调) */
    5 N- F; R8 R5 B, y" k( J
  38. static volatile int pending_key;
    , ^7 M0 D9 y, q/ m5 t

  39. . |2 T' C5 _! U- o
  40. /* IMON 电流反馈:EVL4248 IMON 脚 → PC2(ADC1_INP12),IOUT = V_IMON / 0.34 */
    8 ?+ g9 Z4 E4 ~' J
  41. static const struct adc_dt_spec imon_adc =# s  o* I0 w. I# y3 v$ ]( ?
  42.         ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 0);
    $ J. I5 L5 q- K* a/ X6 V
  43. /* VOUT 分压(101.1k/5.05k)→ PC3(ADC1_INP13),VOUT = V_ADC × VOUT_DIV_RATIO */
    5 Y5 _. s5 S% }$ |  c+ \: L! i
  44. #define VOUT_DIV_RATIO        ((101.1f + 5.05f) / 5.05f)
    : b/ y6 Z$ |$ t! k' p% C( Y
  45. static const struct adc_dt_spec vout_adc =" \0 z: g# K5 W" t
  46.         ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 1);. p; _. o4 b* C" Z" T8 u
  47. static float iout_amps;
    6 R( c/ I& w, B' N9 B' V& C
  48. static float vout_volts;        /* VOUT 实测值 */6 o# m/ h( E5 e! ?; r8 M6 r4 O
  49. static int16_t imon_raw = -1;        /* 调试:ADC 原始值(-1=读失败) */1 s0 a5 y' q9 a. ~& C- j$ S9 f
  50. $ M# ?3 s  b' F$ C; ^0 M
  51. static void joy_cb(struct input_event *evt, void *user_data)+ o3 m4 z0 U  F6 c, E! p
  52. {
    ' a! N  q* o  E5 r8 @
  53.         ARG_UNUSED(user_data);
    3 T# }# v1 u% G! H9 @: ?5 t& N
  54.         if (evt->value) {        /* 只处理按下 */
    - l! Q. i' Y4 p
  55.                 pending_key = evt->code;. c7 p7 W; z) \& u! B
  56.         }; z) ?5 l5 L% F* Q- f: C
  57. }: G1 O* d6 Y+ l+ J& M$ N# v0 l
  58. INPUT_CALLBACK_DEFINE(NULL, joy_cb, NULL);
    # L) v/ u. W( e' s; B* w5 I9 ~* @* w

  59. * q) e8 }$ l* O3 x( ~4 S. Y$ H2 [
  60. /* 每行补空格到满宽(20 列),行内覆盖刷新,不再整屏清屏 */8 g8 U7 h/ }$ J8 f7 A4 [1 z
  61. /* 读一路 ADC 并转为 mV,失败返回负 errno */4 B! r7 K7 b- p. X
  62. static int adc_read_mv(const struct adc_dt_spec *spec, int32_t *mv_out)2 \4 |" k9 m1 f6 Q( l1 J; T# D
  63. {9 i$ Y/ w$ `* T! G( F6 b* _8 e
  64.         int16_t raw;" v, O# e, g- P) q2 I8 U" @
  65.         struct adc_sequence seq = {0};! u8 P( T9 ?, B# M1 v0 g7 j9 \# C
  66.         int ret = adc_sequence_init_dt(spec, &seq);7 |3 n) i9 s$ e: ~2 E$ _9 k
  67. ; G+ M7 i- j, S4 N7 S% d0 ^  k
  68.         if (ret != 0) {' b, w" j0 U: X5 o  r! Q: s2 y
  69.                 return ret;
    . y; Z; `1 R2 C$ `, W6 h; v3 X
  70.         }
    8 g* S$ j0 n& [/ M
  71.         seq.buffer = &raw;9 R1 ~' _0 D! ?7 B, ~$ W. y1 m
  72.         seq.buffer_size = sizeof(raw);
    8 s" J1 y7 ]$ C
  73.         ret = adc_read_dt(spec, &seq);; c7 T5 |% H  G- ~0 S% ?
  74.         if (ret == 0) {4 ^. R0 {9 H: V; g; Z  ^; _0 J" Q
  75.                 int32_t mv = raw;8 B+ c7 h7 w+ T( A9 A! X
  76. # F1 T+ F2 n' r2 D+ w2 q  X+ Q
  77.                 ret = adc_raw_to_millivolts_dt(spec, &mv);
    / S7 p6 o7 ^+ j  E  ~
  78.                 if (ret == 0) {. o) C. {5 a" j
  79.                         *mv_out = mv;  f& u8 |: a+ [- A- w
  80.                 }; M8 f( P1 v! ^  x
  81.         }
      W6 r& A$ K' N. C9 y6 B
  82.         return ret;
    4 K$ V3 N& h+ q
  83. }
    : R  {& e2 A$ q  a$ r$ Y
  84. / W3 t& y! X7 O! q
  85. static void ui_line(uint8_t row, uint16_t fg, const char *fmt, ...)& B, P! M  V9 F5 S
  86. {
    1 S3 E  m; i0 a+ A* r2 w- A* t
  87.         char line[24];% u3 e+ g. L# x  S- |2 E
  88.         va_list ap;
    4 @/ z' d8 s8 q* k& ^* ]/ d
  89. 1 w+ X" m5 W" P; ]5 O' _
  90.         va_start(ap, fmt);+ C! U; B' R/ n
  91.         vsnprintf(line, sizeof(line), fmt, ap);
    1 p' p: n( a; L/ F, }
  92.         va_end(ap);! O6 g& \, A3 E
  93.         size_t n = strlen(line);$ M) v2 `- g. Y6 g; {1 v7 F3 o# n! `0 c) X

  94. $ v6 b$ m. o) s% x+ G
  95.         while (n < 20) {
    & n' r; F  G# P- B" g6 ]: _/ D
  96.                 line[n++] = ' ';
    8 Z7 S# K" ]" w. E! i
  97.         }1 d- _$ H" w& Q9 J! n9 q8 d9 f
  98.         line[n] = '\0';( N/ J  ?( S) S1 l/ ]
  99.         lcd_bare_text(0, row * 8, line, fg, LCD_BLACK);4 t& g) [. D6 L2 Y+ ^) G
  100. }
    ! m' `* a4 f( w7 O# Z; P- c: O
  101. " H) ]/ A# t% ?' d# B4 l
  102. static void ui_redraw(void). j+ n  l! ^9 J* F
  103. {
    * k) a( B3 [  d/ R
  104.         float rb;8 `& ?/ P% T# v  [( u( X6 _& r2 g
  105.         uint16_t st = status_word;
    5 _  h; I; _  B9 F& I
  106. ( Z: n- J; n+ V! w8 S) C
  107.         ui_line(0, LCD_WHITE, "DPS MP4248  I2C:%s", mp4248_online ? "OK" : "ERR");
    2 k( G/ R7 F8 w& A
  108.         ui_line(1, LCD_BLUE, "--------------------");
    + q" ~& N9 I; Z  ]0 b3 P1 v2 p& {
  109. ' C7 y8 N7 l# m6 u2 p
  110.         ui_line(3, LCD_YELLOW, "%cSET: %5.2f V", edit_target == 0 ? '>' : ' ',
    8 d  n/ k; R+ u% g+ v
  111.                 (double)set_volt);
    & [" p( U" G7 X' s
  112.         ui_line(5, LCD_YELLOW, "%cILIM:%4.2f/%4.2fA", edit_target == 1 ? '>' : ' ',' \, e# a1 E1 C- |/ X$ W
  113.                 (double)set_ilim, (double)rb_ilim);
    ( P# Q1 G* H! q: b9 p$ Z3 ?. O1 i! t
  114. 1 x& i9 p! c2 W4 `
  115.         if (mp4248_get_vout(&rb) == 0) {& w, l1 {: p* g
  116.                 ui_line(7, LCD_GREEN, "VCMD: %5.2f V", (double)rb);: X9 x, F  G2 J6 i3 v+ r& m+ `
  117.         } else {! F  ?# w3 g( O" f* o; }
  118.                 ui_line(7, LCD_RED, "VCMD: --.-- V");: t0 ]; ]* g* z
  119.         }& e3 p' _* R5 h
  120. ! U- j# }5 k+ j4 e. n% o
  121.         ui_line(8, LCD_GREEN, "VOUT:%5.2f V", (double)vout_volts);  {6 b# W$ k% q& H# A& N
  122.         ui_line(9, LCD_GREEN, "IOUT:%5.2f A", (double)iout_amps);# K- G1 J7 r! V+ r. H! |

  123. 6 g" M  Z! `3 z1 l( w: C6 j
  124.         ui_line(11, output_on ? LCD_GREEN : LCD_RED, "OUT:%s ST:%04X",
    8 e1 G! q5 e& M: M  V
  125.                 output_on ? "ON " : "OFF", st);, w7 r- _  `; R" q1 c
  126. # K( H) ^! I5 I# Q# b) E, o
  127.         ui_line(13, LCD_WHITE, "LR:item UD:adj OK:out");  c2 j" y- f3 y8 D$ U
  128.         ui_dirty = false;
      [2 t( f( M9 }' G  C
  129. }6 x% a. i& I9 m; U& A8 }; S

  130. - F/ D; }. F9 [
  131. int main(void)
    $ w' _6 j5 N) [) D9 v- W: D
  132. {' a# m5 s- K  E0 T! {
  133.         printk("dps: NUCLEO-H5E5ZJ digital power supply (M2)\n");; H& o. d9 [( ?; [8 n

  134. 1 y" h" R- v) W: y. Z5 |6 Y) K- p( d
  135.         if (lcd_bare_init() != 0) {& j% m% i# z: [& C
  136.                 printk("dps: lcd init failed\n");
    - a$ I- j; [# Z  n! [6 v
  137.         }/ F& v( W3 w# v; ^# u) c
  138.         lcd_bare_fill(LCD_BLACK);        /* 只在开机整屏清一次,之后按行覆盖刷新 */7 r7 V! V. T, p( V3 |
  139.         if (mp4248_init() == 0) {
    7 H1 P" W  }2 C1 x/ F! H5 \( f
  140.                 mp4248_online = (mp4248_probe() == 0);7 d7 f6 U4 i% j5 n9 j5 k$ x( u
  141.                 if (mp4248_online) {
    5 e2 L, D  j: I' x. D, G
  142.                         mp4248_get_ilimit(&set_ilim);        /* 读回芯片当前限流作为初值 */5 v) L% u/ ?4 }- t
  143.                 }
    + n  V9 I7 Y% F: z- y- y4 v, a& @" T, w
  144.         }
      g/ j# z0 I, F0 n1 o
  145.         printk("dps: mp4248 %s\n", mp4248_online ? "online" : "NOT FOUND");( i+ o% P- ]: I3 i) z7 h* O

  146. $ \5 Q" m- R6 E# ?$ i! i6 v
  147.         if (adc_is_ready_dt(&imon_adc) && adc_is_ready_dt(&vout_adc)) {5 H. Y, @. @$ e; o0 y
  148.                 int rc1 = adc_channel_setup_dt(&imon_adc);
    # C6 E2 s% W/ @% q, o1 v6 }, ]5 v
  149.                 int rc2 = adc_channel_setup_dt(&vout_adc);7 z& F, N8 i8 c4 T- w) h/ r
  150. , v3 b8 Q8 `' x1 T* s) L. D
  151.                 printk("dps: adc setup imon=%d vout=%d\n", rc1, rc2);
    ' d% y, S. |$ f
  152.         } else {
    * W( _( h, P! E9 _
  153.                 printk("dps: adc not ready\n");
    ! P0 r4 J! \7 [. q" I  R" Y
  154.         }
    ! q5 @. N. F' g- H7 F; y5 Q
  155. ; @5 V- A3 j. }9 Q' _! P- U
  156.         uint32_t last_poll = 0;
    8 V% ]5 F# K+ c+ P/ b) V# p/ y

  157. / [3 o3 O& K* ~, I9 N0 U
  158.         while (1) {7 }' f4 b, v3 o5 Z  A4 F
  159.                 int key = pending_key;
    / d3 f( l; U, `6 N. T
  160. $ u( q+ `- {' f  S& P' v
  161.                 pending_key = 0;
    ! \, w. k) C% }
  162.                 switch (key) {! `, R; r( F6 K7 M) W% H9 O6 I
  163.                 case INPUT_KEY_LEFT:
    : T, U: K8 W" _% ?" H) h
  164.                 case INPUT_KEY_RIGHT:
    4 r: I1 B; c8 H7 p
  165.                         edit_target ^= 1;        /* 电压 <-> 限流 */1 Y' B8 q5 q; S5 M. O
  166.                         break;1 B# E/ a: B6 R9 X; h3 X: P
  167.                 case INPUT_KEY_UP:
    0 H8 @. v% r, u" w" U( c
  168.                         if (edit_target == 0) {
    1 A8 H- }7 g2 N
  169.                                 set_volt += 0.1f;
    1 L8 F/ w& `/ ~  L( ~
  170.                                 if (set_volt > MP4248_VOUT_MAX) {7 c' }0 x1 P+ n: w& ~+ l
  171.                                         set_volt = MP4248_VOUT_MAX;. w# p/ q  b' V6 Y$ ^9 I8 @
  172.                                 }/ h3 m. F8 c/ U' e
  173.                                 if (mp4248_set_vout(set_volt) != 0) {& m. w$ N' D6 y5 p4 k, b
  174.                                         mp4248_online = false;
    / N7 u& A6 e! \& X1 h
  175.                                 }
    & s( _. e+ s% m/ U! z
  176.                         } else {
    9 S$ f: J4 c* E0 q7 @
  177.                                 set_ilim += 0.1f;
    / e) H$ q- c; _" G7 J
  178.                                 if (set_ilim > 5.4f) {. ^* @# {$ m3 a
  179.                                         set_ilim = 5.4f;& c( w% I3 j, e! j; S: U: b5 T" W
  180.                                 }8 X4 T5 r, \+ e/ e! U# D* K
  181.                                 if (mp4248_set_ilimit(set_ilim) != 0) {
    - a, N9 w5 m5 f7 q$ }
  182.                                         mp4248_online = false;- Z; n; }. L! `9 `  G
  183.                                 }
    8 E9 \& _4 e3 [1 J4 G: C
  184.                         }
    , P/ b3 L" J/ U* n4 ^* M/ [3 }
  185.                         break;: d$ h; g3 v/ O$ _) j( x1 ?; U
  186.                 case INPUT_KEY_DOWN:
    - i* V& A$ f8 t: j: j( b: E: U
  187.                         if (edit_target == 0) {
    4 V) h2 e2 N) L( `, i5 ^5 X
  188.                                 set_volt -= 0.1f;# D. K7 i' e! V+ A, k
  189.                                 if (set_volt < MP4248_VOUT_MIN) {
    8 }" |  \) b# G0 P. E5 G
  190.                                         set_volt = MP4248_VOUT_MIN;
    ( b9 d  f+ M4 E2 A2 {6 H5 Z2 h0 c
  191.                                 }4 G7 e: b- I. E! Z3 `& h$ T
  192.                                 if (mp4248_set_vout(set_volt) != 0) {: J1 _2 S, s# d# v! b' T7 _! P
  193.                                         mp4248_online = false;
    % \7 x, v: O& @6 X4 d8 L; f
  194.                                 }
    1 ?7 Z: `6 |" _" j/ x- u
  195.                         } else {) b: T6 h$ W1 l+ o
  196.                                 set_ilim -= 0.1f;
    / j. ]. }) n7 W! K# o5 m) ]) |
  197.                                 if (set_ilim < 0.5f) {
    & ?4 Y4 O8 S6 l: `8 p# N1 N
  198.                                         set_ilim = 0.5f;
    7 |+ y& [9 O: B% @0 C* g9 y0 ]' l
  199.                                 }& U: {) @: @! ?( c. I+ g) t& L" S+ U+ |
  200.                                 if (mp4248_set_ilimit(set_ilim) != 0) {
    ( {2 n* D/ Q- \$ A7 [4 `
  201.                                         mp4248_online = false;4 Z+ I; i% Z6 b4 F9 s* p4 u
  202.                                 }
    0 e% n( U7 h5 L" d* p5 c
  203.                         }
    3 K& R. E# b, Z5 w' H
  204.                         break;. t  F  e% C8 i3 B
  205.                 case INPUT_KEY_ENTER:# T6 W9 k- g# p; k8 ]
  206.                         output_on = !output_on;$ I" n& h0 M* p  o2 J* `2 g5 x
  207.                         if (output_on) {( N: J& G/ J; p
  208.                                 /* 开输出前清掉历史故障锁存(PMBus 状态位需 CLEAR_FAULTS 才复位) */& |0 t5 T" F* }& M1 p5 p* D1 y+ o
  209.                                 (void)mp4248_clear_faults();! M" F/ B9 e, U, h5 j) I
  210.                         }
    & W  v7 ?4 r; w; m
  211.                         if (mp4248_output(output_on) != 0) {
    1 p7 h, v+ x& m3 P5 ~$ {& K
  212.                                 mp4248_online = false;
    0 x6 \1 `/ W, S! G  D
  213.                         }
    * @# f% K5 Y! |2 A) I
  214.                         printk("dps: output %s\n", output_on ? "ON" : "OFF");
    . a" U8 `% ~$ Y" K
  215.                         break;
    " ]3 a5 L4 {) ?+ c/ }9 q5 s
  216.                 default:8 G/ P' _3 D& q
  217.                         break;+ ]/ ~* ~9 Z" H; x$ O+ W! M
  218.                 }: `$ {) J) }; y  m+ _/ b  m
  219. 4 _1 q* y3 Q7 T' [5 g
  220.                 if (key != 0) {& r0 ]$ u8 X& Z8 X
  221.                         ui_dirty = true;
    ) {" E$ P! Z/ v9 O- R: ~
  222.                 }' q4 s/ h- F& g$ ^9 G5 N# J- k
  223. ) }0 k. J3 E/ y1 j0 |
  224.                 /* 500ms 轮询读回电压 + 限流读回 + 状态字 + IMON + VOUT 实测 */7 y) j/ I* u( u* p/ L9 x
  225.                 if (k_uptime_get_32() - last_poll > 500) {% b6 [7 n* }% P* P+ z$ }. a5 x
  226.                         last_poll = k_uptime_get_32();
    " ^% ?7 Y* j" B2 t- \4 h( c
  227.                         if (!mp4248_online) {
      f) j0 S* Q% v. d, p$ i# T- @6 J
  228.                                 /* 离线时每 2 秒重试 probe(评估板后上电/接线恢复也能上线) */
      M1 J4 Y1 r) L0 o7 R( H' C
  229.                                 static uint32_t last_probe;
      t4 _5 B. J7 X) B- L2 l1 E; e. K

  230. 3 Q! W5 Q8 O5 \& z- U7 g: D
  231.                                 if (k_uptime_get_32() - last_probe > 2000) {
    & i0 T! R/ A  W3 t4 |- y2 `
  232.                                         last_probe = k_uptime_get_32();
    , ]$ K9 g( h" v+ d6 P" o# F1 Y
  233.                                         if (mp4248_probe() == 0) {
    % B4 `2 b1 d" F2 j  [% r
  234.                                                 mp4248_online = true;
    ! ?5 k" S* \9 o- S6 Y6 C
  235.                                                 mp4248_get_ilimit(&set_ilim);
    5 U0 F- p% s  s$ [4 T8 ?
  236.                                                 printk("dps: mp4248 back online\n");
    9 K) r: Y, b- B9 e
  237.                                         }- `& i% @6 x. N( g- l) `# W- ^
  238.                                 }
    1 ^( j! b. y- O3 i
  239.                         } else {
    * p; j7 o* H! g" ^
  240.                                 (void)mp4248_status_word(&status_word);/ X; y" j+ ~5 T8 E9 T" _
  241.                                 (void)mp4248_get_ilimit(&rb_ilim);' w' e1 C% I# a4 r, r5 J/ m
  242.                         }
    9 w- l9 E% C3 c( H6 U! ^2 C+ h
  243.                         /* IMON:IOUT = V_IMON / 0.34(5mΩ×68V/V) */
    0 |' ^7 f* C3 }) ~3 r; B; _/ y5 J
  244.                         int32_t mv;
    * H% {. a5 U9 N6 d: P9 t( P5 n  q/ H
  245.                         int rr = adc_read_mv(&imon_adc, &mv);5 s% P5 l) i! ?6 c& Y1 K

  246. 4 k* {9 m3 R7 g) N
  247.                         if (rr == 0) {
    ( [' L3 E4 `/ K9 `4 v
  248.                                 imon_raw = (int16_t)(mv * 4096 / 3300);
    , v% a1 a7 S3 q9 V; b, P8 E
  249.                                 iout_amps = (float)mv / 1000.0f / 0.34f;
    , ^1 z, I# {' p% Y1 Z9 n
  250.                         } else {
    . M1 U$ S' m3 ]- P
  251.                                 imon_raw = (int16_t)rr;        /* 负 errno 直接上屏 */
    5 m9 y$ f7 n; {6 S1 `& a  h6 ]
  252.                                 printk("dps: adc read err %d\n", rr);
    % v' G: F! _6 ^
  253.                         }# H2 W: t8 e7 t% V) f
  254.                         /* VOUT 分压:VOUT = V_ADC × VOUT_DIV_RATIO */
    ! O+ G8 H2 |4 `- o% H1 Q
  255.                         if (adc_read_mv(&vout_adc, &mv) == 0) {
    2 M, a! F3 O4 k5 Z7 @$ s$ t" y
  256.                                 vout_volts = (float)mv / 1000.0f * VOUT_DIV_RATIO;
    ; `3 d! A) J: I8 B; e5 f
  257.                         }
    : B. U0 X( Z' v7 B( V" ]* h: {. G
  258.                         ui_dirty = true;; @1 h+ h5 G  ]4 i4 Y
  259.                 }6 @+ S) L( v) Z, H1 X
  260.                 if (ui_dirty) {6 ^9 s& E9 S7 w; Z6 t
  261.                         ui_redraw();
    3 {* D0 k% n4 j; P, o" Z# b1 C
  262.                 }
    # M% t( ]" k! z# n( n
  263.                 k_msleep(50);
    0 F( R: _! h0 s1 \( Z4 s
  264.         }
    * i: R; E# L9 s6 I# r- w! b/ V
  265.         return 0;
    6 b+ U; ^! f( l$ i
  266. }
    ; p& {! N$ @7 u' L. x+ H7 A0 \
复制代码
八、项目展示$ |# i' ~; r, `7 K& |* d1 z+ g4 U$ t! Y
数字电源整体项目.jpg
3 F7 `  I- G+ |通过按键可以实时调节输出电压、电流限值等。
8 S3 W# F& q5 r
0 @$ y$ L" u' g  ]3 T% q, R
5 I  d1 Y+ r; S" `3 R: C; v7 `1 E# _4 I) |# O( ~
/ |. Z! y  c' Z- b/ R1 L
" {3 G$ y1 L! i% I
  Y& W' ^( w! q
赞 收藏 评论0 发布时间:2026-10-18 11:31

举报

0个回答

所属标签

相似技术帖

官网相关资源

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