基于ESP8266网络天气时钟的OLED显示

news/2024/6/30 17:46:59/文章来源:https://www.cnblogs.com/Jin-Lei-Li/p/18272418

基于ESP8266网络天气时钟的OLED显示

注意修改 WiFi 名称和密码

需要申请【心知天气】API私钥

心知天气URL:https://www.seniverse.com

/*
参考:
https://blog.csdn.net/weixin_44668788/article/details/120643078
http://www.taichi-maker.com/homepage/iot-development/iot-platform/seniverse/esp8266-application/
OLED connect with ESP8266 NodeMCU
SCL -- D1
SDA -- D2
*/
//引入必要的头文件
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <SPI.h>
#include <U8g2lib.h>
#include <WiFiUdp.h>
#include <TimeLib.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
WiFiUDP Udp;
unsigned int localPort = 8888; // 用于侦听UDP数据包的本地端口//网络校时的相关配置
static const char ntpServerName[] = "ntp1.aliyun.com"; //NTP服务器,使用阿里云
int timeZone = 8; //时区设置,采用东8区//保存断网前的最新数据
int results_0_now_temperature_int_old;
String results_0_now_text_str_old;
int results_0_daily_1_high_int_old;
int results_0_daily_1_low_int_old;
String results_0_daily_1_text_day_str_old;//函数声明
time_t getNtpTime();
void sendNTPpacket(IPAddress &address);
void oledClockDisplay();
void sendCommand(int command, int value);
void initdisplay();
void connectWiFi();
void parseInfo_now(WiFiClient client,int i);
void parseInfo_fut(WiFiClient client,int i);
//
boolean isNTPConnected = false;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}; /*六*/typedef struct
{                  //存储配置结构体int tz;        //时间戳
} config_type;
config_type config;WiFiClient clientNULL;
DNSServer dnsServer;
ESP8266WebServer server(80);//----------WIFI连接配置----------
const char* ssid     = "xxxxxxx";       // 连接WiFi名,需要修改
const char* password = "xxxxxxxx";          // 连接WiFi密码,需要修改// 请将您需要连接的WiFi密码填入引号中
//----------天气API配置----------
const char* host = "api.seniverse.com";   // 将要连接的服务器地址  
const int httpPort = 80;              // 将要连接的服务器端口      // 心知天气HTTP请求所需信息
String reqUserKey = "xxxxxx";   // 私钥,需要修改
String reqLocation = "Shanghai";            // 城市
String reqUnit = "c";                      // 摄氏/华氏//----------设置屏幕----------
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
int sta = 0;
//----------初始化OLED----------
void initdisplay()
{u8g2.begin();u8g2.enableUTF8Print();
}
//----------用于获取实时天气的函数(0)----------
void TandW(){String reqRes = "/v3/weather/now.json?key=" + reqUserKey ++ "&location=" + reqLocation + "&language=en&unit=" +reqUnit;// 向心知天气服务器服务器请求信息并对信息进行解析httpRequest(reqRes,0);//延迟,需要低于20次/分钟delay(5000);
}
void display_1(int results_0_now_temperature_int,String results_0_now_text_str);//声明函数,用于显示温度、天气//----------获取3天预报(1)----------
void threeday(){// 建立心知天气API当前天气请求资源地址String reqRes = "/v3/weather/daily.json?key=" + reqUserKey ++ "&location=" + reqLocation + "&language=en&unit=" +reqUnit + "&start=0&days=3";// 向心知天气服务器服务器请求信息并对信息进行解析httpRequest(reqRes,1);delay(5000);
}void clock_display(time_t prevDisplay){server.handleClient();dnsServer.processNextRequest();if (timeStatus() != timeNotSet){if (now() != prevDisplay){ //时间改变时更新显示prevDisplay = now();oledClockDisplay();}}
}void setup(){Serial.begin(9600);          Serial.println("");initdisplay();// 连接WiFiu8g2.clearBuffer();u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.setCursor(0, 14);u8g2.print("Waiting for WiFi");u8g2.setCursor(0, 30);u8g2.print("connection...");u8g2.sendBuffer();connectWiFi();Udp.begin(localPort);setSyncProvider(getNtpTime);setSyncInterval(300); //每300秒同步一次时间}time_t prevDisplay = 0; //当时钟已经显示void loop(){if (sta>=0 && sta<=250){clock_display(prevDisplay);}else if(sta == 251){TandW();}else{threeday();}++sta;if(sta==253){sta = 0;}
}// 向心知天气服务器服务器请求信息并对信息进行解析
void httpRequest(String reqRes,int stat){WiFiClient client;// 建立http请求信息String httpRequest = String("GET ") + reqRes + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n";Serial.println(""); Serial.print("Connecting to "); Serial.print(host);// 尝试连接服务器if (client.connect(host, 80)){Serial.println(" Success!");// 向服务器发送http请求信息client.print(httpRequest);Serial.println("Sending request: ");Serial.println(httpRequest);  // 获取并显示服务器响应状态行 String status_response = client.readStringUntil('\n');Serial.print("status_response: ");Serial.println(status_response);// 使用find跳过HTTP响应头if (client.find("\r\n\r\n")) {Serial.println("Found Header End. Start Parsing.");}if (stat == 0){// 利用ArduinoJson库解析心知天气响应信息(实时数据)parseInfo_now(client,1); }else if(stat == 1){parseInfo_fut(client,1);}}else {Serial.println(" connection failed!");if (stat == 0){// 利用ArduinoJson库解析心知天气响应信息(实时数据)parseInfo_now(clientNULL,0); }else if(stat == 1){parseInfo_fut(clientNULL,0);}}//断开客户端与服务器连接工作client.stop(); 
}// 连接WiFi
void connectWiFi(){WiFi.begin(ssid, password);                  // 启动网络连接Serial.print("Connecting to ");              // 串口监视器输出网络连接信息Serial.print(ssid); Serial.println(" ...");  // 告知用户NodeMCU正在尝试WiFi连接int i = 0;                                   // 这一段程序语句用于检查WiFi是否连接成功while (WiFi.status() != WL_CONNECTED) {      // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。 delay(1000);                               // 如果WiFi连接成功则返回值为WL_CONNECTED                       Serial.print(i++); Serial.print(' ');      // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值}                                            // 同时NodeMCU将通过串口监视器输出连接时长读秒。// 这个读秒是通过变量i每隔一秒自加1来实现的。                                              Serial.println("");                          // WiFi连接成功后Serial.println("Connection established!");   // NodeMCU将通过串口监视器输出"连接成功"信息。Serial.print("IP address:    ");             // 同时还将输出NodeMCU的IP地址。这一功能是通过调用Serial.println(WiFi.localIP());              // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。  
}// 利用ArduinoJson库解析心知天气响应信息(实时)
void parseInfo_now(WiFiClient client,int i){if(i==1){const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 230;DynamicJsonDocument doc(capacity);deserializeJson(doc, client);JsonObject results_0 = doc["results"][0];JsonObject results_0_now = results_0["now"];const char* results_0_now_text = results_0_now["text"]; // "Sunny"const char* results_0_now_code = results_0_now["code"]; // "0"const char* results_0_now_temperature = results_0_now["temperature"]; // "32"const char* results_0_last_update = results_0["last_update"]; // "2020-06-02T14:40:00+08:00" // 通过串口监视器显示以上信息String results_0_now_text_str = results_0_now["text"].as<String>(); int results_0_now_code_int = results_0_now["code"].as<int>(); int results_0_now_temperature_int = results_0_now["temperature"].as<int>(); String results_0_last_update_str = results_0["last_update"].as<String>();   Serial.println(F("======Weahter Now======="));Serial.print(F("Weather Now: "));Serial.print(results_0_now_text_str);Serial.print(F(" "));Serial.println(results_0_now_code_int);Serial.print(F("Temperature: "));Serial.println(results_0_now_temperature_int);Serial.print(F("Last Update: "));Serial.println(results_0_last_update_str);Serial.println(F("========================"));display_0(results_0_now_temperature_int,results_0_now_text_str);results_0_now_text_str_old = results_0_now_text_str;results_0_now_temperature_int_old = results_0_now_temperature_int;}else{display_0(results_0_now_temperature_int_old,results_0_now_text_str_old);}}
//----------输出实时天气----------
void display_0(int results_0_now_temperature_int,String results_0_now_text_str){//显示输出u8g2.clearBuffer();u8g2.setFont(u8g2_font_wqy16_t_gb2312);u8g2.setCursor(15, 14);u8g2.print("上海实时天气");u8g2.setFont(u8g2_font_logisoso24_tr);u8g2.setCursor(45, 44);u8g2.print(results_0_now_temperature_int);u8g2.setCursor(15, 61);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print(results_0_now_text_str);u8g2.sendBuffer();
}// 利用ArduinoJson库解析心知天气响应信息(预测)
void parseInfo_fut(WiFiClient client,int i){if(i==1){const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(3) + JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 3*JSON_OBJECT_SIZE(14) + 860;DynamicJsonDocument doc(capacity);deserializeJson(doc, client);JsonObject results_0 = doc["results"][0];JsonArray results_0_daily = results_0["daily"];JsonObject results_0_daily_0 = results_0_daily[0];const char* results_0_daily_0_date = results_0_daily_0["date"]; const char* results_0_daily_0_text_day = results_0_daily_0["text_day"]; const char* results_0_daily_0_code_day = results_0_daily_0["code_day"];const char* results_0_daily_0_text_night = results_0_daily_0["text_night"]; const char* results_0_daily_0_code_night = results_0_daily_0["code_night"]; const char* results_0_daily_0_high = results_0_daily_0["high"];const char* results_0_daily_0_low = results_0_daily_0["low"]; const char* results_0_daily_0_rainfall = results_0_daily_0["rainfall"];const char* results_0_daily_0_precip = results_0_daily_0["precip"]; const char* results_0_daily_0_wind_direction = results_0_daily_0["wind_direction"]; const char* results_0_daily_0_wind_direction_degree = results_0_daily_0["wind_direction_degree"];const char* results_0_daily_0_wind_speed = results_0_daily_0["wind_speed"];const char* results_0_daily_0_wind_scale = results_0_daily_0["wind_scale"];const char* results_0_daily_0_humidity = results_0_daily_0["humidity"];JsonObject results_0_daily_1 = results_0_daily[1];const char* results_0_daily_1_date = results_0_daily_1["date"];const char* results_0_daily_1_text_day = results_0_daily_1["text_day"];const char* results_0_daily_1_code_day = results_0_daily_1["code_day"];const char* results_0_daily_1_text_night = results_0_daily_1["text_night"]; const char* results_0_daily_1_code_night = results_0_daily_1["code_night"]; const char* results_0_daily_1_high = results_0_daily_1["high"];const char* results_0_daily_1_low = results_0_daily_1["low"]; const char* results_0_daily_1_rainfall = results_0_daily_1["rainfall"]; const char* results_0_daily_1_precip = results_0_daily_1["precip"]; const char* results_0_daily_1_wind_direction = results_0_daily_1["wind_direction"];const char* results_0_daily_1_wind_direction_degree = results_0_daily_1["wind_direction_degree"]; const char* results_0_daily_1_wind_speed = results_0_daily_1["wind_speed"];const char* results_0_daily_1_wind_scale = results_0_daily_1["wind_scale"];const char* results_0_daily_1_humidity = results_0_daily_1["humidity"]; JsonObject results_0_daily_2 = results_0_daily[2];const char* results_0_daily_2_date = results_0_daily_2["date"];const char* results_0_daily_2_text_day = results_0_daily_2["text_day"];const char* results_0_daily_2_code_day = results_0_daily_2["code_day"];const char* results_0_daily_2_text_night = results_0_daily_2["text_night"];const char* results_0_daily_2_code_night = results_0_daily_2["code_night"];const char* results_0_daily_2_high = results_0_daily_2["high"]; const char* results_0_daily_2_low = results_0_daily_2["low"]; const char* results_0_daily_2_rainfall = results_0_daily_2["rainfall"];const char* results_0_daily_2_precip = results_0_daily_2["precip"]; const char* results_0_daily_2_wind_direction = results_0_daily_2["wind_direction"]; const char* results_0_daily_2_wind_direction_degree = results_0_daily_2["wind_direction_degree"]; const char* results_0_daily_2_wind_speed = results_0_daily_2["wind_speed"];const char* results_0_daily_2_wind_scale = results_0_daily_2["wind_scale"]; const char* results_0_daily_2_humidity = results_0_daily_2["humidity"]; const char* results_0_last_update = results_0["last_update"]; // 从以上信息中摘选几个通过串口监视器显示String results_0_daily_0_date_str = results_0_daily_0["date"].as<String>();String  results_0_daily_0_text_day_str = results_0_daily_0["text_day"].as<String>(); int results_0_daily_0_code_day_int = results_0_daily_0["code_day"].as<int>(); String results_0_daily_0_text_night_str = results_0_daily_0["text_night"].as<String>(); int results_0_daily_0_code_night_int = results_0_daily_0["code_night"].as<int>(); int results_0_daily_0_high_int = results_0_daily_0["high"].as<int>();int results_0_daily_0_low_int = results_0_daily_0["low"].as<int>();String results_0_last_update_str = results_0["last_update"].as<String>();int results_0_daily_1_high_int = results_0_daily_1["high"].as<int>();int results_0_daily_1_low_int = results_0_daily_1["low"].as<int>();String results_0_daily_1_text_day_str = results_0_daily_1["text_day"].as<String>();Serial.println(F("======Today Weahter ======="));Serial.print(F("DATE: "));Serial.println(results_0_daily_0_date_str);Serial.print(F("Day Weather: "));Serial.print(results_0_daily_0_text_day_str);Serial.print(F(" "));Serial.println(results_0_daily_0_code_day_int);Serial.print(F("Night Weather: "));Serial.print(results_0_daily_0_text_night_str);Serial.print(F(" "));Serial.println(results_0_daily_0_code_night_int);Serial.print(F("High: "));Serial.println(results_0_daily_0_high_int);Serial.print(F("LOW: "));Serial.println(results_0_daily_0_low_int);Serial.print(F("Last Update: "));Serial.println(results_0_last_update_str);Serial.println(F("=============================="));display_1(results_0_daily_1_high_int,results_0_daily_1_low_int,results_0_daily_1_text_day_str);results_0_daily_1_high_int_old=results_0_daily_1_high_int;results_0_daily_1_low_int_old=results_0_daily_1_low_int;results_0_daily_1_text_day_str_old=results_0_daily_1_text_day_str;
}else{display_1(results_0_daily_1_high_int_old,results_0_daily_1_low_int_old,results_0_daily_1_text_day_str_old);
}}
//----------预测明天天气----------
void display_1(int results_0_daily_1_high_int,int results_0_daily_1_low_int,String results_0_daily_1_text_day_str){//显示输出u8g2.clearBuffer();u8g2.setFont(u8g2_font_wqy16_t_gb2312);u8g2.setCursor(15, 14);u8g2.print("上海明天天气");u8g2.setFont(u8g2_font_logisoso24_tr);u8g2.setCursor(20, 46);u8g2.print(results_0_daily_1_low_int);u8g2.setCursor(56, 46);u8g2.print("~");u8g2.setCursor(75, 46);u8g2.print(results_0_daily_1_high_int);u8g2.setCursor(30, 62);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print(results_0_daily_1_text_day_str);u8g2.sendBuffer();
}/*-------- NTP 代码 ----------*/const int NTP_PACKET_SIZE = 48;     // NTP时间在消息的前48个字节里
byte packetBuffer[NTP_PACKET_SIZE]; // 输入输出包的缓冲区time_t getNtpTime()
{IPAddress ntpServerIP; // NTP服务器的地址while (Udp.parsePacket() > 0); // 丢弃以前接收的任何数据包Serial.println("Transmit NTP Request");// 从池中获取随机服务器WiFi.hostByName(ntpServerName, ntpServerIP);Serial.print(ntpServerName);Serial.print(": ");Serial.println(ntpServerIP);sendNTPpacket(ntpServerIP);uint32_t beginWait = millis();while (millis() - beginWait < 1500){int size = Udp.parsePacket();if (size >= NTP_PACKET_SIZE){Serial.println("Receive NTP Response");isNTPConnected = true;Udp.read(packetBuffer, NTP_PACKET_SIZE); // 将数据包读取到缓冲区unsigned long secsSince1900;// 将从位置40开始的四个字节转换为长整型,只取前32位整数部分secsSince1900 = (unsigned long)packetBuffer[40] << 24;secsSince1900 |= (unsigned long)packetBuffer[41] << 16;secsSince1900 |= (unsigned long)packetBuffer[42] << 8;secsSince1900 |= (unsigned long)packetBuffer[43];Serial.println(secsSince1900);Serial.println(secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR);return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;}}Serial.println("No NTP Response :-("); //无NTP响应isNTPConnected = false;return 0; //如果未得到时间则返回0
}// 向给定地址的时间服务器发送NTP请求
void sendNTPpacket(IPAddress &address)
{memset(packetBuffer, 0, NTP_PACKET_SIZE);packetBuffer[0] = 0b11100011; // LI, Version, ModepacketBuffer[1] = 0;          // Stratum, or type of clockpacketBuffer[2] = 6;          // Polling IntervalpacketBuffer[3] = 0xEC;       // Peer Clock Precision// 8 bytes of zero for Root Delay & Root DispersionpacketBuffer[12] = 49;packetBuffer[13] = 0x4E;packetBuffer[14] = 49;packetBuffer[15] = 52;Udp.beginPacket(address, 123); //NTP需要使用的UDP端口号为123Udp.write(packetBuffer, NTP_PACKET_SIZE);Udp.endPacket();
}void oledClockDisplay()
{int years, months, days, hours, minutes, seconds, weekdays;years = year();months = month();days = day();hours = hour();minutes = minute();seconds = second();weekdays = weekday();Serial.printf("%d/%d/%d %d:%d:%d Weekday:%d\n", years, months, days, hours, minutes, seconds, weekdays);u8g2.clearBuffer();u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.setCursor(0, 14);if (isNTPConnected){if(timeZone>=0){u8g2.print("当前时间(UTC+");u8g2.print(timeZone);u8g2.print(")");}else{u8g2.print("当前时间(UTC");u8g2.print(timeZone);u8g2.print(")");}}elseu8g2.print("无网络!"); //如果上次对时失败,则会显示无网络String currentTime = "";if (hours < 10)currentTime += 0;currentTime += hours;currentTime += ":";if (minutes < 10)currentTime += 0;currentTime += minutes;currentTime += ":";if (seconds < 10)currentTime += 0;currentTime += seconds;String currentDay = "";currentDay += years;currentDay += "/";if (months < 10)currentDay += 0;currentDay += months;currentDay += "/";if (days < 10)currentDay += 0;currentDay += days;u8g2.setFont(u8g2_font_logisoso24_tr);u8g2.setCursor(0, 44);u8g2.print(currentTime);u8g2.setCursor(0, 61);u8g2.setFont(u8g2_font_unifont_t_chinese2);u8g2.print(currentDay);u8g2.drawXBM(80, 48, 16, 16, xing);u8g2.setCursor(95, 62);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();
}

实现效果如下:



转载请注明出处,感谢!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenVX™图形管道化、流式处理和批处理扩展到OpenVX 1.1和1.2

OpenVX™图形管道化、流式处理和批处理扩展到OpenVX 1.1和1.2 https://registry.khronos.org/OpenVX/extensions/vx_khr_pipelining/1.0.1/vx_khr_pipelining_1_0_1.html 1.简介 1.1. 意图 启用具有不同输入和输出的给定图形的多次初始化。此外,该扩展为应用程序提供了一种执行…

二分图与网络流,ACMer需要掌握的一些模型

写在前面 前些日子的四川省赛,我们队伍拿到了网络流C题的一血。看完题目和队友讨论了下,大概两三分钟就把题目正确做法讨论出来了,但是写代码过程还是比较笨拙的,建完图后一度蒙圈甚至不知道自己建的是什么意思,后来冷静下来才把图改对。 作为23年学校图论专题的负责人,我…

解析ORB-SLAM3的源码

随着计算机视觉与机器人技术的发展,SLAM(同步定位与地图构建)技术在自动导航、机器人和无人机领域中起着至关重要的作用。作为当前最先进的SLAM系统之一,ORB-SLAM3因其卓越的性能和开源特性,备受关注。本文将详细解析ORB-SLAM3的源码,帮助读者更好地理解其内部机制。 一、…

Javascript-this/作用域/闭包

this & 作用域 & 闭包this的核心,在大多数情况下,可以简单地理解为谁调用了函数,this就指向谁。但请注意,这里不包括通过call、apply、bind、new操作符或箭头函数进行调用的特殊情况。在这些特殊情况下,this的指向会有所不同。 this的值是在函数运行时根据调用方式…

TIM1比较模式

暂不讨论捕获功能,简化下面的描述方便阅读理解。 -------------------------------------------------------------------------------- 13.4.14 TIM1 比较寄存器 1(TIMx_CCR1)    CCR1[15:0]: 比较通道1的值 (Compare 1 value) 若CC1 通道配置为输出:CCR1包含了装入比较…

[C++ Primer] 顺序容器

记录C++中STL标准模板库的常见操作顺序容器 顺序容器概述下标列出了标准库中的顺序容器,所有顺序容器都提供了快速顺序访问元素的能力。这些容器在以下方面都有不同的性能折中:向容器添加或从容器中删除元素的代价 非顺序访问容器中元素的代价2. 若不确定应该使用哪种容器,可…

Centos7.6下安装配置Jenkins

目前,网上很多关于Jenkins持续集成工具在Centos上部署教程,但发现部署完之后,基本都是不能使用,大部分是关于版本问题的报错, 都会提示让我们更新jenkins到比较新的版本,而更新到新版Jenkins又必须使用JDK11以上的版本,而我开发、测试用的环境JDK8版本, 一旦升级JDK,很…

VSCode 中 Markdown Preview Enhanced 插件利用 Chrome (Puppeteer) 导出 PDF 文件使用说明与问题解决

准备 预先安装好 Chrome 浏览器。 使用方法 右键选择 Chrome (Puppeteer)。设置 Puppeteer 通过 front-matter 即在 markdown 文档开头加上 yaml 格式的配置代码 --- puppeteer:format: "A4"scale: 1.0margin:top: 2cmright: 3cmbottom: 2cmleft: 3cm ---这里 format…

全网最适合入门的面向对象编程教程:03 类和对象的Python实现-为自定义类添加属性

本文主要介绍了,当使用Python创建自定义类时,如何为其添加属性,包括为类和实例添加属性两种,以及如何获取自定义的属性等内容。摘要: 本文主要介绍了,当使用 Python 创建自定义类时,如何为其添加属性,包括为类和实例添加属性两种,以及如何获取自定义的属性等内容。 往…

全网最适合入门的面向对象编程教程:03 类和对象的Python实现-使用Python创建类

本文主要介绍了,当使用Python创建自定义类时,如何为其添加属性,包括为类和实例添加属性两种,以及如何获取自定义的属性等内容。摘要: 本文主要介绍了,当使用 Python 创建自定义类时,如何为其添加属性,包括为类和实例添加属性两种,以及如何获取自定义的属性等内容。 往…

Centos7下安装配置MySQL5.7

本次安装的版本是在Centos7.6版本下安装配置mysql5.7版本。具体操作步骤如下: 1. 首先通过wget命令,下载MySQL源安装包: wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm 安装MySQL源: yum localinstall mysql57-community-release-el7-11.noar…

Hugging Face Accelerate 两个后端的故事:FSDP 与 DeepSpeed

社区中有两个流行的 零冗余优化器(Zero Redundancy Optimizer,ZeRO) 算法实现,一个来自 DeepSpeed,另一个来自 PyTorch。Hugging Face Accelerate 对这两者都进行了集成并通过接口暴露出来,以供最终用户在训练/微调模型时自主选择其中之一。本文重点介绍了 Accelerate 对…

自制键盘(一)

概述 这个项目的灵感来源是稚晖君的客制化键盘项目,看到瀚文就觉得很震撼,就想自己也做一把试试。正好最近也正好在学嵌入式,顺便巩固一下最近所学的知识、也可以多了解一点技术栈。不过由于技术首先所以先做一把小键盘试试手。 项目整体思路 整个项目大致可以分为三个部分,…

尝试使用 Python 截屏并录屏

( 本文的完整版地址在 https://www.ccgxk.com/?post=494 ) 我在去年,曾经尝试过一个大胆的东西,就是使用 Python 写了个程序来录屏,以此给自己一种“期待感”,当时有没有效果我忘了,但是现在我又将这个项目捡了起来。界面是长上面那个样子,集成了项目名设置、开始录…

Compose 延迟列表踩过的坑

问题 在使用 Jetpack Compose 延迟列表时遇到一个坑,简单记录一下。直接上代码:这个代码看起来也没有什么问题,滑动正常,点击滑动到顶部也正常。 但是极端操作:在一边滑动列表一边点击按钮,就出问题了。这样再点击按钮,就不生效了。从日志来看,点击时协程发射值没有问题…

代码随想录算法训练营第22天 | 77.组合 216.组合总和 17.电话号码的字母组合

77.组合 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 解题 只能取比它大的,所以有个参数startindex 参数:一维数组单个组合path,二维数组结果集result,总数n,组合大小k,搜索结果的开始索引startindex 终止条件:path.size=k点击查看代码 class Solut…

(四)详解RLHF

一直都特别好奇大模型的强化学习微调是怎么做的,网上虽然相关文章不少,但找到的文章都是浅尝辄止说到用PPO训练,再细致深入的就没有讲了。。。只能自己看一看代码,以前搞过一点用PPO做游戏,感觉和语言模型PPO的用法不太一样。在游戏场景,每个step给环境一个action之后,a…

模拟集成电路设计系列博客——8.1.1 锁相环基本介绍

8.1.1 锁相环基本介绍 几乎所有的数字,射频电路以及大部分的模拟电路。不幸的是,集成电路振荡器本身并不适合用于高性能电路中的频率/时间参考源。一个主要的问题是它们的震荡频率并不能精确知道。更进一步的,集成电路振荡器的时钟抖动(可以被认为是频率上的随机波动)对于…

(三)使用 PPO 算法进行 RLHF 的 N 步实现细节

使用 PPO 算法进行 RLHF 的 N 步实现细节 当下,RLHF/ChatGPT 已经变成了一个非常流行的话题。我们正在致力于更多有关 RLHF 的研究,这篇博客尝试复现 OpenAI 在 2019 年开源的原始 RLHF 代码库,其仓库位置位于 openai/lm-human-preferences。尽管它具有 “tensorflow-1.x” …