WiFi 时钟

WiFi 时钟有很多开源项目的。但是,成品往往代码一大篇,看起来有些上头。加上有些库和环境的版本变迁,编译报错排查起来很是费劲。于是从头捋一遍,一步一步的过程,容易上手:

准备工作:

a 零件:只需要用到 ESP8266 和 OLED 各一个。

b 开发环境:arduino_1.8.19 + ESP8266_3.0.2 ,这是我当前使用的,其他高一些的应该也行,没测试

制作步骤:

1. 首先需要保证OLED能够亮起来

#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(/*默认R0,R2为旋转180°*/U8G2_R2, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 4, /* data=*/ 0);  

void setup(){
  pinMode(16,OUTPUT);digitalWrite(16,HIGH); // OLED供电
  pinMode(5,OUTPUT);digitalWrite(5,LOW);    // OLED供电    
  Serial.begin(115200);  
  u8g2.begin();
  u8g2.enableUTF8Print();                   // 启用中文显示,但库不全
  oledClockDisplay();
}

void loop(){    
}

void oledClockDisplay(){
  u8g2.clearBuffer();      
    u8g2.setCursor(0, 47);u8g2.setFont(u8g2_font_logisoso42_tr);u8g2.print("18:56");   
    u8g2.setCursor(54,35);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print("34");   
    u8g2.setCursor(0, 64);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print("2023/04/01");  
    u8g2.print("星期六");
  u8g2.sendBuffer();
}

上面的代码可以让OLED显示出一个静止的时钟,但是星期六三个汉字只有“期”能显示出来,这是因为U8G2库的原生中文字库很小,“星”、“六”这两字没有。

这个布局花了点心思,42号时能够显示全的最大号字体,把“秒”放在冒号中间,需要读秒也能看到。

#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(/*默认R0,R2为旋转180°*/U8G2_R2, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 4, /* data=*/ 0);  

const unsigned char /*星*/ xing[] U8X8_PROGMEM = {
  0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x80, 0x00, 0x88, 0x00,
  0xF8, 0x1F, 0x84, 0x00, 0x82, 0x00, 0xF8, 0x0F, 0x80, 0x00, 0x80, 0x00, 0xFE, 0x3F, 0x00, 0x00
};  
const unsigned char /*六*/ liu[] U8X8_PROGMEM = { 
  0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00,
  0x20, 0x02, 0x20, 0x04, 0x10, 0x08, 0x10, 0x10, 0x08, 0x10, 0x04, 0x20, 0x02, 0x20, 0x00, 0x00
};  

void setup(){
  pinMode(16,OUTPUT);digitalWrite(16,HIGH); // OLED供电
  pinMode(5,OUTPUT);digitalWrite(5,LOW);    // OLED供电    
  Serial.begin(115200);  
  u8g2.begin();
  u8g2.enableUTF8Print();                   // 启用中文显示,但库不全
  oledClockDisplay();
}

void loop(){    
}

void oledClockDisplay(){
  u8g2.clearBuffer();      
    u8g2.setCursor(0, 47);u8g2.setFont(u8g2_font_logisoso42_tr);u8g2.print("18:56");   
    u8g2.setCursor(54,35);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print("34");   
    u8g2.setCursor(0, 64);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print("2023/04/01");  
    u8g2.drawXBM(80, 49, 16, 16, xing);
    u8g2.setCursor(95, 63);u8g2.print("期");
    u8g2.drawXBM(111, 49, 16, 16, liu);
  u8g2.sendBuffer();
}

 u8g2.drawXBM 以图片方式显示汉字, 这样显示部分调试就算完成了。

2. 让时钟走起来

这时需要用到 TimeLib.h 这个库

#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(/*默认R0,R2为旋转180°*/U8G2_R2, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 4, /* data=*/ 0);  

const unsigned char /*星*/ xing[] U8X8_PROGMEM = {
  0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x80, 0x00, 0x88, 0x00,
  0xF8, 0x1F, 0x84, 0x00, 0x82, 0x00, 0xF8, 0x0F, 0x80, 0x00, 0x80, 0x00, 0xFE, 0x3F, 0x00, 0x00
};  
const unsigned char /*六*/ liu[] U8X8_PROGMEM = { 
  0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00,
  0x20, 0x02, 0x20, 0x04, 0x10, 0x08, 0x10, 0x10, 0x08, 0x10, 0x04, 0x20, 0x02, 0x20, 0x00, 0x00
};  

#include <TimeLib.h>
time_t currentDisplayTime = 0; 

void setup(){
  pinMode(16,OUTPUT);digitalWrite(16,HIGH); // OLED供电
  pinMode(5,OUTPUT);digitalWrite(5,LOW);    // OLED供电    
  Serial.begin(115200);  
  u8g2.begin();
  u8g2.enableUTF8Print();                   // 启用中文显示,但库不全
  oledClockDisplay();
}

void loop(){   
  if (now()!= currentDisplayTime){ 
    currentDisplayTime = now();
    oledClockDisplay();
  } 
}

void oledClockDisplay(){
  int years = year();
  int months = month();
  int days = day();
  int hours = hour();
  int minutes = minute();
  int seconds = second();
  int weekdays = weekday();
  Serial.printf("%d/%d/%d %d:%d:%d Weekday:%d\n", years, months, days, hours, minutes, seconds, weekdays);
  String currentTime = "";
    if (hours < 10)currentTime += 0;currentTime += hours;currentTime += ":";
    if (minutes < 10)currentTime += 0;currentTime += minutes;currentTime += ":";
  String currentDate = "";
    currentDate += years;currentDate += "/";
    if (months < 10)currentDate += 0;currentDate += months;currentDate += "/";
    if (days < 10)currentDate += 0;currentDate += days;
  String s="";  if (seconds < 10)s += 0;s += seconds;             // 单独把秒字符串拿出来以小字体显示在冒号处
  
  u8g2.clearBuffer();      
    u8g2.setCursor(0, 47);u8g2.setFont(u8g2_font_logisoso42_tr);u8g2.print(currentTime);   
    u8g2.setCursor(54,35);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print(s);   
    u8g2.setCursor(0, 64);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print(currentDate);  
    u8g2.drawXBM(80, 49, 16, 16, xing);
    u8g2.setCursor(95, 63);u8g2.print("期");
         if (weekdays == 1)u8g2.print("日");
    else if (weekdays == 2)u8g2.print("一");
    else if (weekdays == 3)u8g2.print("二");
    else if (weekdays == 4)u8g2.print("三");
    else if (weekdays == 5)u8g2.print("四");
    else if (weekdays == 6)u8g2.print("五");
    else if (weekdays == 7)u8g2.drawXBM(111, 49, 16, 16, liu);
  u8g2.sendBuffer();
}

 因为还没有添加对时代码,这个时钟是从1970/1/1 00:00 开始走的。

下面 利用 __TIME__ 这个常量,把PC的时钟写入到ESP8266,只要不断电,这个时钟还算不错,但要做到断电时间不停摆,需要DS1302之类的带电池的RTC模块, 不过ESP8266有WiFi,能从网络获取NTP时间。

#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(/*默认R0,R2为旋转180°*/U8G2_R2, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 4, /* data=*/ 0);  

const unsigned char /*星*/ xing[] U8X8_PROGMEM = {
  0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x80, 0x00, 0x88, 0x00,
  0xF8, 0x1F, 0x84, 0x00, 0x82, 0x00, 0xF8, 0x0F, 0x80, 0x00, 0x80, 0x00, 0xFE, 0x3F, 0x00, 0x00
};  
const unsigned char /*六*/ liu[] U8X8_PROGMEM = { 
  0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00,
  0x20, 0x02, 0x20, 0x04, 0x10, 0x08, 0x10, 0x10, 0x08, 0x10, 0x04, 0x20, 0x02, 0x20, 0x00, 0x00
};  

#include <TimeLib.h>
time_t currentDisplayTime = 0; 

void setup(){
  pinMode(16,OUTPUT);digitalWrite(16,HIGH); // OLED供电
  pinMode(5,OUTPUT);digitalWrite(5,LOW);    // OLED供电    
  Serial.begin(115200);  
  u8g2.begin();
  u8g2.enableUTF8Print();                   // 启用中文显示,但库不全
  oledClockDisplay();

  int yy = 2023;                            // 年月日可以从常量 __DATE__ 中获得,这里暂不处理,只处理时间,以演示 setTime 用法,后续用网络同步即可
  int mm = 4;  
  int dd = 19;
  int HH = (int(__TIME__[0])-48)*10 + int(__TIME__[1])-48;    // 0 的 ascii 48
  int MM = (int(__TIME__[3])-48)*10 + int(__TIME__[4])-48;
  int SS = (int(__TIME__[6])-48)*10 + int(__TIME__[7])-48;
  setTime(mktime(yy,mm,dd,HH,MM,SS)+30); 
  //setTime(1357041600);                    // 从1970-1-1开始至今的秒数 1357041600 = Jan 1 2013
  //setTime(mktime(2023,4,19,17,42,00));    // 从日期计算秒数
}

void loop(){   
  if (now()!= currentDisplayTime){ 
    currentDisplayTime = now();
    Serial.println(currentDisplayTime);    // 输出为 1681868855 这样的 Epoch 时间 https://www.epochconverter.com/
    oledClockDisplay();
  } 
}

void oledClockDisplay(){
  int years = year();
  int months = month();
  int days = day();
  int hours = hour();
  int minutes = minute();
  int seconds = second();
  int weekdays = weekday();
  Serial.printf("%d/%d/%d %d:%d:%d Weekday:%d\n", years, months, days, hours, minutes, seconds, weekdays);
  String currentTime = "";
    if (hours < 10)currentTime += 0;currentTime += hours;currentTime += ":";
    if (minutes < 10)currentTime += 0;currentTime += minutes;currentTime += ":";
  String currentDate = "";
    currentDate += years;currentDate += "/";
    if (months < 10)currentDate += 0;currentDate += months;currentDate += "/";
    if (days < 10)currentDate += 0;currentDate += days;
  String s="";  if (seconds < 10)s += 0;s += seconds;             // 单独把秒字符串拿出来以小字体显示在冒号处
  
  u8g2.clearBuffer();      
    u8g2.setCursor(0, 47);u8g2.setFont(u8g2_font_logisoso42_tr);u8g2.print(currentTime);   
    u8g2.setCursor(54,35);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print(s);   
    u8g2.setCursor(0, 64);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print(currentDate);  
    u8g2.drawXBM(80, 49, 16, 16, xing);
    u8g2.setCursor(95, 63);u8g2.print("期");
         if (weekdays == 1)u8g2.print("日");
    else if (weekdays == 2)u8g2.print("一");
    else if (weekdays == 3)u8g2.print("二");
    else if (weekdays == 4)u8g2.print("三");
    else if (weekdays == 5)u8g2.print("四");
    else if (weekdays == 6)u8g2.print("五");
    else if (weekdays == 7)u8g2.drawXBM(111, 49, 16, 16, liu);
  u8g2.sendBuffer();
}

/* ----------------- 当前到1970-1-1 的秒数 https://blog.csdn.net/weixin_46935110/article/details/124325951 ------------*/
long mktime (int year, int mon, int day, int hour, int min, int sec){
    if (0 >= (int) (mon -= 2)){mon += 12;year -= 1;} 
    return ((((unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) + year*365 - 719499)*24 + hour)*60 + min)*60 + sec; 
}

3. 网络对时

先直接上代码,注意需要修改 “WiFi.begin("SSID", "PASSWORD");” 这一行

用到了 NTPClient.h 这个库,在线对时的代码很简洁了。

整个代码里,几十行都是显示相关语句,还有几十行头文件,初始化这些固定操作,真正体现程序逻辑的是 loop 里面的3行,以及函数 getNtpTime 里面的4行, 理解起来应该很清晰了。

#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(/*默认R0,R2为旋转180°*/U8G2_R2, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 4, /* data=*/ 0);  

#include <TimeLib.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
WiFiUDP Udp;
NTPClient timeClient(Udp, "cn.pool.ntp.org"); //ntp1.aliyun.com
time_t currentDisplayTime = 0;    

const unsigned char /*星*/ xing[] U8X8_PROGMEM = {
  0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x80, 0x00, 0x88, 0x00,
  0xF8, 0x1F, 0x84, 0x00, 0x82, 0x00, 0xF8, 0x0F, 0x80, 0x00, 0x80, 0x00, 0xFE, 0x3F, 0x00, 0x00
};  
const unsigned char /*六*/ liu[] U8X8_PROGMEM = { 
  0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00,
  0x20, 0x02, 0x20, 0x04, 0x10, 0x08, 0x10, 0x10, 0x08, 0x10, 0x04, 0x20, 0x02, 0x20, 0x00, 0x00
};   

void setup(){
  pinMode(16,OUTPUT);digitalWrite(16,HIGH); // OLED供电
  pinMode(5,OUTPUT);digitalWrite(5,LOW);    // OLED供电
    
  Serial.begin(115200);
  
  u8g2.begin();
  u8g2.enableUTF8Print();                   // 启用中文显示,但库不全
  
  WiFi.begin("SSID", "PASSWORD");
  Serial.print("\n\n\nConnecting WiFi");    // ESP8266复位有很多乱码,换几行再显示
  while (WiFi.status()!= WL_CONNECTED){delay(1000);Serial.print(".");}
  Udp.begin(8888);                          // UDP 侦听端口,任意指定
  setSyncProvider(getNtpTime);
  setSyncInterval(60);                      // NTP网络同步间隔时间,单位秒
}

void loop(){
  if (now()!= currentDisplayTime){ 
    currentDisplayTime = now();
    oledClockDisplay();
  }
}

/*---------------- 刷新显示 ------------------*/
void oledClockDisplay(){
  int years = year();
  int months = month();
  int days = day();
  int hours = hour();
  int minutes = minute();
  int seconds = second();
  int weekdays = weekday();
  Serial.printf("%d/%d/%d %d:%d:%d Weekday:%d\n", years, months, days, hours, minutes, seconds, weekdays);
  String currentTime = "";
    if (hours < 10)currentTime += 0;currentTime += hours;currentTime += ":";
    if (minutes < 10)currentTime += 0;currentTime += minutes;currentTime += ":";
  String currentDate = "";
    currentDate += years;currentDate += "/";
    if (months < 10)currentDate += 0;currentDate += months;currentDate += "/";
    if (days < 10)currentDate += 0;currentDate += days;
  String s="";  if (seconds < 10)s += 0;s += seconds;             // 单独把秒字符串拿出来以小字体显示在冒号处
  
  u8g2.clearBuffer();      
    u8g2.setCursor(0, 47);u8g2.setFont(u8g2_font_logisoso42_tr);u8g2.print(currentTime);   
    u8g2.setCursor(54,35);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print(s);   
    u8g2.setCursor(0, 64);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print(currentDate);  
    u8g2.drawXBM(80, 49, 16, 16, xing);
    u8g2.setCursor(95, 63);u8g2.print("期");
    if      (weekdays == 1)u8g2.print("日");
    else if (weekdays == 2)u8g2.print("一");
    else if (weekdays == 3)u8g2.print("二");
    else if (weekdays == 4)u8g2.print("三");
    else if (weekdays == 5)u8g2.print("四");
    else if (weekdays == 6)u8g2.print("五");
    else if (weekdays == 7)u8g2.drawXBM(111, 49, 16, 16, liu);
  u8g2.sendBuffer();
}

/*---------------- NTP 代码 ------------------*/
time_t getNtpTime(){
  Serial.print("\nSync...");
  if(timeClient.update())Serial.println("Success!");    // 串口打印同步成功与否 0 失败 1 成功
  else Serial.println("Failed!");    
  return(timeClient.getEpochTime()+28800);              // GMT+8, 3600*8
}

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

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

相关文章

【天梯赛补题】

175对我这种蒟蒻好难&#xff0c;&#xff0c;&#xff0c; L1-6剪切粘贴 题目详情 - L1-094 剪切粘贴 (pintia.cn) 天梯赛&#xff1a;L1-094 剪切粘贴_scarecrow133的博客-CSDN博客 本蒟蒻看到字符串就害怕&#xff0c;一看就没思路&#xff0c;果断跳过了…… 等佬佬讲…

《面试1v1》java注解

我是 javapub&#xff0c;一名 Markdown 程序员从&#x1f468;‍&#x1f4bb;&#xff0c;八股文种子选手。 面试官&#xff1a;接下来&#xff0c;聊聊Java的注解,它们到底有什么用? 候选人&#xff1a; 注解的用处主要三个: 第一个,编译期使用。比如Override确保你正确重…

Vue 条件语句

文章目录 Vue 条件语句条件判断v-ifv-elsev-else-ifv-show Vue 条件语句 条件判断 v-if 条件判断使用 v-if 指令&#xff1a; v-if 指令 在元素 和 template 中使用 v-if 指令&#xff1a; <div id"app"><p v-if"seen">现在你看到我了<…

自阿里P8爆出内部1031道java面试题后,在Boss直聘狂拿千份Offer

开始之前我问大家几个问题&#xff0c;看大家是如何思考的&#xff1a; 1.程序员一定要去一线城市漂泊吗&#xff1f;在自己家乡如何拿到一份满意的薪水&#xff1f; 2.程序员被裁员、找不到工作&#xff0c;代表什么&#xff1f; 3.程序员一定要进一线大厂吗&#xff1f;你…

LeetCode热题HOT100:单词拆分、环形链表 II、LRU 缓存

LeetCode热题HOT100 139. 单词拆分 题目&#xff1a;给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 示例 1&#xf…

一个从培训学校走出来的测试工程师自述....

简单介绍一下我自己&#xff0c;1997年的&#xff0c;毕业一年了&#xff0c;本科生&#xff0c;专业是机械制造及其自动化。 在校度过了四年&#xff0c;毕业&#xff0c;找工作&#xff0c;填三方协议&#xff0c;体检&#xff0c;入职。我觉得我可能就这么度过我平平无奇的…

D. Ehab and the Expected XOR Problem(构造 + 异或和)

Problem - D - Codeforces 给出两个整数nn和xx&#xff0c;构造一个满足以下条件的数组&#xff1a; 对于数组中的任何元素aiai&#xff0c;1≤ai<2n1≤ai<2n&#xff1b; 没有非空的子段&#xff0c;其位数XOR值等于00或xx、 它的长度ll应该是最大的。 一个序列bb是一个…

Spring更简单的读取和存储对象

1.存储对象 通过注解来替代配置&#xff0c;依然需要配置扫描包的类对象 1.配置扫描路径 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001…

Amazon Linux2部署安装Jenkins

先决条件 服务器配置要求 256 MB of RAM 1 GB of drive space (although 10 GB is a recommended minimum if running Jenkins as a Docker container) 需要部署安装JDK环境部署安装的Jenkins版本为Version 2.400 部署安装JDK 1. 下载JDK软件包 wget https://corretto.aws/…

c++积累11-强制类型转换运算符(static_cast/reinterpret_cast/const_cast/dynamic_cast)

1、背景 将类型名作为强制类型转换运算符的做法是C语言的老式做法&#xff0c;C为保持兼容而予以保留。强制类型转换是有一定风险的&#xff0c;C引入新的转换机制&#xff0c;主要为了客服C语言转换的三个缺点&#xff1b; 1、没有从形式上体现转换功能和风险的不同。 例如&a…

深度强化学习——第一次知识小结(3.5)

一、策略网络的小结&#xff1a; 重要概念回顾&#xff1a; 1、动作价值函数QΠ(st,at) 动作价值函数是未来奖励总和Ut的条件期望&#xff0c;如果已知了策略函数Π与当前的状态st&#xff0c;QΠ就可以对所有的动作a打分&#xff0c;以此来决定选择哪个a 其实顾名思义就是…

【分布式版本控制系统Git】| 国内代码托管中心-Gitee、自建代码托管平台-GitLab

目录 一&#xff1a;国内代码托管中心-码云 1. 码云创建远程库 2. IDEA 集成码云 3. 码云复制 GitHub 项目 二&#xff1a;自建代码托管平台-GitLab 1. GitLab 安装 2. IDEA 集成 GitLab 一&#xff1a;国内代码托管中心-码云 众所周知&#xff0c;GitHub 服务器在国外&…

二:伙伴系统

内核空间内存分配 目录 内核空间内存分配 伙伴系统 首先从内核空间开始&#xff0c;讲解内存管理模式。 主要分为三种方式&#xff1a; 这篇文章我们集中注意于伙伴系统 伙伴系统 解决了外部碎片问题&#xff0c;针对大块内存分配设计 Linux中的内存管理的“页”大小为4…

第三章(4):自然语言处理入门

第三章&#xff08;4&#xff09;&#xff1a;自然语言处理入门 在本节中&#xff0c;我们将在简单文本数据上&#xff08;例如一个句子上&#xff09;&#xff0c;执行一系列基本操作&#xff0c;来帮助你熟悉NLP的工作原理&#xff0c;其中一些技术在第三章&#xff08;2&…

SLIC超像素分割算法

SLIC超像素分割算法 《SLIC Superpixels》 摘要 超像素在计算机视觉应用中越来越受欢迎。然而&#xff0c;很少有算法能够输出所需数量的规则、紧凑的超级像素&#xff0c;并且计算开销低。我们介绍了一种新的算法&#xff0c;将像素聚类在组合的五维颜色和图像平面空间中&a…

腾讯云COS+SpringBOot实现文件上传下载功能

文章目录 第一步&#xff1a;在.yml文件中配置对应秘钥内容第二步&#xff1a;完成COSConfig类编写第三步&#xff1a;编写Controller类Bug提示&#xff1a; 最近一直在做一个项目&#xff0c;需要支持视频&#xff0c;音频&#xff0c;图片的上传&#xff0c;前面介绍的都是把…

2023年制造业产品经理考NPDP有什么用?

产品经理国际资格认证NPDP是新产品开发方面的认证&#xff0c;集理论、方法与实践为一体的全方位的知识体系&#xff0c;为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。 【认证机构】 产品开发与管理协会&#xff08;PDMA&#xff09;成立于1979年&#xff0c;是…

beef-xss浏览器劫持

beef-xss浏览器劫持 一&#xff0c;实验拓扑图二&#xff0c;租用一台阿里云&#xff0c;搭建docker环境和beef环境1.租一台阿里云服务器&#xff0c;系统选用ubuntu&#xff0c;计时收费的那种&#xff0c;一个小时几毛钱2.开启策略组3000端口&#xff0c;5000端口4.安装docke…

交友项目【查询好友动态,查询推荐动态】实现

目录 1&#xff1a;圈子 1.1&#xff1a;查询好友动态 1.1.1&#xff1a;接口分析 1.1.2&#xff1a;流程分析 1.1.2&#xff1a;代码实现 1.2&#xff1a;查询推荐动态 1.2.1&#xff1a;接口分析 1.2.2&#xff1a;流程分析 1.2.3&#xff1a;代码实现 1&#xff1a…

十五分钟带你学会 Electron

文章目录 什么是 Electron为什么要选择 Electron安装 Electron桌面CSDN实战Electron 基础配置Electron 进程主进程渲染进程主进程与渲染进程的区别主进程与渲染进程的通信 Electron 跨平台问题Electron 部署打包应用程序发布应用程序 Electron 跨端原理总结 什么是 Electron E…