用Raspberry Pi Pico和ILI9341屏做个桌面小仪表:C语言+LVGL实时显示ADC电压值

张开发
2026/4/17 22:55:42 15 分钟阅读

分享文章

用Raspberry Pi Pico和ILI9341屏做个桌面小仪表:C语言+LVGL实时显示ADC电压值
用Raspberry Pi Pico和ILI9341打造迷你电压监测仪从硬件搭建到LVGL界面优化在创客圈里Raspberry Pi Pico以其亲民的价格和强大的性能成为了无数DIY项目的核心。而当我们为它搭配一块色彩鲜艳的ILI9341显示屏时就能轻松打造出一个既实用又具观赏性的桌面小工具。本文将带你完整实现一个实时电压监测仪从硬件连接到LVGL界面设计让你的工作台多一个会说话的电子伙伴。1. 项目规划与硬件选型为什么选择Raspberry Pi Pico作为这个项目的主控这款由树莓派基金会推出的微控制器板载RP2040双核ARM Cortex-M0处理器运行频率可达133MHz性能远超传统Arduino。更重要的是它具备丰富的GPIO接口和硬件ADC非常适合实时数据采集项目。ILI9341是一款240x320分辨率的2.2英寸TFT液晶屏支持SPI接口色彩表现优异。相比OLED屏幕它的可视角度更大阳光下依然清晰可见特别适合作为桌面仪表的显示设备。所需材料清单Raspberry Pi Pico开发板 ×1ILI9341 TFT显示屏2.2英寸 ×110kΩ电位器 ×1用于模拟电压变化面包板及杜邦线若干Micro USB数据线 ×1硬件连接示意图如下表所示Pico引脚ILI9341引脚功能说明GP0SCLKSPI时钟GP1MOSISPI数据输出GP5CS片选信号GP6DC数据/命令选择GP7RST复位信号3V3VCC电源正极GNDGND电源负极GP26-ADC输入(接电位器中端)2. 开发环境搭建与基础驱动在开始编码前我们需要配置好开发环境。推荐使用Visual Studio Code配合PlatformIO插件这是目前最便捷的嵌入式开发方案之一。首先创建一个新的PlatformIO项目选择Raspberry Pi Pico作为开发板。然后在platformio.ini配置文件中添加必要的库依赖[env:rpipico] platform https://github.com/maxgerhardt/platform-raspberrypi.git board rpipico framework pico-sdk lib_deps lvgl/lvgl^8.3.4 bodmer/TFT_eSPI^2.5.0LVGLLight and Versatile Graphics Library是一个开源的嵌入式GUI库特别适合资源有限的微控制器。它提供了丰富的控件和动画效果能让我们的电压监测仪拥有专业级的界面表现。基础驱动代码需要完成三个关键任务初始化SPI接口与ILI9341屏幕配置ADC输入引脚设置LVGL显示缓冲区#include pico/stdlib.h #include hardware/spi.h #include hardware/adc.h #include lvgl.h #define SPI_PORT spi0 #define PIN_MISO 4 #define PIN_CS 5 #define PIN_SCK 2 #define PIN_MOSI 3 #define PIN_DC 6 #define PIN_RST 7 void hardware_init() { // SPI初始化 spi_init(SPI_PORT, 1000 * 1000); gpio_set_function(PIN_MISO, GPIO_FUNC_SPI); gpio_set_function(PIN_SCK, GPIO_FUNC_SPI); gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI); // 控制引脚初始化 gpio_init(PIN_CS); gpio_init(PIN_DC); gpio_init(PIN_RST); gpio_set_dir(PIN_CS, GPIO_OUT); gpio_set_dir(PIN_DC, GPIO_OUT); gpio_set_dir(PIN_RST, GPIO_OUT); // ADC初始化 adc_init(); adc_gpio_init(26); adc_select_input(0); }3. LVGL界面设计与美化LVGL提供了多种方式来创建美观的界面。对于电压监测仪我们可以设计一个模拟仪表盘让数据显示更加直观。首先创建一个仪表盘对象lv_obj_t *gauge lv_gauge_create(lv_scr_act(), NULL); lv_gauge_set_range(gauge, 0, 3300); // 设置量程为0-3.3V(以毫伏为单位) lv_gauge_set_critical_value(gauge, 3000); // 设置警告阈值 lv_obj_set_size(gauge, 200, 200); lv_obj_align(gauge, NULL, LV_ALIGN_CENTER, 0, -20);为了让界面更加专业我们可以自定义样式static lv_style_t gauge_style; lv_style_init(gauge_style); lv_style_set_bg_color(gauge_style, LV_STATE_DEFAULT, lv_color_hex(0x222222)); lv_style_set_text_color(gauge_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_style_set_line_width(gauge_style, LV_STATE_DEFAULT, 3); lv_style_set_line_color(gauge_style, LV_STATE_DEFAULT, lv_color_hex(0x0099FF)); lv_obj_add_style(gauge, LV_GAUGE_PART_MAIN, gauge_style);添加数值显示标签和单位lv_obj_t *label lv_label_create(lv_scr_act(), NULL); lv_obj_align(label, gauge, LV_ALIGN_OUT_BOTTOM_MID, 0, 20); lv_label_set_text(label, 0.00V); lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_font_montserrat_24);4. 数据采集与实时显示Raspberry Pi Pico内置的12位ADC能够提供0-3.3V的电压测量。我们需要定期采样并将结果更新到界面上。创建一个定时器任务来处理数据更新static void adc_read_task(lv_task_t *task) { static uint32_t last_value 0; uint16_t adc_raw adc_read(); uint32_t voltage_mv adc_raw * 3300 / 4096; // 转换为毫伏 // 添加简单的滤波处理 voltage_mv (last_value * 3 voltage_mv) / 4; last_value voltage_mv; // 更新仪表指针 lv_gauge_set_value(gauge, 0, voltage_mv); // 更新数字显示 char buf[16]; snprintf(buf, sizeof(buf), %.2fV, voltage_mv / 1000.0f); lv_label_set_text(label, buf); // 超过阈值时改变颜色 if(voltage_mv 3000) { lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); } else { lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); } }在主函数中初始化并启动这个任务int main() { stdio_init_all(); hardware_init(); lv_init(); tft_init(); lv_port_disp_init(); create_gauge_ui(); lv_task_t *task lv_task_create(adc_read_task, 100, LV_TASK_PRIO_MID, NULL); while(1) { lv_task_handler(); sleep_ms(5); } }5. 功能扩展与项目优化基础功能实现后我们可以考虑添加更多实用功能数据记录功能#define HISTORY_SIZE 100 static uint16_t voltage_history[HISTORY_SIZE]; static uint8_t history_index 0; // 在adc_read_task中添加 voltage_history[history_index] voltage_mv; history_index (history_index 1) % HISTORY_SIZE;然后创建一个新的图表来显示历史数据lv_obj_t *chart lv_chart_create(lv_scr_act(), NULL); lv_obj_set_size(chart, 220, 100); lv_obj_align(chart, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -10); lv_chart_set_range(chart, 0, 3300); lv_chart_set_point_count(chart, HISTORY_SIZE); lv_chart_series_t *ser lv_chart_add_series(chart, LV_COLOR_RED);多通道监测 Pico有多个ADC通道可以同时监测多路电压adc_gpio_init(26); // ADC0 adc_gpio_init(27); // ADC1 adc_gpio_init(28); // ADC2 // 在读取时切换通道 adc_select_input(0); // 读取ADC0 uint16_t adc0 adc_read(); adc_select_input(1); // 读取ADC1 uint16_t adc1 adc_read();低功耗优化 如果希望设备能电池供电可以添加休眠模式#include hardware/clocks.h #include hardware/pll.h void enter_sleep_mode() { // 降低CPU频率 set_sys_clock_khz(12000, true); // 关闭不需要的外设 spi_deinit(SPI_PORT); // 进入休眠 sleep_run_from_xosc(); }6. 外壳设计与成品展示一个精心设计的外壳能让项目更加完整。可以使用3D打印制作一个适合的支架或者改造现有的小相框。考虑以下设计要点为屏幕设计合适的视窗开口预留USB接口和调节旋钮的位置考虑散热和防尘底部增加防滑垫如果想让设备更加个性化可以在LVGL界面中添加自定义背景图片日期时间显示温度监测通过Pico的内部温度传感器主题切换功能// 添加背景图片 LV_IMG_DECLARE(background_img); lv_obj_t *img lv_img_create(lv_scr_act(), NULL); lv_img_set_src(img, background_img); lv_obj_move_background(img); // 将图片移到最底层在实际项目中我发现将屏幕刷新率控制在30-60FPS之间既能保证流畅度又不会给处理器带来太大负担。另外使用双缓冲技术可以有效减少屏幕闪烁// 在lv_conf.h中启用双缓冲 #define LV_DISP_DOUBLE_BUFFER 1 #define LV_DISP_BUF_SIZE (240 * 320 / 10) // 根据内存调整

更多文章