嵌入式产品级-超小尺寸热成像相机(从0到1 硬件-软件-外壳)

Thermal_Imaging_Camera 
This is a small thermal imaging camera that includes everything from hardware and software.

小尺寸热成像相机-Pico-LVGL-RTOS

基于RP2040 Pico主控与RTOS,榨干双核性能实现LVGL和成图任务并行。ST7789驱动240×280屏,CST816T触摸IC,MLX90640传感器实现热成像功能。充电采用SGM4056,DC-DC使用SGM6031等等。

产品描述:树莓派RP204 Pico, 双核 LVGL RTOS,合理分配热成像呈现内容,UI画面的更新反馈。

探头既可支持长焦的BAB款,支持广角的BAA款,MCU + ST7789屏幕(240 * 280)+ CST816T 触摸IC + MLX90640热成像传感器 + 充电采用SGM4056,DC-DC使用SGM6031等等。

ui类似Apple Watch,按键1开启ui,支持卡尔曼滤波、插值切换、7种显示色彩和温度,折线图,电池电量。按键2拍照,触摸屏显示任意位置温度不限个数,支持调光。

传统热成像设备的痛点

  • 价格昂贵:大多数热成像设备由于采用高端传感器和复杂的硬件设计,导致成本高昂。
  • 体积较大:便携性较差,限制了其在移动应用或小型设备中的应用。
  • 开发门槛高:传统设备通常依赖复杂的嵌入式系统,难以快速定制化开发。

用户需求

  • 对于消费者和开发者而言,市场需要一种低成本、小尺寸、易用的热成像解决方案,同时具备良好的图像质量和功能拓展性。

产品优势

  • 低成本实现

    • 通过使用 RP2040 Pico 和 MLX90640 这类性价比高的硬件组合,实现了功能的最大化。
    • 使用开源的 LVGL 图形库,避免高额商业软件授权费用。
  • 小尺寸设计

    • 紧凑的硬件结构使设备便于携带和嵌入其他系统,例如无人机、手持设备等场景。
  • 高性能多任务

    • 基于 RTOS 实现多任务调度,充分利用 RP2040 的双核性能,在图像处理和触摸交互中保持流畅性能。
  • 高扩展性

    • 支持通过触摸屏实现用户交互(例如温度调节、热图切换)。
    • 支持电池供电,搭配 SGM4056 和 SGM6031 提供高效的电源管理。

项目包含下述内容

  • 硬件部分、PCB制板、BOM表文件等等 (Hardware)
  • 软件程序、用于RP2040软件程序以及LVGL UI等等(Software)
  • 上位机(UpperComputerQT上位机 待更新!
  • 二次开发方案
  • 技术支持、全项目内容答疑
  • 项目持续更新中(任何问题和想法 功能都可以跟我提,我会慢慢跟进解决

功能图例

下图为用户配置设置界面,你可以设置配置你想要的参数,例如是否插值,是否启用卡尔曼滤波,色彩选择等。

下图是温度折线图界面,左滑即可。

下图为电源状态管理界面,右滑即可。

下图为相机状态,也就是捕捉热源成像。

下述就是不同色彩呈现的图示了。

更多内容附在资料包中~

代码部分如下所示:展示部分。

void my_disp_flush( lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p )
{
    uint32_t w = ( area->x2 - area->x1 + 1 );
    uint32_t h = ( area->y2 - area->y1 + 1 );

    tft.startWrite();
    #if (ROTATE == 0 || ROTATE == 2)
    tft.setAddrWindow( area->x1, area->y1, w, h );
    #endif
    #if (ROTATE == 1 || ROTATE == 3)
    tft.setAddrWindow( area->x1, area->y1, w, h );
    #endif
    tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
    tft.endWrite();

    lv_disp_flush_ready( disp_drv );
}

/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * indev_drv, lv_indev_data_t * data )
{

    touch.update();
    // Serial.print( "touch called " );
    // Serial.println( touch.tp.touching );
    bool touched = touch.tp.touching;
    if( !touched )
    // if( 0!=touch.data.points )
    {
        data->state = LV_INDEV_STATE_REL;
    }
    else
    {
        data->state = LV_INDEV_STATE_PR;
        #if (ROTATE == 0)
        /*Change to your screen resolution*/
        data->point.x = touch.tp.x;
        data->point.y = touch.tp.y;
        #endif
        #if (ROTATE == 1)
        /*Change to your screen resolution*/
        data->point.x = touch.tp.y;
        data->point.y = 240-touch.tp.x;
        #endif
        #if (ROTATE == 2)
        /*Change to your screen resolution*/
        data->point.x = 240-touch.tp.x;
        data->point.y = 280-touch.tp.y;
        #endif

        #if (ROTATE == 3)
        data->point.x = 280-touch.tp.y;
        data->point.y = touch.tp.x;
        #endif
        // data->point.x = touch.tp.x;
        // data->point.y = touch.tp.y;
        // Serial.print( "Data x " );
        // Serial.println( touch.tp.x );

        // Serial.print( "Data y " );
        // Serial.println( touch.tp.y );  
    }
}

// 按键输入设备读取回调函数
void my_keypad_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
    int button_state = digitalRead(24);  // 读取按键的状态,假设按键接地为 LOW
    if (button_state == LOW) {
        // 如果按键按下,记录开始按下的时间
        if (btn2_pushed_start_time == 0) {
            btn2_pushed_start_time = millis();
        }
        // 检测是否为长按
        if (millis() - btn2_pushed_start_time >= BTN_LONG_PUSH_T) {
            if (!btn2_long_pushed) {
                btn2_long_pushed = true;  // 标记为长按
                // 长按的处理,例如切换到不同屏幕
                
            }
        }
        data->state = LV_INDEV_STATE_PRESSED;  // 按键按下
    } else {
        // 按键松开,判断是否为短按
        if (btn2_pushed_start_time != 0) {
            if (!btn2_long_pushed) {
                btn2_pushed = true;  // 短按标记
                // 短按的处理,例如切换到不同屏幕
                if (!btn2_long_pushed){freeze = !freeze; } //切换 freeze 状态
            }
            btn2_pushed_start_time = 0;  // 重置按下时间
        }
        // 清除长按标记
        btn2_long_pushed = false;
        data->state = LV_INDEV_STATE_RELEASED;  // 按键松开
    }
}

void my_keypad_bootsel_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
    if (BOOTSEL) {
        // 如果按键按下,记录开始按下的时间
        if (btn1_pushed_start_time == 0) {
            btn1_pushed_start_time = millis();
        }
        // 检测是否为长按
        if (millis() - btn1_pushed_start_time >= BTN_LONG_PUSH_T) {
            if (!btn1_long_pushed) {
                btn1_long_pushed = true;  // 标记为长按
                // 长按的处理,例如切换到不同屏幕
                _ui_screen_change(&ui_Screen3, LV_SCR_LOAD_ANIM_FADE_ON, 500, 0, &ui_Screen3_screen_init);
            }
        }
        data->state = LV_INDEV_STATE_PRESSED;  // 按键按下
    } else {
        // 按键松开,判断是否为短按
        if (btn1_pushed_start_time != 0) {
            if (!btn1_long_pushed) {
                btn1_pushed = true;  // 短按标记
                // 短按的处理,例如切换到不同屏幕
                user_ui_flag = !user_ui_flag;
                if(user_ui_flag){
                  test_points[0][0] = 0; // 重置测试点数据
                  test_points[0][1] = 0;
                  _ui_screen_change(&ui_Screen2, LV_SCR_LOAD_ANIM_FADE_ON, 500, 0, &ui_Screen2_screen_init);
                } else {
                  _ui_screen_change(&ui_Screen1, LV_SCR_LOAD_ANIM_FADE_ON, 0, 0, &ui_Screen1_screen_init);
                }
            }
            btn1_pushed_start_time = 0;  // 重置按下时间
        }
        // 清除长按标记
        btn1_long_pushed = false;
        data->state = LV_INDEV_STATE_RELEASED;  // 按键松开
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/959317.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springfox-swagger-ui 3.0.0 配置

在3.0中&#xff0c;访问地址URL变了。 http://地址:端口/项目名/swagger-ui/ SpringBoot maven项目引入 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>3.0.0</version> </…

【0x03】HCI_Connection_Complete事件详解

目录 一、事件概述 二、事件格式及参数详解 2.1. HCI_Connection_Complete事件格式 2.2. 事件参数 2.2.1. Status 2.2.2. Connection_Handle 2.2.3. BD_ADDR 2.2.4. Link_Type 2.2.5. Encryption_Enabled 三、事件处理流程 3.1. 事件触发 3.2. 事件接收与解析 3.…

PCI 总线学习笔记(三)

PCI 总线学习系列&#xff0c;参考自 技术大牛博客&#xff1a; PCIe 扫盲系列博文连载目录篇 书籍&#xff1a;王齐老师的《PCI Express 体系结构导读》 下面的文章中加入了自己的一些理解和实际使用中遇到的一些场景&#xff0c;供日后查询和回忆使用 阅读本篇文章前&#x…

麒麟操作系统基础知识保姆级教程(二十一)进入单用户模式

如果你想拥有你从未拥有过的东西&#xff0c;那么你必须去做你从未做过的事情 在咱们运维工作中&#xff0c;服务器的密码长度&#xff0c;密码复杂度&#xff0c;修改时间&#xff0c;超时时间&#xff0c;用户权限管理&#xff0c;root直接远程连接&#xff0c;普通用户su到r…

ARM64平台Flutter环境搭建

ARM64平台Flutter环境搭建 Flutter简介问题背景搭建步骤1. 安装ARM64 Android Studio2. 安装Oracle的JDK3. 安装 Dart和 Flutter 开发插件4. 安装 Android SDK5. 安装 Flutter SDK6. 同意 Android 条款7. 运行 Flutter 示例项目8. 修正 aapt2 报错9. 修正 CMake 报错10. 修正 N…

OpenCV:高通滤波之索贝尔、沙尔和拉普拉斯

目录 简述 什么是高通滤波&#xff1f; 高通滤波的概念 应用场景 索贝尔算子 算子公式 实现代码 特点 沙尔算子 算子公式 实现代码 特点 拉普拉斯算子 算子公式 实现代码 特点 高通滤波器的对比与应用场景 相关阅读 OpenCV&#xff1a;图像滤波、卷积与卷积核…

VS企业版和专业版的区别

网上查询vs分析dump文件&#xff0c;查找托管内存泄露&#xff0c;需要使用“调试托管内存”功能&#xff0c;当前安装的vs2022 专用版找不到这个选项&#xff0c;vs2015是ok的&#xff0c;比较版本发现2022是专业版&#xff0c;2015是企业版。网上搜索专业版和企业版差异如下&…

ESP8266 NodeMCU与WS2812灯带:实现多种花样变换

在现代电子创意项目中&#xff0c;LED灯带的应用已经变得极为广泛。通过结合ESP8266 NodeMCU的强大处理能力和FastLED库的高效功能&#xff0c;我们可以轻松实现多达100种灯带变换效果。本文将详细介绍如何使用Arduino IDE编程&#xff0c;实现从基础到高级的灯光效果&#xff…

技术 · 创作 · 生活 | 我的 2024 全面复盘

目录 &#x1f31f;2024年度总结&#xff1a;回顾、成长与突破&#x1f31f;&#x1f680; 一、技术成长与突破 &#x1f680;&#x1f517; 1. 深入区块链与智能合约&#x1f50d; 2. 探索新兴技术 ✍️ 二、创作与博客历程 ✍️&#x1f4d6; 1. 内容创作的演变&#x1f3c6;…

嵌入式MCU面试笔记2

目录 串口通信 概论 原理 配置 HAL库代码 1. 初始化函数 2. 数据发送和接收函数 3. 中断和DMA函数 4. 中断服务函数 串口通信 概论 我们知道&#xff0c;通信桥接了两个设备之间的交流。一个经典的例子就是使用串口通信交换上位机和单片机之间的数据。 比较常见的串…

LeetCode --- 433周赛

题目列表 3427. 变长子数组求和 3428. 最多 K 个元素的子序列的最值之和 3429. 粉刷房子 IV 3430. 最多 K 个元素的子数组的最值之和 一、变长子数组求和 题意要求我们能快速算出 n u m s [ s t a r t . . . i ] nums[start...i] nums[start...i] 这段区间和&#xff0c;其中…

EasyNVR免费版已发布!EasyNVR接入海康NVR大华NVR宇视NVR天地伟业NVR接入各种IPC摄像机工业监控家庭监控

EasyNVR不用多说了&#xff0c;驰名已久&#xff01;之前一直是收费的&#xff0c;不管多少个摄像机接入都是收费的&#xff0c;这就导致&#xff0c;很多个人用户&#xff0c;或者说是家庭用户&#xff0c;家里就那么两三个摄像机&#xff0c;想通过EasyNVR接入NAS系统&#x…

任务一:Android逆向

首先我使用了一个叫objection的东西。 列出了他所有的活动界面,列出来之后在慢慢筛选。 然后用了一个命令,就是可以跳到这个活动界面的命令。 我就确定了这个活动界面的位置,然后我就采取了objection的另一种栈追踪。 追踪到了这个地方。 先打印出具有特征参数的值,在…

黑龙江锅包肉:酸甜香酥的东北经典

黑龙江锅包肉:酸甜香酥的东北经典 黑龙江锅包肉,作为东北菜的代表之一,尤其在黑龙江省哈尔滨市享有极高的声誉。这道美食不仅承载着丰富的历史文化内涵,更以其鲜明的地域特色,成为了黑龙江省乃至整个东北地区的标志性菜肴。 历史渊源 锅包肉的历史可以追溯到清朝光绪年间,其…

[JavaScript] ES6及以后版本的新特性

文章目录 箭头函数&#xff08;Arrow Functions&#xff09;为什么需要箭头函数&#xff1f;箭头函数的完整语法箭头函数中的 this实用场景 解构赋值&#xff08;Destructuring Assignment&#xff09;为什么需要解构赋值&#xff1f;数组解构赋值的完整用法对象解构赋值的完整…

ipad和macbook同步zotero文献附件失败的解决办法

背景&#xff1a;我所有的文献及其附件pdf都是在台式机&#xff08;windows系统&#xff09;&#xff0c;想要把这些文献同步到云上&#xff0c;然后再从云上同步到平板和其他笔记本电脑比如macbook。文献同步虽已成功&#xff0c;但文献附件都无法打开。 平板报错如下&#xf…

element tbas增加下拉框

使用Tabs 标签页的label插槽&#xff0c;嵌入Dropdown 下拉菜单&#xff0c;实现Tabs 标签页增加下拉切换功能 Tabs 标签页 tab-click"事件"&#xff08;这个事件当中到拥有下拉框的tab里时&#xff0c;可以存一下Dropdown 第一个菜单的id&#xff0c;实现点击到拥有…

环境变量配置与问题解决

目录 方法 配置了还是运行不了想要的东西 解决方案 为什么 解决方案 方法 方法一&#xff1a;此电脑右击-属性-相关链接-高级系统设置-环境变量&#xff08;N&#xff09;-系统变量里面找到Path-三个确定】 方法二&#xff1a;winr cmd 黑框输入sysdm.cpl&#xff0c;后面…

【C++】详细讲解继承(下)

本篇来继续说说继承。上篇可移步至【C】详细讲解继承&#xff08;上&#xff09; 1.继承与友元 友元关系不能继承 &#xff0c;也就是说基类友元不能访问派⽣类私有和保护成员。 class Student;//前置声明class Same //基类 { public:friend void Fun(const Same& p, con…

联想电脑怎么设置u盘启动_联想电脑设置u盘启动方法(支持新旧机型)

有很多网友问联想电脑怎么设置u盘启动&#xff0c;联想电脑设置u盘启动的方法有两种&#xff0c;一是通过bios进行设置。二是通过快捷方式启动进入u盘启动。但需要注意有两种引导模式是&#xff0c;一种是uefi引导&#xff0c;一种是传统的leacy引导&#xff0c;所以需要注意制…