RP2040-ETH-DVI-ZERO:Adafruit IO 仪表板监视器( HDMI / DVI 模式)

新开发的Raspberry Pi RP2040开发板,带有DVI接口和以太网。该项目可以显示 adafruit IO 仪表板并跟踪任何更改。

转发: RP2040-ETH-DVI-ZERO: Adafruit IO Dashboard Monitor ( HDMI / DVI Mode )

Surf5 Design Contest


项目介绍

我新开发了一块Raspberry Pi RP2040开发板,具有DVI/HDMI输出接口,使用W5100S作为网络接入,并具有TF卡插槽。我将这款开发板命名为“RP2040-ETH-DVI-ZERO”。

据我所知,RP2040-ETH-DVI-ZERO是第一款具有网络功能的RP2040 DVI开发板。

RP2040-ETH-DVI-ZERO采用与Raspberry Pi ZERO W官方相同的外部尺寸和接口设计,RP2040-ETH-DVI-ZERO可以使用Raspberry Pi ZERO W官方外壳。

RP2040-ETH-DVI-ZERO可以同时进行网络通信和图像DVI输出显示。

可以生成320*240分辨率的图像,并通过扩展至640*480(60Hz)输出到显示器

为什么要开发 RP2040-ETH-DVI-ZERO?

市面上有很多带DVI接口的RP2040开发板,但均不具备网络通信功能。由于PICO W的无线通讯部分占用大量动态内存,DVI输出功能无法与网络功能同时使用,或者其使用受到很大限制。因为使用W5100S可以让网络通信只使用少量的动态内存,所以我开发了RP2040-ETH-DVI-ZERO和项目。

这只是 W5100S 使用的动态内存的 2%。 

这是 PICO W 使用的动态内存的 25%,对比相当明显。

RP2040-DVI-ETH-ZERO 硬件:

顶视图:

底视图:

我对W5100S部分使用与W5100S_EVB_PICO相同的引脚设计,因此我可以使用W5100S_EVB_PICO的所有参考代码。

该项目的名称是“Adafruit IO Dashboard Monitor”。我的想法是为 adafruit.io 开发一个通用的仪表板显示界面。所有显示内容均从adafruit.io获取,包括显示adafruit.io的dashboard框架并解析dashboard中包含的所有Block,自动订阅dashboard中包含的所有“feed”内容,并通过DVI输出到显示器。

因为是通用的显示框架,所以我在程序中没有定义任何固定的参数。所有参数都是通过Adafruit.io获取的,包括显示框架。

因为没有固定的参数,所以我们在第一次开机的时候需要通过内嵌的网页输入adafruit的访问参数。

RP2040-ETH-DVI-ZERO的屏幕显示:

通过浏览嵌入式网页输入三个参数,即 adafruit 的名称、密钥和仪表板 id。

通过浏览嵌入式网页输入三个参数,即 adafruit 的名称、密钥和仪表板 id。点击“提交”后,将被存储到RP2040内部的Flash中。下次打开RP2040-ETH-DVI-ZERO时,将跳过从浏览器获取参数的步骤,直接运行“获取adafruit仪表板”。

该嵌入网页的HTML代码:

#ifndef PROGMEM
#define PROGMEM
#endif

const char html_page[] PROGMEM = {
    "HTTP/1.1 200 OK\r\n"
    "Content-Type: text/html\r\n"
    "Connection: close\r\n"  // the connection will be closed after completion of the response
    //"Refresh: 5\r\n"         // refresh the page automatically every n sec
    "\r\n"
    "<!DOCTYPE HTML>"
    "<html>"
    "<head>"
      "<meta charset='UTF-8'>"
      "<title>RP2040-DVI-ETH-ZERO : adafruit io monitor</title>"  
      "<link rel='icon' href='https://cdn-learn.adafruit.com/guides/images/000/000/570/medium800/AIO_LOGO.png' type='image/x-icon'>"
    "</head>"
    "<body>"
    "<p style='text-align:center;'>"
    "<img alt='ChatGPT' src='https://cdn-learn.adafruit.com/guides/images/000/000/570/medium800/AIO_LOGO.png' height='200' width='200'>"
    "<h1 align='center'>RP2040-DVI-ETH-ZERO</h1>" 
    "<h1 align='center'>adafruit io monitor</h1>" 
    "<div style='width:900px;margin: 0 auto;text-align: center'>"
    "<form action='/' method='post'>"
    "<input type='text' placeholder='adafruit io user' size='35' name='adafruit_user' required='required'/><br><br>"
    "<input type='text' placeholder='adafruit io key' size='35' name='adafruit_key' required='required'/><br><br>"
    "<input type='text' placeholder='adafruit io dashboard key' size='35' name='dashboard_key' required='required'/><br><br>"
    "<input type='submit' value='Submit' style='height:30px; width:80px;'/>"
    "</form>"
    "<div style='text-align: left;'>"
    "<h5>"
    "</h5>\r\n" 
    "</div>"
    "</div>"
    "</body>\r\n"
    "<html>\r\n"
};

获取adafruit.io的仪表板,我们可以得到屏幕上需要显示的所有框架的布局,包括所有块信息、位置、大小、对应的Feeds和Groups。

#define dashboard_layout_max 16
struct _Dashboard_Layout{
  boolean exist = false;
  uint8_t x;
  uint8_t y;
  uint8_t x_size;
  uint8_t y_size;
  String id;
};
_Dashboard_Layout dashboard_layout[dashboard_layout_max];

这是仪表板“RP2040-DVI-ETH-ZERO”的 Adafruit io 网络版本。

A_1_temp (W5100S_POE_EVB_PICO)
A_2_温度(W5100S_EVB_PICO)
A_3_temp (W5100S_EVB_PICO)
A_4_温度(W5500_EVB_PICO)
四块 PICO 板每 10 秒将这些内置温度传感器数据上传到 adafruit.io。

(因为我使用的是Adafruit的免费服务,所以通讯次数有限制)

这是我获取仪表板信息并重构显示框架后的仪表板。

在解析仪表板消息时,我们还获取了所有相关的 Feed 和 Group 信息。代码会自动订阅所有的Feed和Group,并将它们放入消息回调处理函数中。

#define dashboard_block_max 16
struct _Dashboard_block{
  boolean exist = false;
  String id;
  String name;
  String type;
  String label;
  uint16_t minValue;
  uint16_t maxValue;
  uint16_t minWarning;
  uint16_t maxWarning;
  uint8_t decimal;
  String feed_id;
  String feed_key;
  String feed_name;
  String group_key;
};
_Dashboard_block dashboard_block[dashboard_block_max];

消息回调处理代码:

// you can also attach multiple feeds to the same
// meesage handler function. both counter and counter-two
// are attached to this callback function, and messages
// for both will be received by this function.
void feed_handle(AdafruitIO_Data *data) {
  Serial.print("received <- ");
  // since we are using the same function to handle
  // messages for two feeds, we can use feedName() in
  // order to find out which feed the message came from.
  Serial.print(data->feedName());
  Serial.print(" ");
  // print out the received count or counter-two value
  Serial.println(data->value()); 
  
  for(int i=0; i<dashboard_block_max; i++)
  {
    String Feed_data_decimal;
    if(dashboard_block[i].feed_key == data->feedName())
    {
      display.setTextColor(DashBoard_Text_Color); 
      
      std::string Feed_data_decimal(data->value());
      if(Feed_data_decimal.find('.')!= -1)
      {        
        Feed_data_decimal = (Feed_data_decimal.substr(0,Feed_data_decimal.find('.')+1+dashboard_block[i].decimal));
        Serial.println(Feed_data_decimal.c_str()); 
      }
      if(dashboard_block[i].type == "slider")
      {        
        display.fillRoundRect(dashboard_layout[i].x*20+4,dashboard_layout[i].y*20+2+_y+dashboard_layout[i].y_size*20-16,dashboard_layout[i].x_size*20-8,10,3,DashBoard_Back_Color);
        display.fillRoundRect(dashboard_layout[i].x*20+5,dashboard_layout[i].y*20+2+_y+dashboard_layout[i].y_size*20-15,dashboard_layout[i].x_size*20-10,8,3,adafruit_grey);        
        uint16_t slider_point = (atoi(data->value()))*(dashboard_layout[i].x_size*20-10)/100;

        display.fillRoundRect(dashboard_layout[i].x*20+5,dashboard_layout[i].y*20+2+_y+dashboard_layout[i].y_size*20-15,slider_point,8,3,DashBoard_Bar_Color);
        display.fillRect(dashboard_layout[i].x*20+dashboard_layout[i].x_size*10-7,dashboard_layout[i].y*20+4+_y+10,30,10,DashBoard_Back_Color);
        display.setTextSize(1);
        display.setCursor(dashboard_layout[i].x*20+dashboard_layout[i].x_size*10-7,dashboard_layout[i].y*20+4+_y+10);
        display.println(atoi(data->value()));
       
      }
      else if(dashboard_block[i].type == "gauge")
      {
display.fillArc(dashboard_layout[i].x*20+dashboard_layout[i].x_size*10,dashboard_layout[i].y*20+4+_y+40, 24, 30, 105, 75, DashBoard_Bar_Back_Color); 
        display.setCursor(dashboard_layout[i].x*20 + 13, dashboard_layout[i].y*20 + _y + dashboard_layout[i].y_size*20 - 12);
        display.println(dashboard_block[i].minValue);
        display.setCursor(dashboard_layout[i].x*20 + dashboard_layout[i].x_size*20 -18 , dashboard_layout[i].y*20 + _y + dashboard_layout[i].y_size*20 - 12);
        display.println(dashboard_block[i].maxValue); 
        display.setCursor(dashboard_layout[i].x*20+dashboard_layout[i].x_size*10, dashboard_layout[i].y*20+4+_y+48);

        if((atoi(data->value()) <= dashboard_block[i].minWarning)||(atoi(data->value()) >= dashboard_block[i].maxWarning))
        {          
display.fillArc(dashboard_layout[i].x*20+dashboard_layout[i].x_size*10,dashboard_layout[i].y*20+4+_y+40, 24, 30, 105, 105+ (atoi(data->value()) * 330 / 100), adafruit_red);   
          DashBoard_warning = dashboard_block[i].maxWarning * 330 / 100;
display.fillArc(dashboard_layout[i].x*20+dashboard_layout[i].x_size*10,dashboard_layout[i].y*20+4+_y+40, 24, 30, 105+DashBoard_warning-1, 105+DashBoard_warning, BLACK);
        }
        else
        {
display.fillArc(dashboard_layout[i].x*20+dashboard_layout[i].x_size*10,dashboard_layout[i].y*20+4+_y+40, 24, 30, 105, 105+ (atoi(data->value()) * 330 / 100), DashBoard_Bar_Color); 
          DashBoard_warning = dashboard_block[i].maxWarning * 330 / 100;          display.fillArc(dashboard_layout[i].x*20+dashboard_layout[i].x_size*10,dashboard_layout[i].y*20+4+_y+40, 24, 30, 105+DashBoard_warning-1, 105+DashBoard_warning, adafruit_red);          
        }
        display.fillRect(dashboard_layout[i].x*20+dashboard_layout[i].x_size*10-11,dashboard_layout[i].y*20+4+_y+30,30,10,DashBoard_Back_Color);
        
        display.setTextSize(1);
        display.setCursor(dashboard_layout[i].x*20+dashboard_layout[i].x_size*10-11,dashboard_layout[i].y*20+4+_y+30);
        display.println(Feed_data_decimal.c_str());
      }
    }    
  }
}

将Feed和Group消息数据更新到显示屏后,效果如下:

由于该项目没有使用固定的显示参数,因此可以随着仪表板网页版的页面布局的任何变化而更改后续。

编辑布局后并保存。

那么RP2040-ETH-DVI-ZERO的显示界面也会相应改变显示布局。

仪表盘中包含了各个区块的警告值信息,显示界面也会根据警告值的不同显示不同。

我人为地提高了A_4_temp(W5500_EVB_PICO)的温度,您可以在屏幕上看到一条警告消息。

而且,显示界面的深色模式和浅色模式也会自动切换。

灯光模式视图:

我使用Arduino开发它,这些是该项目中使用的所有库:

#include <AdafruitIO_Ethernet.h>
#include <SPI.h>
#include <EEPROM.h>
#include <Ethernet.h>
#include <LittleFS.h>
#include <SD.h>
#include <PicoDVI.h>                 
#include <Arduino_GFX_Library.h>
#include "html.h"
#include "icon.h"
#include <PNGdec.h>
#include <iostream>
#include <string> 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值