【FireBeetle 2 ESP32 C6】电池供电和功耗检测测试
<p><strong>测试介绍</strong></p><p>ESP32C6的功率管理较为单一,功耗管理, 通过选择时钟频率、占空比、Wi-Fi工作模式和单独控制内部器件的电源,实现精准电源控制。ESP32C6设计四种功耗模式:Active、Modem-sleep、Light-sleep、Deep-sleep, Deep-sleep 模式下功耗低至7µA,并且该模式下可以保持低功耗存储器 (LP memory)的内容仍保持工作和RTC 定时器工作。</p>
<p>本次测试使用FireBeetle 2开发板和可调电源,使用esp_deep_sleep_start()函数可以进入deep_sleep模式。使用EXT0/1 wakeup中断唤醒。使用OLED显示屏测试内容。</p>
<p><strong>测试设置</strong></p>
<p>1、本来使用电池供电,但是电池供电不能改变电压,所以使用可调的电源来代替。本次测试电压为3.0V供电。</p>
<p>2、程序启动后测试MQTT模式通讯和在OLED屏显示内容。</p>
<p>将MQTT程序进行修改。执行如下命令</p>
<pre>
<code class="language-bash">idf.py set-target esp32c6
idf.py menuconfig</code></pre>
<p> </p>
<p> 3、使用延时函数来进入Deep-sleep函数。</p>
<p><strong>测试程序</strong></p>
<p>首先将MQTT的wifi密码设置完成,确认能够正常工作。</p>
<p> </p>
<p>将该程序加入OLED SSD1306显示内容。</p>
<pre>
<code class="language-cpp">
flash 重复数据问题 地址映射
Could not find `protoc` installation and this build crate cannot proceed without
this knowledge. If `protoc` is installed and this crate had trouble finding
it, you can set the `PROTOC` environment variable with the specific path to your
installed `protoc` binary.You can download it from https://github.com/protocolbuffers/protobuf/releases or from your package manager.
stable-x86_64-pc-windows-gnu stable-x86_64-pc-windows-msvc
/* MQTT (over TCP) Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "ssd1366.h"
#include "font8x8_basic.h"
#define SDA_PIN GPIO_NUM_19
#define SCL_PIN GPIO_NUM_20
static const char *TAG = "mqtt_example";
void i2c_master_init() {
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = SDA_PIN,
.scl_io_num = SCL_PIN,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL
};
i2c_param_config(I2C_NUM_0, &i2c_config);
i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
}
void ssd1306_init() {
esp_err_t espRc;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
// 向 I2C 总线发送启动信号,表示一个新的传输事务即将开始。
i2c_master_start(cmd);
// 写入一个字节到 I2C 总线。这里使用 OLED 模块的 I2C 地址,左移一位并加上写入标志,指示写入操作
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
// 写入 OLED 控制命令流的字节,表示后续的字节是控制命令。
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
// 写入 OLED 控制命令,设置充电泵
i2c_master_write_byte(cmd, OLED_CMD_SET_CHARGE_PUMP, true);
// 写入参数字节
i2c_master_write_byte(cmd, 0x14, true);
// 写入 OLED 控制命令,设置段重映射,即左右反转
i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP, true); // reverse left-right mapping
// 写入 OLED 控制命令,设置行扫描模式,即上下反转
i2c_master_write_byte(cmd, OLED_CMD_SET_COM_SCAN_MODE, true); // reverse up-bottom mapping
// 写入 OLED 控制命令,打开 OLED 显示
i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_ON, true);
// 向 I2C 总线发送停止信号,表示传输事务结束。
i2c_master_stop(cmd);
// 执行 I2C 命令序列,将前面构建的命令发送到 I2C 总线上。返回的 espRc 变量会保存执行结果。
espRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);
if (espRc == ESP_OK) {
ESP_LOGI(tag, "OLED configured successfully");
} else {
ESP_LOGE(tag, "OLED configuration failed. code: 0x%.2X", espRc);
}
// 释放创建的 I2C 命令句柄,以便后续的使用
i2c_cmd_link_delete(cmd);
}
void task_ssd1306_display_text(void *arg_text) {
char *text = (char *)arg_text;
uint8_t text_len = strlen(text);
i2c_cmd_handle_t cmd;
uint8_t cur_page = 0;
// 重置起始位置
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
i2c_master_write_byte(cmd, 0x00, true); // reset column
i2c_master_write_byte(cmd, 0x10, true);
i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // reset page
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
for (uint8_t i = 0; i < text_len; i++) {
if (text == '\n') {
// 换行
cur_page++;
if (cur_page >= 8) {
break; // 显示完整文本,超出屏幕范围,退出
}
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true);
i2c_master_write_byte(cmd, 0x00, true); // reset column
i2c_master_write_byte(cmd, 0x10, true);
i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // increment page
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
} else {
// 显示字符
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true);
i2c_master_write(cmd, font8x8_basic_tr[(uint8_t)text], 8, true);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
}
}
vTaskDelete(NULL);
}
void generate_string(int columns, int newlines, char* ret) {
char buffer;
int j=0;
for(int page=0;page<newlines;page++){
for(int i=0;i<columns;i++){
buffer = ' ';
j++;
}
buffer='\n';
j++;
}
buffer = '\0';
strcpy(ret, buffer);
}
static void log_error_if_nonzero(const char *message, int error_code)
{
if (error_code != 0) {
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
}
}
/*
* @brief Event handler registered to receive MQTT events
*
*This function is called by the MQTT client event loop.
*
* @param handler_args user data registered to the event.
* @param base Event base for the handler(always MQTT Base in this example).
* @param event_id The id for the received event.
* @param event_data The data for the event, esp_mqtt_event_handle_t.
*/
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
esp_mqtt_event_handle_t event = event_data;
esp_mqtt_client_handle_t client = event->client;
int msg_id;
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
log_error_if_nonzero("captured as transport's socket errno",event->error_handle->esp_transport_sock_errno);
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
}
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
static void mqtt_app_start(void)
{
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = CONFIG_BROKER_URL,
};
#if CONFIG_BROKER_URL_FROM_STDIN
char line;
if (strcmp(mqtt_cfg.broker.address.uri, "FROM_STDIN") == 0) {
int count = 0;
printf("Please enter url of mqtt broker\n");
while (count < 128) {
int c = fgetc(stdin);
if (c == '\n') {
line = '\0';
break;
} else if (c > 0 && c < 127) {
line = c;
++count;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
mqtt_cfg.broker.address.uri = line;
printf("Broker url: %s\n", line);
} else {
ESP_LOGE(TAG, "Configuration mismatch: wrong broker url");
abort();
}
#endif /* CONFIG_BROKER_URL_FROM_STDIN */
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(client);
}
void app_main(void)
{
i2c_master_init();
ssd1306_init();
// 清屏操作
const int columns = 16;
const int page = 8;
char space;
generate_string(columns, page, space);
// 清除屏幕内容
xTaskCreate(&task_ssd1306_display_text, "ssd1306_display_text", 2048, (void *)space, 6, NULL);
// 间隔一会防止进程有干扰
vTaskDelay(500/portTICK_PERIOD_MS);
xTaskCreate(&task_ssd1306_display_text, "ssd1306_display_text", 2048,
(void *) "Hello world!\nMulitine is OK!\nAnother line", 6, NULL);
ESP_LOGI(TAG, " Startup..");
ESP_LOGI(TAG, " Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, " IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE);
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
esp_log_level_set("transport", ESP_LOG_VERBOSE);
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
mqtt_app_start();
}
</code></pre>
<p>使得程序可以显示,演示进入esp_deep_sleep_start()模式。</p>
<p><strong> 测试过程</strong></p>
<p>将电源调试到3.3V和3.0V测试。</p>
<p> </p>
<p>连接测试</p>
<p> </p>
<p>系统进入deep_sleep模式,但是可以发现,屏幕显示好像没有变化,但是ping主机确无法通过了。</p>
<p> </p>
<p>使用短路引脚无法唤醒。只能重新上电。</p>
<p>Deep-sleep可以通过RTC进行唤醒吗?</p>
wangerxian 发表于 2024-6-14 20:53
Deep-sleep可以通过RTC进行唤醒吗?
<p>据说可以,但是开发板无法设置RTC,勘误表说RTC的设计有缺陷会受到干扰。</p>
<p>远程唤醒设备的技术有哪些种类?带有无线模块自组网的话</p>
hellokitty_bean 发表于 2024-6-16 20:56
远程唤醒设备的技术有哪些种类?带有无线模块自组网的话
<p>深度的睡眠模式理论上只能外部唤醒,所以无线网络不能在该模式使用,所以可以使用的方式只能是外部方式。例如:gpio输入、RTC这样的方式</p>
bigbat 发表于 2024-6-17 10:21
深度的睡眠模式理论上只能外部唤醒,所以无线网络不能在该模式使用,所以可以使用的方式只能是外部方式。 ...
<p>感谢大神回复。。。。。。。</p>
<p>Ad-Hoc中的微尘节点为节约电池,往往处于睡眠状态,只在需要时唤醒,好奇它是如何唤醒远程节点的。<img height="48" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/smile.gif" width="48" /></p>
页:
[1]