FireBeetle 2 ESP32 C6 试用——制作一个室外的温湿度气象站
本帖最后由 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;
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, qos=0)
self.client.loop_forever()# 保持连接
if __name__ == "__main__":
mqtt=MqttMsg()
mqtt.run()
如果我想从I2C接口获取其他的传感器数据,是不是还得用其他的库文件? 余老师 发表于 2024-4-6 20:31
如果我想从I2C接口获取其他的传感器数据,是不是还得用其他的库文件?
库文件 一般是针对具体传感器的。走i2c协议都是试用wire文件了。所以 要是能找到具体的库文件,就要加载库文件,找不到的话,就用wire自己写方法了。
页:
[1]