本帖最后由 aramy 于 2024-4-3 20:51 编辑  
 
FireBeetle 2 ESP32 C6到手把玩了几天了。是时候去实现申请时定下的目标了:尝试一下esp32系列的低功耗功能。用太阳能电池板,制作一个室外的温湿度气象站。 
首先分析使用场景:计划在房屋外边搭建一个气象站。离房屋不会太远,所以WiFi是能够覆盖到,计划使用物联网通讯,收集温湿度信息。虽然离房屋不远,但是室外是没有电源的,使用电池供电,就存在更换电池的问题,所以打算使用电池加太阳能板补能的方式解决能源问题。白天通过太阳能给锂电池补能,夜间就通过锂电池给单片机供电,同时单片机必须实现低功耗,用来节约电能。 
 
ESP32低功耗可以通过睡眠模式实现。可以进入light-sleep和deep-sleep模式。 
light-sleep:CPU暂停运行,wifi/蓝牙基带和射频关闭。RTC、ULP运行,任何唤醒事件都会唤醒芯片。数字外设、大部分内存和CPU都会被停用(停用时钟),电源功耗也会降低,从light-sleep模式下唤醒后外设和CPU会接回时钟源并继续工作,他们的外部状态会被保存。 
deep-sleep:CPU、大部分外设掉电,wifi/蓝牙基带和射频关闭,进有RTC、ULP运行,wifi和蓝牙连接数据被转移到RTC内存中。仅有一部分中断源会唤醒芯片。由APB_CLK时钟提供是时钟源的CPU、大部分内存和所有数字外设都会掉电;只有片上RTC控制器、RTC外设、ULP和RTC内存会被保留电源。 
了解了两种睡眠模式,这里当然就是去使用最节能的deep-sleep模式啦!有睡眠就要有唤醒,这里选用的是时间唤醒。
			
			
			- esp_sleep_enable_timer_wakeup(time_in_us)
 
  复制代码
  
 
为了适应低功耗,就去掉了自制的扩展板。接了个额外的SHT30模块,使用板载的I2C接口,和模块连接起来。这里我使用了 Arduino-sht的库,用来驱动SHT30;还使用了adafruit_mqtt库,这样收集到的信息就通过mqtt上传到物联网上了,这里物联网选用了百度的物联网平台。  
 
 
 
与传统的Arduino编程方式有所区别。传统的Arduino运行方式为:step方法中对系统进行初始化,然后程序在loop方法中不停的循环。而使用deep-sleep方式工作,则每次唤醒都需要对系统进行初始化,包括连wifi、连mqtt、读取温湿度、上传传感器信息,然后进入deep-sleep状态,不停地重复。  
 
基本流程就比较简单,在连接wifi和连接mqtt过程中,遇到错误会重试,重试一定次数依然失败就进入睡眠状态,等待时钟的唤醒。 - #include<WiFi.h>
 - #include <esp_sleep.h>
 - #include "driver/rtc_io.h"
 - #include "WiFiClient.h"
 - #include "Adafruit_MQTT.h"
 - #include "Adafruit_MQTT_Client.h"
 - #include <Wire.h>
 - #include "SHTSensor.h"
 - 
 - #define WIFI_SSID "AAA"
 - #define WIFI_PASSWORD "xxxxxxxx"
 - 
 - const char *MQTT_SERVER = "afgsmmu.iot.gz.baidubce.com";
 - const int MQTT_PORT = 1883;
 - const char *MQTT_USRNAME = "your_mqtt_username";
 - const char *MQTT_PASSWD = "your_mqtt_passwd";
 - const char *TOPIC = "$iot/AICAM/user/ismask";
 - 
 - WiFiClient espClient;
 - Adafruit_MQTT_Client mqtt(&espClient, MQTT_SERVER, MQTT_PORT, MQTT_USRNAME, MQTT_PASSWD);
 - Adafruit_MQTT_Publish pub = Adafruit_MQTT_Publish(&mqtt, TOPIC); // 发布主题
 - 
 - #define ANALOG_PIN_0   0   //电池AD管脚
 - SHTSensor sht;
 - 
 - #define uS_TO_S_FACTOR 1000000ULL   //计时单位 秒
 - 
 - void mcusleep() {
 -   digitalWrite(15, LOW);      //关灯
 -   Serial.flush();
 -   esp_deep_sleep_start();
 - }
 - 
 - void MQTT_connect()//连接mqtt服务器,5s连接一次  连接超过5次还连不上 就休眠
 - {
 -   int8_t ret;
 -   if (mqtt.connected())
 -   {
 -     return;
 -   }
 -   Serial.print("Connecting to MQTT... ");
 -   uint8_t retries = 5;//尝试5次
 -   while ((ret = mqtt.connect()) != 0)
 -   {
 -     Serial.println(mqtt.connectErrorString(ret));
 -     Serial.println("Retying MQTT connection in 5 seconds...");
 -     mqtt.disconnect();
 - //    digitalWrite(15, LOW);      //关灯
 -     delay(5000);
 -     retries--;
 -     if (retries == 0) //如果五次都没连接上进入死循环
 -     {
 -       esp_sleep_enable_timer_wakeup(60 * uS_TO_S_FACTOR);
 -       Serial.println("MQTT connect fail! Going to sleep now");
 -       mcusleep();
 -     }
 -     Serial.println("MQTT Connected!");
 -   }
 - }
 - 
 - void setup() {
 -   Serial.begin(115200);
 -   pinMode(15, OUTPUT);
 -   digitalWrite(15, HIGH);       //亮灯
 -   //  rtc_gpio_isolate(GPIO_NUM_15);
 -   Wire.begin();
 -   pinMode(ANALOG_PIN_0, INPUT);     //电源电池电压测量
 -   uint8_t retries = 10;//尝试连接wifi 10次
 -   WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
 -   while (!WiFi.isConnected())
 -   {
 -     digitalWrite(15, LOW);      //关灯
 -     delay(5000);
 -     digitalWrite(15, HIGH);       //亮灯
 -     retries--;
 -     Serial.print(".");
 -     if (retries == 0) //如果五次都没连接上进入死循环
 -     {
 -       esp_sleep_enable_timer_wakeup(60 * uS_TO_S_FACTOR);
 -       Serial.println("wifi connect fail! Going to sleep now");
 -       mcusleep();
 -     }
 -   }
 -   Serial.println("WIFI connect success!");
 - 
 -   MQTT_connect();
 -   sht.init();
 -   sht.setAccuracy(SHTSensor::SHT_ACCURACY_MEDIUM); // only supported by SHT3x
 - }
 - void loop() {             //空循环
 -   uint analog_value = 0;
 -   char msg[100];
 -   analog_value = analogRead(ANALOG_PIN_0);  //读取电池电压
 -   sht.readSample();                     //读取sht30
 -   Serial.printf("bat:%.1f\t RH:%.2f\t T:%.2f\n", float(analog_value) / 497.5, sht.getHumidity(), sht.getTemperature());
 -   sprintf(msg, "{"Bat":%.2f,"Humidity":%.2f,"Temperature":%.2f}", float(analog_value) / 497.5, sht.getHumidity(), sht.getTemperature());
 -   Serial.println(msg);
 -   pub.publish(msg);
 - 
 -   esp_sleep_enable_timer_wakeup(30 * uS_TO_S_FACTOR);
 -   Serial.println("Finsh work! Going to sleep now");
 -   delay(100);
 -   mcusleep();
 -   delay(10000);     //代码到不了这里
 - }
 
  复制代码 
1、管脚0,是接到通过电阻分压后的电源上,可以通过管脚0测量电源电池的电压。 2、板子一旦进入deep-sleep状态了,那么就是连串口都会消失掉的。所以在调试烧写代码时,会找不到串口号,无法烧写。此时烧写板子就需要按住板子上的BOOT按键,再按下RST按键,然后松开,进入烧写模式,即可有串口出现,此时可以正常烧写。   
  
 
 
 
使用Python写个简单的上位机,用来接收mqtt的消息,只是简单地测试一下物联网。接下来就是要使用电池做测试,看看一天能耗电池多少电量,然后决定用多大的太阳能板进行补能。- #!/usr/bin/env python
 - # -*- coding:utf-8 -*-
 - # @FileName  :mqtt_recvmsg.py
 - # @Time      :2024/3/25 11:20
 - # @Author    :aramy
 - import paho.mqtt.client as mqtt
 - from unit.mqttinfo import MQTT_INFO
 - 
 - 
 - class MqttMsg():
 -     def __init__(self):
 -         super(MqttMsg, self).__init__()
 -         self.mqttinfo=MQTT_INFO()
 -         self.client=mqtt.Client()
 -         self.message=""
 - 
 -     def on_connect(self,client, userdata, flags, rc):
 -         print("Connected with result code: " + str(rc))
 - 
 -     def on_message(self,client, userdata, msg):
 -         print(msg.topic + " " + str(msg.payload))
 -         # self.sinGetNewMsg.emit(str(msg.payload,encoding = "utf-8"))
 - 
 - 
 -     def run(self):
 -         self.client.username_pw_set(self.mqttinfo.mqtt_name, self.mqttinfo.mqtt_pwd)  # 设置用户名,密码
 -         self.client.connect(self.mqttinfo.broker_address, self.mqttinfo.port, 60)  # 连接服务 keepalive=60
 -         self.client.on_connect = self.on_connect
 -         self.client.on_message = self.on_message
 -         self.client.subscribe(self.mqttinfo.publishtopic[0], qos=0)
 -         self.client.loop_forever()  # 保持连接
 - 
 - if __name__ == "__main__":
 -     mqtt=MqttMsg()
 -     mqtt.run()
 
  复制代码
  
 
 
 
 |