【开源项目学习】esp8266点阵时钟(二)

CSDN垃圾了,保存了草稿还被吞了好几次


目录

Udps::initudp()

httptoolticker.attach()

HttpTool::updateBilibiliFlag()

timestampticker.attach()

DateTimes::timestampAdd

resetTime(NULL)

System::uint8t_to_long(uint8_t *data, int length)

DateTimes::setDateTimes(long timestamp)

//======后期要更新

Udps::updateTime()更新系统时间

sendNTPpacket()发送NTP请求

Udps::getNtpTimestamp()获取当前时间戳

HttpTool::bilibiliFans()刷新bilibili粉丝

HttpTool::loadBuid()从EEPROM中加载bilibili的UID

EEPROMTool.loadData()定义在EEPROMTool.h中

WiFi.status()语句来获取联网状态

获取粉丝数部分代码

initSleepTime(); // 初始化休眠时间


项目来源:ES8266多功能点阵时钟 - 立创EDA开源硬件平台

今天就从setup()函数中的udps.initudp()开始吧

udps.initudp()定义在Udps.cpp中。




Udps::initudp()

//Udps.cpp
//WiFiUDP udp;
void Udps::initudp()
{
  // todo 这里需要判断网络状态
  WiFi.hostByName(ntpServerName, timeServerIP); //将域名转换成IP地址//从网站名获取IP地址
  udp.begin(localPort);                         // 启动监听本地端口
}



httptoolticker.attach()

//(时间, 回调函数)
httptoolticker.attach(5 * 6 * 1000, httptool.updateBilibiliFlag); // 每五分分钟更新一次更新bilibili粉丝flag

 updateBilibiliFlag()定义在HttpTool.cpp文件中。

HttpTool::updateBilibiliFlag()


//置更新flag为TRUE
void HttpTool::updateBilibiliFlag()
{
  is_need_update_bilibili = true;// 判断是否需要更新bilibili粉丝数flag
}



timestampticker.attach()

timestampticker.attach(1, DateTimes::timestampAdd);               // 每一秒叠加一次秒数

DateTimes::timestampAdd

//系统时间戳++
void DateTimes::timestampAdd() { currtimestamp++; }

if (!wifis.isApMode())判断,在wifis.cpp定义




resetTime(NULL)

resetTime(NULL);               // 每次初始化的时候都校准一下时间,这里是随便传的一个参数,不想重新声明参数

resetTime(NULL) 定义在Main.h中

// 重置时间: 重置时间这里有两种方式,一种就是用NTP校准时间,还有一种就是设备没有连接wifi,直接用手机发来的时间戳进行校准时间
void resetTime(uint8_t *data)
{
    if (data != NULL) // 函数中参数如果不为空则使用参数值来作为时间来历
    {
        long timestamp = System::uint8t_to_long(data, 5); // 先将uint_8转成 long
        datetimes.setDateTimes(timestamp + 8 * 60 * 60);  // 将时间戳同步到系统时间中去
    }
    else
    {
        udps.updateTime(); // 校准时间
    }
    functions.reset(); // 重置功能
    initStatus();      // 重置状态
}

uint8t_to_long(data, 5)定义在System.h中

System::uint8t_to_long(uint8_t *data, int length)

// * @brief uint8_t数组转long
long System::uint8t_to_long(uint8_t *data, int length)
{
    long temp = 0;
    for (int i = 0; i < length; i++)
    {
        temp += data[i] << (i * 8);
    }
    return temp;
}

datetimes.setDateTimes(timestamp + 8 * 60 * 60)定义在DateTimes.cpp中

DateTimes::setDateTimes(long timestamp)

//@brief 给时钟芯片和系统时间设置时间信息
void DateTimes::setDateTimes(long timestamp)
{
  currtimestamp = timestamp;            //每秒++
  datetime = DateTime(timestamp);        //这个没找到
}

//======后期要更新

udps.updateTime()定义在Udps.cpp中

Udps::updateTime()更新系统时间

/**
 * @brief 更新系统时间
 *
 */
void Udps::updateTime()
{
  int count = 5;               // 一共尝试五次
  sendNTPpacket();             // 向NTP服务器发请求,先发送更新时间的操作
  int lastSendTime = millis(); // 记录上一次发送更新时间的时间戳
  while (true)                 // 这里用一个死循环来搞定,先发送更新时间的操作
  {
    long timeStamp = getNtpTimestamp(); // 获取当前时间戳
    if (timeStamp != 0)                 // 说明已经获取到了时间信息,这里直接做更新操作
    {
      datetimes->setDateTimes(timeStamp); // 给时钟设置时间
      break;                              // 跳出死循环
    }
    else
    {
      if (millis() - lastSendTime >= 1000) // 如果说发送时间超出上次发送时间1秒钟,则重新发送NTP请求
      {
        sendNTPpacket(); // 向NTP服务器发请求,先发送更新时间的操作
        lastSendTime = millis();
        count--;
      }
    }
    lattice->showLongIcon(2); // 这里延迟两秒是因为过程太快了,交互体验不好//???这不是显示函数嘛
    pilotLight->flashing();   // 校准时间LED闪烁
    delay(100);               // 等待100ms
    if (count < 0)            // 如果说所有机会都用完了
    {
      break; // 跳出死循环
    }
  }
}

sendNTPpacket()定义在Udps.cpp中

sendNTPpacket()发送NTP请求

/**
 * @brief 发送NTP请求
 *
 */
void Udps::sendNTPpacket()
{
  memset(packetBuffer, 0, NTP_PACKET_SIZE);     // 将字节数组的数据全部设置为0
  packetBuffer[0] = 0b11100011;                 // 请求部分其实是有很多数据的,具体的请看参考请求报文说明,这里我们就只设置一个请求头部分即可
  udp.beginPacket(timeServerIP, remoteNtpPort); // 配置远端ip地址和端口
  udp.write(packetBuffer, NTP_PACKET_SIZE);     // 把数据写入发送缓冲区
  udp.endPacket();                              // 发送数据
  Serial.println("send ntp data");              //
}
memset(地址, 替换值, 字节数)
//将地址的字节数的值替换为替换值,替换值0~255
//UDP数据发送准备
udp.beginPacket(timeServerIP, remoteNtpPort); // 配置远端ip地址和端口
//UDP数据接收设备的IP地址(IPAddress类型)、UDP数据接收设备的IP地址监听端口号(uint16_t类型)
//将即将通过UDP协议发送的数据写入发送缓冲区。此函数必须置于beginPacket和endPacket之间。
udp.write(packetBuffer, NTP_PACKET_SIZE);     // 把数据写入发送缓冲区
//此函数仅仅将数据写入发送缓冲区,但是数据不会发送。实施数据发送的函数是endPacket函数。

 long timeStamp = getNtpTimestamp()定义在Udps.cpp,获取当前时间戳

Udps::getNtpTimestamp()获取当前时间戳

// 获取当前时间戳
long Udps::getNtpTimestamp()
{
  int packetSize = udp.parsePacket(); //解析Udp数据包
  if (!packetSize)                    //解析包为空
  {
    return 0;
  }
  else //解析包不为空
  {
    udp.read(packetBuffer, NTP_PACKET_SIZE); // 解析UDP数据包中的数据
    // todo这里获取到的时间其实不是真实的时间,实际上还包含了网络延时的,但是为了方便,这里我们忽略这个因素的存在
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); // 取出t2时间的高位和低位数据拼凑成以秒为单位的时间戳
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    unsigned long secsSince1900 = highWord << 16 | lowWord; // 拼凑成以秒为单位的时间戳(时间戳的记录以秒的形式从 1900-01-01 00:00:00算起)
    const unsigned long seventyYears = 2208988800UL;
    unsigned long timestamp = secsSince1900 - seventyYears; // 前面的32bit是时间戳的秒数(是用1900-01-01 00:00:00开始的秒数,但是我们的是1970年,所以需要减掉2208988800秒)
    timestamp = timestamp + 8 * 60 * 60;                    // 这里加8 是因为时区的问题,如果不加8,得到的结果就会是其他时区的时间
    return timestamp;
  }
}
udp.parsePacket(); //解析Udp数据包
//用于检查是否有UDP数据包传入,返回值为数据包大小
udp.read(packetBuffer, NTP_PACKET_SIZE); // 解析UDP数据包中的数据
// (传入数据包的内存指针, 数据包大小)
//本函数可用于从设备接收到数据中读取数据。函数将会返回等待读取的数据字节数。
//请注意,使用本函数以前需要先调用parsePacket函数。



httptool.bilibiliFans()定义在HttpTool.cpp中

HttpTool::bilibiliFans()刷新bilibili粉丝

//刷新bilibili粉丝
void HttpTool::bilibiliFans()
{
  if (!is_need_update_bilibili)
  {
    return;
  }
  fans = 0;             // 每次都先重置粉丝数量,避免出现问题
  biliUid = loadBuid(); // 每次都重新加载bilibili用户ID
  Serial.println(biliUid);

  if (WiFi.status() != WL_CONNECTED) // 确保wifi网络是可用的,不可用则忽略
  {
    Serial.println("no wifi");
    is_need_update_bilibili = false;
    return;
  }
  espClient.begin(wifiClient, bilibiliFansApi + biliUid); // 这里做法欠妥,我用自己服务器做了一层代理,直接解析了UP的粉丝数
  int httpCode = espClient.GET();
  Serial.println(httpCode);
  if (httpCode > 0)
  {
    if (httpCode == HTTP_CODE_OK)
    {
      String nums = espClient.getString();
      fans = strtol(nums.c_str(), NULL, 10);
      Serial.println(fans);
      is_need_update_bilibili = false;
    }
  }
  espClient.end();
}

biliUid = loadBuid() // 每次都重新加载bilibili用户ID,定义在HttpTool.cpp中

HttpTool::loadBuid()从EEPROM中加载bilibili的UID

// @brief 从EEPROM中加载bilibili的UID
long HttpTool::loadBuid()
{
  long uid = 0;
  uint8_t *temp = EEPROMTool.loadData(BILIBILI_UID, 5); // 这里的97处理的不得当,后续优化,但是不影响实际功能
  for (int i = 0; i < 5; i++)
  {
    uid += temp[i] << (i * 8);
  }
  // 用完以后删除内存
  free(temp);
  return uid;
}

EEPROMTool.loadData(BILIBILI_UID, 5)

人家UID都是5位的,我八位!

EEPROMTool.loadData()定义在EEPROMTool.h中

//   * @brief EEPROM获取数据
  uint8_t *loadData(int offset, int length)
  {
    unsigned char *arr = new uint8_t[length];
    for (int i = 0; i < length; i++)
    {
      arr[i] = EEPROM.read(offset + i);
    }
    return arr;
  }

WiFi.status()语句来获取联网状态

返回值类型为uint8_t。以下是返回值数值以及对应的信息:

255: WL_NO_SHIELD – 返回值为255说明无扩展板。8266本来带有网络功能,不需要额外的扩展板(sheld),因此一般不会出现这个报错
0:​ WL_IDLE_STATUS – 返回值为0说明正在尝试连接
1​: WL_NO_SSID_AVAIL – 返回值为1说明没有找到设定的SSID的网络
2​: WL_SCAN_COMPLETED – 返回值为2说明网络扫描完毕
3:​ WL_CONNECTED – 返回值为3说明连接成功成功
4: WL_CONNECT_FAILED – 返回值为4说明连接失败
5: WL_CONNECTION_LOST – 返回值为5说明连接丢失
6: WL_DISCONNECTED – 返回值为6说明未连接

获取粉丝数部分代码

参考:

ESP8266 – ESP8266HTTPClient库 – 太极创客icon-default.png?t=M3K6http://www.taichi-maker.com/homepage/iot-development/iot-dev-reference/esp8266-c-plus-plus-reference/esp8266httpclient/

espClient.begin(wifiClient, bilibiliFansApi + biliUid); // 这里做法欠妥,我用自己服务器做了一层代理,直接解析了UP的粉丝数
  int httpCode = espClient.GET();
  Serial.println(httpCode);
  if (httpCode > 0)
  {
    if (httpCode == HTTP_CODE_OK)
    {
      String nums = espClient.getString();
      fans = strtol(nums.c_str(), NULL, 10);
      Serial.println(fans);
      is_need_update_bilibili = false;
    }
  }
  espClient.end();
//本函数用于设置ESP8266发送HTTP请求的目标URL
espClient.begin(wifiClient, bilibiliFansApi + biliUid); 
//(请求网址, 请求的网络服务器端口)
int httpCode = espClient.GET();
//从指定的资源请求数据。返回值:服务器状态码
//此函数可用于获取服务器响应中的响应体信息。响应体信息将以字符串的形式进行返回。
String nums = espClient.getString();
//返回服务器HTTP响应中的响应体数据。(返回值类型:String)
  espClient.end();
//当ESP8266发送HTTP请求结束后,我们应该调用此函数来清除ESP8266的接收缓存以便设备再次接收服务器发来的响应信息。



initSleepTime(); // 初始化休眠时间

定义在Main.h中

void initSleepTime()
{
    // 先从内存中加载
    uint8_t *t = EEPROMTool.loadData(SLEEP_TIME, 5);
    for (int i = 0; i < 5; i++)
    {
        sleepTime[i] = t[i];
    }
    free(t);
}

初始化的东西看完了

初始化的东西看完了

 

猜你喜欢

转载自blog.csdn.net/qq_41650023/article/details/124628833