483|2

53

帖子

4

TA的资源

一粒金砂(高级)

楼主
 

【Beetle ESP32 C6迷你开发板】 网络弹幕点阵时钟的实现 [复制链接]

 
本帖最后由 MioChan 于 2024-5-31 12:53 编辑

本帖主要介绍基于Beetle ESP32-C6 的网络弹幕点阵时钟的代码实现

TCP接受字符串请求的API服务器以及NTP服务授时的实现代码也可以参考上一帖

本来想使用64x32的LED点阵屏幕,但因为这个板子的引脚比较少,试了就算全用上也不太够,但我想到可以不做RGB屏只使用其中一个颜色实现单色不就好了,但写完代码开始编译的时候发现常用的那几个驱动点阵屏的库在这个目标开发板上编译都会各种报错,实在没找到啥好办法,国内外论坛也没有用这种迷你开发版驱动这个屏幕的例子,奈何能力不够,所以退而求其次,我们使用MAX7219 四合一模块,大概17元。然后使用下面两个库来驱动。

#include <MD_Parola.h>
#include <MD_MAX72xx.h>

代码中点阵字体部分参考了M5stack悬浮点阵时钟这个项目,原项目给的是镜像后的字体,本项目将其变成了正像,代码直接在Arduino IDE中安装好必要的库后即可编译烧录。

 

屏幕可以直接安装下面的定义连到这5个引脚

#define MAX_DEVICES 4
#define CS_PIN 5
#define CLK_PIN 23
#define Din_PIN 4

 

 

代码整体结构比较简单,里面也有注释,有问题可以直接帖子里交流

#include <WiFi.h>
#include <NTPClient.h>
#include <ArduinoJson.h>
#include <NetworkUdp.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

//配网及其引脚定义
const int led = 15;
const char* ssid = "XXXX";
const char* password = "XXXX";

int status = WL_IDLE_STATUS;
String receivedContent = "";

const int timeZone = 8; 
const char* ntpServer = "pool.ntp.org";
NetworkUDP udp;
WiFiServer server(80);
NTPClient timeClient(udp,ntpServer, timeZone * 3600, 60000);



#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#define CS_PIN 5
#define CLK_PIN 23
#define Din_PIN 4


//用于驱动点阵屏显示
MD_Parola Display = MD_Parola(HARDWARE_TYPE,Din_PIN,CLK_PIN, CS_PIN, MAX_DEVICES);
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE,Din_PIN,CLK_PIN, CS_PIN, MAX_DEVICES);


void setup() {
  Display.begin();
  mx.begin();

  Display.setIntensity(3);//设置亮度,0为最亮
  Display.displayClear();
  Display.setTextAlignment(PA_CENTER);//字体居中显示

  Serial.begin(9600);

   pinMode(led, OUTPUT);
  digitalWrite(led, 0);
  
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

 


  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    
  }

   Display.print("Connected");



  timeClient.begin();
  timeClient.update();

    server.begin();

  Display.displayClear();


}
//定义点阵字符
//Small_font_0-10 分别为0-10数字以及:
//uint8_t clock_0-7 表示秒针位置指示
//sun moon为太阳和月亮的图形
uint8_t Small_font_0[] = {0x3E, 0x22, 0x3E};
uint8_t Small_font_1[] = {0x24, 0x3E, 0x20};
uint8_t Small_font_2[] = {0x3A, 0x2A, 0x2E}; 
uint8_t Small_font_3[] = {0x2A, 0x2A, 0x3E}; 
uint8_t Small_font_4[] = {0x0E, 0x8, 0x3E};
uint8_t Small_font_5[] = {0x2E, 0x2A, 0x3A}; 
uint8_t Small_font_6[] = {0x3A, 0x2A, 0x3E}; 
uint8_t Small_font_7[] = {0x02, 0x02, 0x3E};  
uint8_t Small_font_8[] = {0x3E, 0x2A, 0x3E}; 
uint8_t Small_font_9[] = {0x2E, 0x2A, 0x3E}; 
uint8_t Small_font_10[] = {0x14};
uint8_t clock_0[] = {0x1C, 0x22, 0x2E, 0x22, 0x1C};
uint8_t clock_1[] = {0x1C, 0x22, 0x2A, 0x26, 0x1C};
uint8_t clock_2[] = {0x1C, 0x22, 0x2A, 0x2A, 0x1C};
uint8_t clock_3[] = {0x1C, 0x22, 0x2A, 0x32, 0x1C};
uint8_t clock_4[] = {0x1C, 0x22, 0x3A, 0x22, 0x1C};
uint8_t clock_5[] = {0x1C, 0x32, 0x2A, 0x22, 0x1C};
uint8_t clock_6[] = {0x1C, 0x2A, 0x2A, 0x22, 0x1C};
uint8_t clock_7[] = {0x1C, 0x26, 0x2A, 0x22, 0x1C};

uint8_t sun[] = {0x24, 0x00, 0xbd, 0x3c, 0x3c, 0xbd, 0x00, 0x24};
uint8_t moon[] = {0x1c, 0x3e, 0x47, 0x03, 0x23, 0x72, 0x24, 0x00};

uint8_t * bitmap_data[] = {
 Small_font_0,
 Small_font_1,
 Small_font_2,
 Small_font_3,
 Small_font_4,
 Small_font_5,
 Small_font_6,
 Small_font_7,
 Small_font_8,
 Small_font_9,
 Small_font_10,
 clock_0,
 clock_1,
 clock_2,
 clock_3,
 clock_4,
 clock_5,
 clock_6,
 clock_7,
 sun,
 moon
};


//用于在点阵上绘制bitmap
void display_bitmap(int abscissa, int width, int bitmap_number) {
  mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
  mx.setBuffer(abscissa, width, bitmap_data[bitmap_number]);
  mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
}

//用于绘制水平横线
void drawHorizontalLine(int y, int x_start, int x_end,bool pixel) {
 mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
  for (int x = x_start; x <= x_end; x++) {
    mx.setPoint(y, x,  pixel);  
    delay(10);
  }
  mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
}

//检测是否有设备Post字符串
void checkForNewClient() {
  WiFiClient client = server.available();
  if (client) {
    Serial.println("New client");
    digitalWrite(led, 1);

    // Read the first line of the request
    String firstLine = client.readStringUntil('\n');

    // Check if this is a POST request
    if (firstLine.startsWith("POST")) {
      // Read the headers and find the Content-Length
      int contentLength = -1;
      while (client.connected()) {
        String line = client.readStringUntil('\n');
        if (line.startsWith("Content-Length:")) {
          contentLength = line.substring(15).toInt();
        }

        // Check if the end of headers is reached (empty line)
        if (line == "\r") {
          break;
        }
      }

      // Read the request body
      if (contentLength > 0) {
        String requestBody = client.readStringUntil('\n');

        // Parse JSON from the request body
        DynamicJsonDocument doc(1024);
        deserializeJson(doc, requestBody);

        String content = doc["content"];
        if (content != "") {
          Serial.println("Received content: " + content);
          receivedContent =content;  // Update the received string
        } else {
          Serial.println("No content received");
        }
      }
    }
    digitalWrite(led,0);
    // Send response to the client
    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/plain");
    client.println("Connection: close");
    client.println();
    client.println("Response sent");
    client.stop();
    Serial.println("Client disconnected");
  }
}

int hours;
int minutes ;
int seconds;
String times;
int Clock_variable = 11;

unsigned long startTime;  
const unsigned long runDuration = 10000;  

void loop() {

times=timeClient.getFormattedTime();
hours = times.substring(0, 2).toInt();
minutes = times.substring(3, 5).toInt();
seconds = times.substring(6, 8).toInt();
if (minutes%30 ==0 )  timeClient.update();


checkForNewClient(); 


if (receivedContent=="")
{

display_bitmap(22, 3, hours/ 10);
display_bitmap(18, 3, hours % 10);
display_bitmap(14, 1, 10);
display_bitmap(12, 3, minutes / 10);
display_bitmap(8, 3, minutes % 10);

display_bitmap(4, 5, seconds/8 +11);

if (seconds==0) drawHorizontalLine(7, 0,23,false);

if ((hours >= 6) && (hours <= 18)) {
  display_bitmap(31, 8, 19);
} else {
  display_bitmap(31, 8, 20);
}
// drawHorizontalLine(7,  (23 - seconds / 10),23,true);
// drawHorizontalLine(7, (15 - seconds % 10),15,true);

startTime = millis();
delay(2000);
}
else
{

 if (Display.displayAnimate()) {
    Display.displayScroll(receivedContent.c_str(), PA_LEFT, PA_SCROLL_LEFT, 50);//滚动显示文字

    if (millis() - startTime >= runDuration) 
   {
    Display.displayClear();  // 清除显示
   receivedContent="";
  }

  }

}

}

 

下面是实际的效果,不过这样的话感觉比较难看,我们还是打印个壳子顺便给屏幕加上柔光板。

 

测量好尺寸,画个外壳

   

 

直接用Bambu Studio切片并打印,3mf文件放在附件了有需要可以自取

 

最终实物的效果,因为我板子已经焊了排针,放不进去只能外挂了,当时设计的时候已经考虑了板子、电池和typec口的位置,没有排针的话板子直接放屏幕后面,焊条线连上就可以了

 

当时钟接受到其他设备的文本Post请求后,会自动开始播放弹幕,下面是文字弹幕的效果(我这里投的是Hello EEWorld),文字会从左向右滚动显示,播放几秒后会再次进入时钟模式。

弹幕投送直接用ios的快捷指令就能实现,详细解释之前那一帖以及说明。

 

 

到此,我们这个小时钟就制作完毕啦

外壳.3mf

26.03 KB, 下载次数: 0

最新回复

总结了一下,大概这么几步 硬件连接,将点阵显示屏连接到ESP32开发板的相应引脚上。 网络配置,配置ESP32连接到Wi-Fi网络 时间获取,用网络API,从互联网获取当前时间。 弹幕实现,编写代码实现弹幕滚动效果 用点阵屏库来控制LED点阵的显示,包括亮度、颜色和显示内容 优化和需要优化代码,调整弹幕的速度和显示效果。 外壳     详情 回复 发表于 2024-6-2 08:52
点赞 关注(1)
 
 

回复
举报

6587

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

总结了一下,大概这么几步

硬件连接,将点阵显示屏连接到ESP32开发板的相应引脚上。
网络配置,配置ESP32连接到Wi-Fi网络
时间获取,用网络API,从互联网获取当前时间。
弹幕实现,编写代码实现弹幕滚动效果
用点阵屏库来控制LED点阵的显示,包括亮度、颜色和显示内容
优化和需要优化代码,调整弹幕的速度和显示效果。
外壳
 

 
 
 

回复

53

帖子

4

TA的资源

一粒金砂(高级)

板凳
 
Jacktang 发表于 2024-6-2 08:52 总结了一下,大概这么几步 硬件连接,将点阵显示屏连接到ESP32开发板的相应引脚上。 网络配置,配置ESP ...

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表