云天 发表于 2024-4-4 11:39:41

智能喝水提醒器

本帖最后由 云天 于 2024-4-4 11:39 编辑

【项目背景】
长时间在电脑前工作,不太容易想起来喝水,今天这个项目是用来定时提醒喝水。
【项目设计】
主控使用Beetle ESP32-c3,使用它的原因,一是因为体积小,有集成充电管理,支持Wi-Fi 。通过从网络时间服务器获取时间,并使用ESP32自带的RTC时钟保持时间更新,每半小时提醒一次。使用UART通讯控制电机及灯光驱动模块的PWM输出,调节LED柔性灯丝。
【硬件准备】
1.3V 260mm 柔性软灯丝
直径2mm,长度260mm的3V柔性软灯丝,可用于DIY灯光装饰,DIY灯泡球,360°全角度发光灯具等。
https://www.dfrobot.com.cn/data/video/1684745025162.mp4

2.灯光&电机驱动板
可以用Python代码控制、WINDOWS上位机控制、UART通讯编程控制、电位器手动控制共四种方式调节的PWM驱动器。用于直流电机调速、灯光调节等应用场景。本产品支持5V~24V宽电压输入,并具有10A的承载能力,能驱动50W左右的直流电机(由于电机端口极性固定,并不能控制电机方向)或者整卷5米左右的灯带。适用于水泵水量控制、散热风扇速度控制、灯光亮度调节、电动工具改造、电机灯带产品测试、电机速度自动化控制、灯光效果自动化控制等场景。

3.Beetle ESP32-C3
基于ESP32-C3的小体积主控,集成充电管理,适用于物联网项目


【硬件连接】
灯光&电机驱动板使用9V电池供电,柔性软灯丝接PWM OUT,通过UART与Beetle ESP32-c3的TX、RX引脚连接。Beetle ESP32-c3使用3.7V锂电池通过BAT引脚供电。

【编写程序】
    柔性软灯丝发热较大,setPwmDuty(80);设置为80,如设置高了,时间长会烧毁灯丝。

#definePWM_ENABLE         0x01
#definePWM_DISENABLE      0x00
#defineDEV_ADDR             0x32
#defineDUTY_REG_ADDR      0x0006
#defineFREQ_REG_ADDR      0x0007
#definePWM_EN_REG_ADDR      0x0008


static uint16_t CheckCRC(uint8_t *data, uint8_t len){
uint16_t crc = 0xFFFF;
for(uint8_t pos = 0; pos < len; pos++){
    crc ^= (uint16_t)data;
    for(uint8_t i = 8; i != 0; i-- ){
      if((crc & 0x0001) != 0){
      crc >>= 1;
      crc ^= 0xA001;
      }else{
      crc >>= 1;
      }
    }
}
crc = ((crc & 0x00FF) << 8) | ((crc & 0xFF00) >> 8);
return crc;
}

static void WriteRegValue(uint16_t regAddr, uint16_t value){
uint8_t tempData;
uint16_t crc;
tempData = DEV_ADDR;
tempData = 0x06;
tempData = (regAddr >> 8) & 0xFF;
tempData = regAddr & 0xFF;
tempData = (value >> 8) & 0xFF;
tempData =value & 0xFF;
crc = CheckCRC(tempData, 6);
tempData = (crc >> 8) & 0xFF;
tempData = crc & 0xFF;
for(uint8_t i = 0 ;i < 8; i++){
    Serial.print((char)tempData);
}
Serial.flush();
}


static void setPwmDuty(uint8_t duty){
WriteRegValue(DUTY_REG_ADDR, (uint16_t)duty);
}

static void setPwmFreq(uint8_t freq){
WriteRegValue(FREQ_REG_ADDR, (uint16_t)freq);
}

static void setPwmEnable(uint8_t pwmStatus){
WriteRegValue(PWM_EN_REG_ADDR, (uint16_t)pwmStatus);
}

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
delay(1000);
setPwmFreq(10);
delay(50);
setPwmDuty(0);
delay(50);
setPwmEnable(PWM_ENABLE);
delay(50);
}

void loop() {
    setPwmDuty(80);
    delay(2000);
    setPwmDuty(0);
    delay(2000);
}



【定时设置】
连接WIFI,并从 "pool.ntp.org"网络时间服务器获取时间,当时间每到半小时(timeinfo.tm_min==30)亮灯提醒喝水。

#include <WiFi.h>

const char *ssid = "*******";    //WIFI名称
const char *password = "********"; //WIFI密码

const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 8 * 3600;
const int daylightOffset_sec = 0;
#definePWM_ENABLE         0x01
#definePWM_DISENABLE      0x00
#defineDEV_ADDR             0x32
#defineDUTY_REG_ADDR      0x0006
#defineFREQ_REG_ADDR      0x0007
#definePWM_EN_REG_ADDR      0x0008


static uint16_t CheckCRC(uint8_t *data, uint8_t len){
uint16_t crc = 0xFFFF;
for(uint8_t pos = 0; pos < len; pos++){
    crc ^= (uint16_t)data;
    for(uint8_t i = 8; i != 0; i-- ){
      if((crc & 0x0001) != 0){
      crc >>= 1;
      crc ^= 0xA001;
      }else{
      crc >>= 1;
      }
    }
}
crc = ((crc & 0x00FF) << 8) | ((crc & 0xFF00) >> 8);
return crc;
}

static void WriteRegValue(uint16_t regAddr, uint16_t value){
uint8_t tempData;
uint16_t crc;
tempData = DEV_ADDR;
tempData = 0x06;
tempData = (regAddr >> 8) & 0xFF;
tempData = regAddr & 0xFF;
tempData = (value >> 8) & 0xFF;
tempData =value & 0xFF;
crc = CheckCRC(tempData, 6);
tempData = (crc >> 8) & 0xFF;
tempData = crc & 0xFF;
for(uint8_t i = 0 ;i < 8; i++){
    Serial.print((char)tempData);
}
Serial.flush();
}


static void setPwmDuty(uint8_t duty){
WriteRegValue(DUTY_REG_ADDR, (uint16_t)duty);
}

static void setPwmFreq(uint8_t freq){
WriteRegValue(FREQ_REG_ADDR, (uint16_t)freq);
}

static void setPwmEnable(uint8_t pwmStatus){
WriteRegValue(PWM_EN_REG_ADDR, (uint16_t)pwmStatus);
}
void printLocalTime()
{
    struct tm timeinfo;
    if (!getLocalTime(&timeinfo))
    {
      Serial.println("Failed to obtain time");
      return;
    }
    //Serial.println(&timeinfo, "%F %T %A"); // 格式化输出
    //Serial.println(timeinfo.tm_sec);
    if(timeinfo.tm_min==30 )
    {
      setPwmDuty(80);
    }
    else{
      setPwmDuty(0);
    }
}
void setup()
{
Serial.begin(9600);
delay(1000);
setPwmFreq(10);
delay(50);
setPwmDuty(0);
delay(50);
setPwmEnable(PWM_ENABLE);
delay(50);

    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED)
    {
      delay(500);
      Serial.print(".");
    }
    Serial.println("WiFi connected!");

    // 从网络时间服务器上获取并设置时间
    // 获取成功后芯片会使用RTC时钟保持时间的更新
    configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
    printLocalTime();

    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
    Serial.println("WiFi disconnected!");

}

void loop()
{
    //setPwmDuty(5);
    printLocalTime();
    //delay(2000);
    //setPwmDuty(0);
    delay(200);
}





【演示视频】
https://www.bilibili.com/video/BV1EZ421B7Zz/?share_source=copy_web
页: [1]
查看完整版本: 智能喝水提醒器