NUCLEO-H5E5ZJ 移植 LVGL(ST7735 LCD + 五向摇杆)
3 ^& W# {% P% W; G* v4 Z( W 0. 效果 LCD 显示 LVGL 菜单界面:标题 Joystick Menu + 4 个菜单按钮(LED1 GREEN / LED2 RED / LED3 BLUE / About)+ 底部状态行。LCD 扩展板上的五向摇杆导航:上下/左右移动焦点(黄色高亮框),按下确认——前 3 项直接翻转板载 LD1/LD2/LD3,状态行同步显示 LDx ON/OFF。已在实物上验证通过。 1. 系统架构五向摇杆(电阻分压) ST7735 LCD+ i! t. Y, s, j& p" x│ ▲2 N' `4 V$ g! j ▼ 模拟电压 │ SPI4 @10MHz& p# K2 f$ C' `/ q" i ADC1_INP9 (PB0, Arduino A3) │: y& B) H: X+ P: i# r3 K │ │! J3 @ L# Y4 [ Y ▼ │ Zephyr adc-keys 输入驱动 │ ┌─────────────────────┐ (50ms 轮询 + 最近阈值匹配 + 消抖) │ │ lcd_bare 裸 SPI 驱动 │ │ INPUT_KEY_* 事件 ├──▶│ display_bare shim │ ▼ │ │ (Zephyr display API) │ zephyr,lvgl-keypad-input │ └─────────────────────┘$ L0 k2 E8 r0 U7 N" J (input-codes → lvgl-codes 映射) │ ▲" y% b P) c D: q, \ │ LV_KEY_* │ display_write(RGB565)$ x) v4 k5 \/ A5 @5 m ▼ │ │ LVGL keypad indev → lv_group 焦点组 ──────┴─── LVGL 渲染(lv_timer_handler) LVGL 显示与输入在 Zephyr 中全部通过设备树声明对接,应用代码零胶水。 2. 硬件连接(LCD 扩展板插 Arduino 排针)功能Arduino 位H5E5ZJ 引脚外设SPI_SCKD13PE12SPI4_SCK9 X; J- f( l _) V" U- i/ r SPI_MISOD12PE13SPI4_MISO SPI_MOSID11PE14SPI4_MOSI0 D; K. s8 ?) E! u2 ], @; G" \4 ^; P LCD CSD10PE11GPIO(软件控制) LCD DCD8PA9GPIO 五向摇杆A3PB0ADC1_INP9 引脚依据为 MB2129 原理图第 5 页连接器部分:
电阻分压式:3.3 V 经上拉,拨向某方向把对应电阻短到 GND,输出不同分压。ADC(12 位,3.3 V 基准)实测各方向电压: 方向ADC raw(约)电压(约)press-thresholds-mv. W4 f- V) P7 y p右8871 mV71 上738595 mV595: d- R. [! l2 V+ G1 w 确认(按下)13101055 mV1055# J: X/ _4 q; R$ K8 m+ u 左20481650 mV16509 I4 i+ {- Q! w 下33762720 mV2720 松开(开路)40953298 mVkeyup = 33003. 逐步实现第 1 步:应用骨架apps/lvgl_demo/ ├── CMakeLists.txt; w6 U9 L7 {( z, g- Z ├── prj.conf ├── boards/nucleo_h5e5zj.overlay$ Y; ]* n$ ]# _ ├── dts/bindings/display/ │ ├── uniknect,lcd-bare.yaml # display shim 绑定 │ └── uniknect,lcd-io.yaml # LCD DC/CS GPIO 绑定 └── src/' q' f2 O) A: m! l! b ├── main.c # LVGL 菜单 UI + 摇杆焦点组7 l" U4 N3 r7 m# p: I% ^+ V' T; K ├── lcd_bare.c / lcd_bare.h # ST7735 裸 SPI 驱动(板级无关) ├── display_bare.c # Zephyr display API shim(LVGL 的显示后端) └── font_petme128_8x8.h第 2 步:overlay —— 摇杆接入 Zephyr 输入子系统 Zephyr 自带 adc-keys 输入驱动(drivers/input/input_adc_keys.c),专为电阻分压式按键设计:按 sample-period-ms 轮询 ADC,找电压最接近的阈值判定按键,内置两周期消抖,无需自写驱动: #include <zephyr/dt-bindings/input/input-event-codes.h>#include <zephyr/dt-bindings/lvgl/lvgl.h>8 G4 y( S' U! H: ]% [ 3 k# F( T/ b% d1 _ / { joystick: joystick { compatible = "adc-keys";0 H% j! b& o+ j- ^ O5 y* A& Q io-channels = <&adc1 9>;+ J" _4 D* j( P) u sample-period-ms = <50>; keyup-threshold-mv = <3300>; /* 松开=开路电压 */ 6 q$ G" g1 A* v% r* i" j! h8 s key_right { press-thresholds-mv = <71>; zephyr,code = <INPUT_KEY_RIGHT>; }; key_up { press-thresholds-mv = <595>; zephyr,code = <INPUT_KEY_UP>; };3 A: K+ g1 I/ A+ _ key_center { press-thresholds-mv = <1055>; zephyr,code = <INPUT_KEY_ENTER>; }; key_left { press-thresholds-mv = <1650>; zephyr,code = <INPUT_KEY_LEFT>; }; key_down { press-thresholds-mv = <2720>; zephyr,code = <INPUT_KEY_DOWN>; }; };0 }7 F7 K" X6 z% X. x& F8 x, e6 K" y }; ADC 通道配置(v4.4 的 H5E5 设备树中 adc1 是独立节点,无 adc12_common 包装层,adc_ker 时钟和分频直接写在 &adc1 上): &adc1 {; b }2 G; f# Cclocks = <&rcc STM32_CLOCK(AHB2, 10)>, F5 W7 \8 Y) n" A4 ~4 C. D <&rcc STM32_SRC_HCLK ADCDAC_SEL(0)>; clock-names = "adcx", "adc_ker"; pinctrl-0 = <&adc1_inp9_pb0>; pinctrl-names = "default"; st,adc-clock-source = "ASYNC";3 h8 a5 u& J: y st,adc-prescaler = <6>; status = "okay"; #address-cells = <1>;8 m4 }- K0 `% P+ ]! J6 f6 j #size-cells = <0>; ' R# q" z( a0 H6 Q channel@9 { reg = <9>; zephyr,gain = "ADC_GAIN_1";6 g/ |' r, z _1 }; a zephyr,reference = "ADC_REF_INTERNAL"; zephyr,vref-mv = <3300>; /* adc-keys 按 mV 判定,必须给基准 */ zephyr,acquisition-time = <ADC_ACQ_TIME_MAX>;3 `( n! K% ]3 J. g( l# p" \ zephyr,resolution = <12>; };0 C. d; U }. c, ]3 }- d };第 3 步:overlay —— 输入事件映射给 LVGL(关键踩坑点) Zephyr 的 LVGL 模块提供 zephyr,lvgl-keypad-input 伪设备:监听指定输入设备的 INPUT_KEY_* 事件,按 input-codes→lvgl-codes 表翻译成 LV_KEY_* 注入 LVGL keypad 输入设备: / {lvgl_keypad {( H6 r2 @% i' N- O compatible = "zephyr,lvgl-keypad-input"; input = <&joystick>; input-codes = <INPUT_KEY_UP INPUT_KEY_DOWN INPUT_KEY_LEFT INPUT_KEY_RIGHT; g( \# C" n* |# h3 a INPUT_KEY_ENTER>;: {; ^6 d- K+ V7 ~) C# s lvgl-codes = <LV_KEY_PREV LV_KEY_NEXT LV_KEY_PREV LV_KEY_NEXT LV_KEY_ENTER>;/ `$ z; C; X* s; I$ I2 a }; };
LCD 部分(SPI4 + lcd_bare + lcd_io 节点)与纯 LCD 工程相同,不重复展开。 第 4 步:prj.confCONFIG_GPIO=yCONFIG_SPI=y CONFIG_DISPLAY=y CONFIG_ADC=y! ^" B t6 w( ?$ g+ O6 J CONFIG_INPUT=y # adc-keys / lvgl-keypad-input 均 default y(节点使能即生效) CONFIG_MAIN_STACK_SIZE=4096 1 P* W% p; Q6 a0 M CONFIG_LVGL=y CONFIG_LV_Z_MEM_POOL_SIZE=16384 CONFIG_LV_COLOR_DEPTH_16=y5 |* G2 Z! q% T6 I, ]$ k& | CONFIG_LV_COLOR_16_SWAP=y # 与 display_bare shim 约定:LVGL 缓冲即大端 RGB565,直透传 CONFIG_LV_USE_BUTTON=y CONFIG_LV_USE_LABEL=y CONFIG_LV_COLOR_16_SWAP=y 必须与 display shim 的字节序约定一致(shim 不做逐像素交换,直接透传 SPI)。 第 5 步:应用代码要点(src/main.c)/* 1. 找到 LVGL keypad 输入设备并绑定焦点组 */lv_indev_t *indev = NULL;3 v* N& `/ j& b5 d while ((indev = lv_indev_get_next(indev)) != NULL) {# M5 ]2 `4 R/ g( O' C( o* q if (lv_indev_get_type(indev) == LV_INDEV_TYPE_KEYPAD) {% w7 ]. v& `" ]" j keypad = indev;. L, Y/ [. |3 z L# k6 I- A }) m: \: B! u/ O5 z: d }* F3 i* ~* f9 K' i( x7 I, j lv_group_t *group = lv_group_create();, b5 r- O5 q, O /* lv_group_add_obj(group, btn); 每个菜单项都加入 */ lv_indev_set_group(keypad, group);& S4 a+ j+ ] K 0 R; z' s9 k7 D% k3 k4 r) z /* 2. 焦点可见性:给菜单按钮加 FOCUS_KEY/FOCUSED 两个状态的样式 */ lv_obj_add_style(btn, &style_focus, LV_STATE_FOCUS_KEY);1 b( k0 t5 t7 c2 M4 R k, o: r lv_obj_add_style(btn, &style_focus, LV_STATE_FOCUSED);3 K$ h8 ^+ x3 q9 a0 q3 L $ X* p: O- ^% L' E /* 3. 主循环 */ display_blanking_off(display_dev);' X! ]& Q& z& p% D while (1) {5 C2 ~0 b8 k4 I1 F% G uint32_t sleep_ms = lv_timer_handler();. g z# K4 y, J0 { k_msleep(MIN(sleep_ms, 20)); } 输入事件在 lv_timer_handler() 内部从消息队列取出处理,主循环单线程即可,无需额外同步。 第 6 步:编译、烧录、验证cd /d/luglZephyrprojectexport ZEPHYR_SDK_INSTALL_DIR=/d/luglZephyrproject/zephyr-sdk-1.0.1/zephyr-sdk-1.0.18 u' |8 F. s& F $ s( I# p- N# ^& e' A, H! {; y" \ s& P west build -b nucleo_h5e5zj /d/STM32/STM32H5E5/NUCLEO_H5E5ZJ/apps/lvgl_demo \ -d build_h5e5_lvgl -p always -- -DBOARD_ROOT=D:/STM32/STM32H5E5/NUCLEO_H5E5ZJ( O- _4 H4 ^2 {- {% l" j west flash -d build_h5e5_lvgl 实测结果(2026-10-16):
4. 经验总结
|
【STM32H5 评测】基于NUCLEO_H5E5ZJ+Zephyr数字电源
【STM32H5 评测】2、Keil中添加RTX5 RTOS和Event Record
STM32C542RC开发板PWM呼吸灯及多功能按键实验
NUCLEO-H5E5ZJ 移植 ST7735 SPI LCD 驱动
NUCLEO-H5E5ZJ 以太网(Ethernet)移植记录
【STM32H5 评测】1、移植记录(LED / Shell)
【STM32H5 评测】介绍、环境搭建、工程测试
架构革新篇:单芯片 GUI 方案原理与核心优化技术
【新品发布】STM32H543/H553 新品登场
STM32C542RC开发板实现长短按键识别功能
微信公众号
手机版