【物联网项目】基于esp32+1

先上视频:

资料提供

准备材料:

连接方式:

语音交互表情制作

ESP32代码部分

1.主函数

2.太空人时钟esp32_101

3.配网与时钟布局

4.与语音模块通信

5.初始化时钟时间

LU-ASR01模块代码


先上视频:

esp32+1.3寸屏幕语音交互

资料提供

百度网盘

链接:https://pan.baidu.com/s/14NO9VFD0rBgw6YYv1eYk3w?pwd=psbn 
提取码:psbn

准备材料:

nodemcu开发板一个

1.3寸IPS模块一个

继电器一个

舵机俩个+舵机云台

LU-ASR01鹿小班智能语音识别模块 离线识别   
购买需要选择带喇叭的

杜邦线  一样买点  都会用得到

温湿度模块  DHT11

12V小灯泡

连接方式:

esp32S           屏幕

GND             GND
3.3V             VCC
14             SCL
15             SDA        
33               RES        
27               DC

esp32S        语音模块  
 
16              IO8
P17             IO7

继电器          语音模块

信号线        IO1

舵机信号线          语音模块

舵机1        I02
舵机2        IO3

温湿度DHT11      语音模块
信号线             DHT

具体实物图连接方式如下:

语音交互表情制作

制作链接:http://tomeko.net/online_tools/file_to_hex.php?lang=en

将240x240大小的图片添加进去,会生成一个数组文件,将数组文件添加到esp266+1.3寸屏幕语音交互\语音模块与1.3寸屏幕交互\esp32_101\img\face.h文件里面

注意这里的数组名需要在语音模块和esp32中对应位置同时进行修改

ESP32代码部分

1.主函数


// UDP时间服务初始化
void UDPTimeInit(){
  Serial.println("Starting UDP");                 //连接时间服务器
  Udp.begin(localPort);
  Serial.print("Local port: ");
//  Serial.println(Udp.localPort());
  Serial.println("waiting for sync");
  setSyncProvider(getNtpTime);
  setSyncInterval(300); //时间校准间隔
}


time_t getNtpTime()                               //获取NTP时间
{
  IPAddress ntpServerIP;                          //NTP服务器的IP地址

  while (Udp.parsePacket() > 0) ;                 //之前的数据没有处理的话一直等待 discard any previously received packets
  WiFi.hostByName(ntpServerName, ntpServerIP);    //从网站名获取IP地址
  
  sendNTPpacket(ntpServerIP);                     //发送数据包
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();                 //接收数据
    if (size >= NTP_PACKET_SIZE) {
      Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);    //从缓冲区读取数据
      
      unsigned long secsSince1900;
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");
  return 0;                                       //没获取到数据的话返回0
}

void sendNTPpacket(IPAddress &address)            //发送数据包到NTP服务器
{
  memset(packetBuffer, 0, NTP_PACKET_SIZE);       //缓冲区清零

  packetBuffer[0] = 0b11100011;                   //LI, Version, Mode   填充缓冲区数据
  packetBuffer[1] = 0;                            //Stratum, or type of clock
  packetBuffer[2] = 6;                            //Polling Interval
  packetBuffer[3] = 0xEC;                         //Peer Clock Precision
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;

  Udp.beginPacket(address, 123);                  //NTP服务器端口123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);       //发送udp数据
  Udp.endPacket();                                //发送结束
}


String week()                                     //星期
{
  String wk[7] = {"日","一","二","三","四","五","六"};
  String s = "周" + wk[weekday()-1];
  return s;
}

String monthDay()                                 //月日
{
  String s = String(month());
  s = s + "月" + day() + "日";
  return s;
}

String hourMinute()                               //时分
{
  String s = num2str(hour());
  s = s + ":" + num2str(minute());
  return s;
}

String num2str(int digits)                        //数字转换成字符串,保持2位显示
{
  String s = "";
  if (digits < 10)
    s = s + "0";
  s = s + digits;
  return s;
}

void printDigits(int digits)                      //打印时间数据
{
  Serial.print(":");
  if (digits < 10)                                //打印两位数字
    Serial.print('0');
  Serial.print(digits);
}

2.太空人时钟esp32_101


#include "main.h"
#define  VERSION   "V101"

void setup()
{
  mySoftwareSerial.begin(9600);
  Serial.begin(115200);                           //初始化串口
  Serial.println();                               //打印回车换行

  TFTDisplayInit();                               //初始化TFT
  connect_wifi();                                 //联网处理
  UDPTimeInit();                                  //初始化时间服务
  
  MainView();                                     //太空表主结构
  
//  getCityCode();                                  //通过IP地址获取城市代码

  CityWeaterShow();                           //获取天气信息
  weatherOldTime = millis();
}

void loop()
{
  SoftSerialRx();
  if(dhStatus != 0){
    runImg(dhStatus);                          
  }else{
    //时钟动画
    taikongren();
  }
                           
}

//太空人业务
void taikongren(){
  //主界面动画
  if (now() != oldTime){                    //如果本次数据和上次不一样的话,刷新
    oldTime = now();
    TimeUpdateShow();
  }
  if(millis() - weatherUpdateTime > 600000){              //10分钟更新一次天气
    weatherUpdateTime = millis();
    CityWeaterShow();
  }
  weatherShow();                                 //天气数据滚动显示
  jpgSlideShow();   
}

3.配网与时钟布局


void connect_wifi()                               //联网
{
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);           //用固定的账号密码连接网络

  while (WiFi.status() != WL_CONNECTED) {         //未连接上的话
    for (uint8_t n = 0; n < 10; n++){             //每500毫秒检测一次状态
      PowerOn_Loading(50);
    }
  }
  while(loadNum < 194){                           //让动画走完
    PowerOn_Loading(1);
  }
  
  Serial.print("\nWiFi connected to: ");
  Serial.println(WIFI_SSID);
  Serial.print("IP:   ");
  Serial.println(WiFi.localIP());                 //得到IP地址
}

void PowerOn_Loading(uint8_t delayTime)           //开机联网显示的进度条,输入延时时间
{
  clk.setColorDepth(8);
  clk.createSprite(200, 50);                      //创建Sprite
  clk.fillSprite(0x0000);                         //填充颜色

  clk.drawRoundRect(0,0,200,16,8,0xFFFF);         //画一个圆角矩形
  clk.fillRoundRect(3,3,loadNum,10,5,0xFFFF);     //画一个填充的圆角矩形
  clk.setTextDatum(CC_DATUM);                     //显示对齐方式
  clk.setTextColor(TFT_GREEN, 0x0000);            //文本的前景色和背景色
  clk.drawString("Connecting to WiFi",100,40,2);  //显示文本
  clk.pushSprite(20,110);                         //Sprite中内容一次推向屏幕
  clk.deleteSprite();                             //删除Sprite
  loadNum += 1;                                   //进度条位置变化,直到加载完成
  if(loadNum>=194){
    loadNum = 194;
  }
  delay(delayTime);
}

void TimeUpdateShow()                        //时间显示
{
  clk.setColorDepth(8); 

  //--------------------中间时间区显示开始--------------------
  //时分
  clk.createSprite(140, 48);                      //创建Sprite,先在Sprite内存中画点,然后将内存中的点一次推向屏幕,这样刷新比较快
  clk.fillSprite(bgColor);                        //背景色
  //clk.loadFont(FxLED_48);
  clk.setTextDatum(CC_DATUM);                     //显示对齐方式
  clk.setTextColor(TFT_BLACK, bgColor);           //文本的前景色和背景色
  clk.drawString(hourMinute(),70,24,7);           //绘制时和分
  //clk.unloadFont();
  clk.pushSprite(28,40);                          //Sprite中内容一次推向屏幕
  clk.deleteSprite();                             //删除Sprite
  
  //秒
  clk.createSprite(40, 32);
  clk.fillSprite(bgColor);
  clk.loadFont(FxLED_32);                         //加载字体
  clk.setTextDatum(CC_DATUM);
  clk.setTextColor(TFT_BLACK, bgColor); 
  clk.drawString(num2str(second()),20,16);
  clk.unloadFont();                               //卸载字体
  clk.pushSprite(170,60);
  clk.deleteSprite();
  //--------------------中间时间区显示结束--------------------

  //--------------------底部时间区显示开始--------------------
  clk.loadFont(ZdyLwFont_20);                     //加载汉字字体
  
  //星期
  clk.createSprite(58, 32);
  clk.fillSprite(bgColor);
  clk.setTextDatum(CC_DATUM);
  clk.setTextColor(TFT_BLACK, bgColor);
  clk.drawString(week(),29,16);                   //周几
  clk.pushSprite(1,168);
  clk.deleteSprite();
  
  //月日
  clk.createSprite(98, 32);
  clk.fillSprite(bgColor);
  clk.setTextDatum(CC_DATUM);
  clk.setTextColor(TFT_BLACK, bgColor);  
  clk.drawString(monthDay(),49,16);               //几月几日
  clk.pushSprite(61,168);
  clk.deleteSprite();

  clk.unloadFont();                               //卸载字体
  //--------------------底部时间区显示结束--------------------
}





void getCityCode()                                //发送HTTP请求并且将服务器响应通过串口输出
{
  String URL = "http://wgeo.weather.com.cn/ip/?_="+String(now());

  httpClient.begin(Client,URL);                          //配置请求地址。此处也可以不使用端口号和PATH而单纯的
  httpClient.setUserAgent("esp8266");             //用户代理版本,其实没什么用 最重要是后端服务器支持
  //httpClient.setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1");//设置请求头中的User-Agent
  httpClient.addHeader("Referer", "http://www.weather.com.cn/");
 
  int httpCode = httpClient.GET();                //启动连接并发送HTTP请求
  Serial.print("Send GET request to URL: ");
  Serial.println(URL);
  
  if (httpCode == HTTP_CODE_OK) {                 //如果服务器响应OK则从服务器获取响应体信息并通过串口输出
    String str = httpClient.getString();
    int aa = str.indexOf("id=");
    if (aa > -1){                                 //应答包里找到ID了
       cityCode = str.substring(aa+4,aa+4+9);     //9位长度
       Serial.println(cityCode); 
       CityWeaterShow();                           //显示天气信息
       weatherOldTime = millis();
    }
    else{                                         //没有找到ID
      Serial.println("获取城市代码失败");  
    }
  } 
  else{
    Serial.println("请求城市代码错误:");
    Serial.println(httpCode);
  }
 
  httpClient.end();                               //关闭与服务器连接
}

void CityWeaterShow()                              //获取城市天气
{
  String URL = "http://d1.weather.com.cn/weather_index/" + cityCode + ".html?_="+String(now());

  httpClient.begin(Client,URL);                          //配置请求地址。
  httpClient.setUserAgent("esp8266");             //用户代理版本,其实没什么用 最重要是后端服务器支持
  //httpClient.setUserAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1");//设置请求头中的User-Agent
  httpClient.addHeader("Referer", "http://www.weather.com.cn/");
 
  int httpCode = httpClient.GET();                //启动连接并发送HTTP请求
  Serial.print("Send GET request to URL: ");
  Serial.println(URL);
  
  if (httpCode == HTTP_CODE_OK) {                 //如果服务器响应OK则从服务器获取响应体信息并通过串口输出
    String str = httpClient.getString();
    int indexStart = str.indexOf("weatherinfo\":");//寻找起始和结束位置
    int indexEnd = str.indexOf("};var alarmDZ");

    String jsonCityDZ = str.substring(indexStart+13,indexEnd);//复制字符串
    Serial.println(jsonCityDZ);

    indexStart = str.indexOf("dataSK =");         //寻找起始和结束位置
    indexEnd = str.indexOf(";var dataZS");
    String jsonDataSK = str.substring(indexStart+8,indexEnd);//复制字符串
    Serial.println(jsonDataSK);

    indexStart = str.indexOf("\"f\":[");          //寻找起始和结束位置
    indexEnd = str.indexOf(",{\"fa");
    String jsonFC = str.substring(indexStart+5,indexEnd);//复制字符串
    Serial.println(jsonFC);
    
    weaterData(&jsonCityDZ,&jsonDataSK,&jsonFC);  //显示天气信息
    Serial.println("获取成功");
    
  } 
  else {
    Serial.println("请求城市天气错误:");
    Serial.print(httpCode);
  }
 
  httpClient.end();                               //关闭与服务器连接
}

void weaterData(String *cityDZ,String *dataSK,String *dataFC)//天气信息写到屏幕上
{
  DynamicJsonDocument doc(512);
  deserializeJson(doc, *dataSK);
  JsonObject sk = doc.as<JsonObject>();

  clk.setColorDepth(8);
  clk.loadFont(ZdyLwFont_20);                     //加载汉字字体
  
  //温度显示
  clk.createSprite(54, 32);                       //创建Sprite
  clk.fillSprite(bgColor);                        //填充颜色
  clk.setTextDatum(CC_DATUM);                     //显示对齐方式
  clk.setTextColor(TFT_BLACK, bgColor);           //文本的前景色和背景色 
  clk.drawString(sk["temp"].as<String>()+"℃",27,16);//显示文本
  clk.pushSprite(185,168);                        //Sprite中内容一次推向屏幕
  clk.deleteSprite();                             //删除Sprite

  //城市名称显示
  clk.createSprite(88, 32); 
  clk.fillSprite(bgColor);
  clk.setTextDatum(CC_DATUM);
  clk.setTextColor(TFT_BLACK, bgColor); 
  clk.drawString(sk["cityname"].as<String>(),44,16);
  clk.pushSprite(151,1);
  clk.deleteSprite();
  
  //PM2.5空气指数显示
  uint16_t pm25BgColor = tft.color565(156,202,127);//优
  String aqiTxt = "优";
  int pm25V = sk["aqi"];
  if (pm25V > 200){
    pm25BgColor = tft.color565(136,11,32);        //重度,显示颜色和空气质量程度
    aqiTxt = "重度";
  }
  else if (pm25V > 150){
    pm25BgColor = tft.color565(186,55,121);       //中度
    aqiTxt = "中度";
  }
  else if (pm25V > 100){
    pm25BgColor = tft.color565(242,159,57);       //轻
    aqiTxt = "轻度";
  }
  else if (pm25V > 50){
    pm25BgColor = tft.color565(247,219,100);      //良
    aqiTxt = "良";
  }
  clk.createSprite(50, 24); 
  clk.fillSprite(bgColor);
  clk.fillRoundRect(0,0,50,24,4,pm25BgColor);
  clk.setTextDatum(CC_DATUM);
  clk.setTextColor(0xFFFF); 
  clk.drawString(aqiTxt,25,13);
  clk.pushSprite(5,130);
  clk.deleteSprite();

  //湿度显示
  clk.createSprite(56, 24); 
  clk.fillSprite(bgColor);
  clk.setTextDatum(CC_DATUM);
  clk.setTextColor(TFT_BLACK, bgColor); 
  clk.drawString(sk["SD"].as<String>(),28,13);
  //clk.drawString("100%",28,13);
  clk.pushSprite(180,130);
  clk.deleteSprite();

  scrollText[0] = "实时天气 " + sk["weather"].as<String>();//滚动显示的数据缓冲区
  scrollText[1] = "空气质量 " + aqiTxt;
  scrollText[2] = "风向 " + sk["WD"].as<String>()+sk["WS"].as<String>();
  
  //左上角滚动字幕
  deserializeJson(doc, *cityDZ);
  JsonObject dz = doc.as<JsonObject>();
  //Serial.println(sk["ws"].as<String>());
  //String aa = "今日天气:" + dz["weather"].as<String>() + ",温度:最低" + dz["tempn"].as<String>() + ",最高" + dz["temp"].as<String>() + " 空气质量:" + aqiTxt + ",风向:" + dz["wd"].as<String>() + dz["ws"].as<String>();
  //Serial.println(aa);
  scrollText[3] = "今日" + dz["weather"].as<String>();
  
  deserializeJson(doc, *dataFC);
  JsonObject fc = doc.as<JsonObject>();
  scrollText[4] = "最低温度"+fc["fd"].as<String>()+"℃";
  scrollText[5] = "最高温度"+fc["fc"].as<String>()+"℃";
  
  clk.unloadFont();                               //卸载字体
}

void weatherShow()                               //天气滚动条显示
{
  
  if(millis() - weatherOldTime > 2500){                    //2.5秒切换一次显示内容
    if(scrollText[Dis_Count]){                    //如果滚动显示缓冲区有数据
      clkb.setColorDepth(8);
      clkb.loadFont(ZdyLwFont_20);                //加载汉字字体
      
//      for(int pos = 24; pos>0; pos--){            //24点,每次移动一个点,从下往上移
//        Dis_Scroll(pos);
//      }

      //滚动显示修改为静态显示,滚动的时候太空人会卡顿
      clkb.createSprite(148, 24);                 //创建Sprite,先在Sprite内存中画点,然后将内存中的点一次推向屏幕,这样刷新比较快
      clkb.fillSprite(bgColor);                   //背景色
      clkb.setTextWrap(false);
      clkb.setTextDatum(CC_DATUM);                //显示对齐方式
      clkb.setTextColor(TFT_BLACK, bgColor);      //文本的前景色和背景色
      clkb.drawString(scrollText[Dis_Count],74,12);//打显示内容
      clkb.pushSprite(2,4);                       //Sprite中内容一次推向屏幕
      clkb.deleteSprite();                        //删除Sprite
  
      
      //clkb.deleteSprite();                      //删除Sprite,这个我移动到Dis_Scroll函数里了
      clkb.unloadFont();                          //卸载字体
  
      if (Dis_Count >= 5){                        //总共显示五条信息
        Dis_Count = 0;                            //回第一个
      }
      else{
        Dis_Count += 1;                           //准备切换到下一个  
      }
      //Serial.println(Dis_Count);
    }
    weatherOldTime = millis();
  }
}

void Dis_Scroll(int pos){                         //字体滚动
  clkb.createSprite(148, 24);                     //创建Sprite,先在Sprite内存中画点,然后将内存中的点一次推向屏幕,这样刷新比较快
  clkb.fillSprite(bgColor);                       //背景色
  clkb.setTextWrap(false);
  clkb.setTextDatum(CC_DATUM);                    //显示对齐方式
  clkb.setTextColor(TFT_BLACK, bgColor);          //文本的前景色和背景色
  clkb.drawString(scrollText[Dis_Count],74,pos+12);//打显示内容
  clkb.pushSprite(2,4);                           //Sprite中内容一次推向屏幕
  clkb.deleteSprite();                            //删除Sprite
}

void SoftSerialRx(){
  String revData;
  
  if(mySoftwareSerial.available()){
    revData = mySoftwareSerial.readStringUntil('\n');
    String val = "kaixin";
    revData.trim();
    Serial.println(revData);
    Serial.println(revData.length());
    Serial.println(val.length());
    
//    if( val=="kaixin"){
//      dhStatus =1;
//    }
    if( revData=="kaixin"){
      dhStatus =1;
    }
    if(revData== "chongbai"){
      dhStatus =2;
    }
    if(revData== "shuaku"){
      dhStatus =3;
    }
    if(revData== "tiaopi"){
      dhStatus = 4;
    }

    if(revData== "zhangsan"){
      dhStatus = 5;
    }

    if(revData== "kongtiao"){
      dhStatus = 6;
    }
  }
}

//开心表情
void kaixindh(){
  TJpgDec.drawJpg(0,0,kaixin, sizeof(kaixin));//
  delay(450);
  TJpgDec.drawJpg(0,0,kaixin2, sizeof(kaixin2));//
  delay(900);

}

//耍酷 表情
void shuakudh(){
  TJpgDec.drawJpg(0,0,shuaku, sizeof(shuaku));//
  delay(450);
  TJpgDec.drawJpg(0,0,kaixin2, sizeof(kaixin2));//
  delay(900);
}

//调皮 表情
void tiaopidh(){
  TJpgDec.drawJpg(0,0,tiaopi, sizeof(tiaopi));//
  delay(450);
  TJpgDec.drawJpg(0,0,kaixin2, sizeof(kaixin2));//
  delay(900);
}

//自定义 表情
void zidingyidh(){
  TJpgDec.drawJpg(0,0,tiaopi, sizeof(tiaopi));//
  delay(450);
  TJpgDec.drawJpg(0,0,kaixin2, sizeof(kaixin2));//
  delay(900);
}



//崇拜 表情
void chongbaidh(){
  TJpgDec.drawJpg(0,0,chongbai, sizeof(chongbai));//
## 最后

**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/32f97c82987e78175d78163a4e004ab3.png)

![img](https://img-blog.csdnimg.cn/img_convert/762396250334144bc1bd58d090d837a7.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/925e03ba7e6ea75d921288490f86871d.png)

 ![img](https://img-blog.csdnimg.cn/img_convert/2a7e12e58011bf19efb6cac26247ab52.png)

![img](https://img-blog.csdnimg.cn/img_convert/77b66a8b4f1f580819f34e1df9475d3a.png)

![img](https://img-blog.csdnimg.cn/img_convert/943e68b2339e12a8ae1d78c2e07e897a.png)

![](https://img-blog.csdnimg.cn/img_convert/97bdb18b3558dd9db19bfa0bd3254266.png)

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中...(img-ZrbNbtKR-1715629903861)]

[外链图片转存中...(img-4Id2les0-1715629903862)]

[外链图片转存中...(img-K0aEM5Rg-1715629903863)]

 [外链图片转存中...(img-r4qCJcUD-1715629903864)]

[外链图片转存中...(img-3Ao9QkJS-1715629903864)]

[外链图片转存中...(img-FWBgDDUZ-1715629903865)]

[外链图片转存中...(img-mHoUR1LO-1715629903866)]

 

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!


  • 20
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值