ESP8266集成开发BL0942电量采集功能
2025/10/12大约 10 分钟
ESP8266集成开发BL0942电量采集功能
BL0942_ESP.h
#ifndef BL0942_h
#define BL0942_h
#include "driver/gpio.h"
void bl0942_init(void);
void reset_energy_data(void);
#endifBL0942_ESP.c
#include "BL0942_ESP82.h"
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "lwrb.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "nvs_config.h"
#include "esp_err.h"
#include <time.h>
#include "iot_mqtt.h"
#include <math.h>
TaskHandle_t bl0942_parser_taskHandle = NULL;
TaskHandle_t bl0942_taskHandle = NULL;
TaskHandle_t u_mqtt_taskHandle = NULL;
lwrb_t lwrb_bl0942; // 定义环形缓冲区对象
volatile uint8_t lwrb_bl0942_buffer[2048 + 1]; // 定义缓冲区内存空间
// 宏定义原型 (通常在esp_err.h中定义)
#define ESP_RETURN_ON_ERROR(x, tag, msg) \
do \
{ \
esp_err_t __err_rc = (x); \
if (__err_rc != ESP_OK) \
{ \
ESP_LOGE(tag, "%s: %s", msg, esp_err_to_name(__err_rc)); \
return __err_rc; \
} \
} while (0)
#define UART_PORT_NUM UART_NUM_0
#define RX_BUF_SIZE 1024
#define BAUD_RATE 9600
uint16_t old_reg = 0;
uint32_t k = 0;
// HLW8032寄存器定义
typedef struct
{
uint8_t state_reg;
uint32_t voltage_param;
uint32_t voltage_val;
float real_voltage_val;
int32_t current_param;
uint32_t current_val;
float real_current_val;
uint32_t power_param; // 功率参数寄存器 5313000
float apparent_power; // 视在功率
float power_factor; //功率因数
float active_power; // 有功功率
uint8_t data_update;
uint32_t pf_counter;
uint8_t checksum;
} bl0942_frame_t;
static bl0942_frame_t frame = {
.state_reg = 0,
.voltage_param = 0,
.voltage_val = 0,
.real_voltage_val = 0.0,
.current_param = 0,
.current_val = 0,
.real_current_val = 0.0,
.power_param = 0,
.apparent_power = 0.0,
.power_factor = 0.0,
.active_power = 0.0,
.data_update = 0,
.pf_counter = 0,
.checksum = 0
};
static void parse_bl0942_data(uint8_t *data, bl0942_frame_t *frame_p);
static uint32_t calculate_pulse_delta(uint32_t current, uint32_t last);
static float calculate_pulse_per_kwh(bl0942_frame_t *frame_p);
// 解析成功标识位
volatile uint8_t parse_success = 0;
// 在文件顶部添加宏定义
#define BL0942_COUNTER_MAX 0xFFFFFF // 24位计数器最大值(16,777,215)
#define MAX_REASONABLE_DELTA 10000 // 合理增量阈值(根据实际用电情况调整)
#define MAX_C 20
static QueueHandle_t uart_queue;
static const char *TAG = "BL0942_ESP82";
// static const uint32_t SAVE_INTERVAL = 3600000; // 1小时保存一次到NVS(毫秒)
static const uint32_t SAVE_INTERVAL = 60000; // 1分钟保存一次到NVS(毫秒)
// 1. 优化全局变量定义区
typedef struct
{
float voltage_coef; // 电压系数
float current_coef; // 电流系数
float daily_energy; // 当日用电量(kWh)
float total_energy; // 累计总用电量(kWh)
uint32_t last_pulse; // 上次脉冲计数值
uint32_t last_send_counter; // 上次日期检查时间
uint8_t current_day; // 当前日期(1-31)
uint32_t last_save; // 上次保存时间
bool initialized; // 初始化标志
} bl0942_ctx_t;
static bl0942_ctx_t ctx = {
.voltage_coef = 1.88f,
.current_coef = 1.0f,
.total_energy = 0.0f,
.daily_energy = 0.0f,
.last_pulse = 0,
.last_send_counter = 0,
.current_day = 0,
.last_save = 0,
.initialized = false};
// 2. 优化NVS存储函数
static esp_err_t bl0942_save_energy()
{
nvs_handle_t handle;
ESP_RETURN_ON_ERROR(nvs_open("bl0942", NVS_READWRITE, &handle), TAG, "NVS open failed");
// 获取当前时间戳作为版本号
uint32_t version = (uint32_t)time(NULL);
// 主备份存储
ESP_RETURN_ON_ERROR(nvs_set_blob(handle, "energy_main", &ctx.total_energy, sizeof(ctx.total_energy)), TAG, "Save main failed");
// 保存ctx.daily_energy
ESP_RETURN_ON_ERROR(nvs_set_blob(handle, "daily_energy", &ctx.daily_energy, sizeof(ctx.daily_energy)), TAG, "Save daily energy failed");
// 保存
ESP_RETURN_ON_ERROR(nvs_set_u32(handle, "energy_ver", version), TAG, "Save main version failed");
// 次备份存储
ESP_RETURN_ON_ERROR(nvs_set_blob(handle, "energy_backup", &ctx.total_energy, sizeof(ctx.total_energy)), TAG, "Save backup failed");
// 保存ctx.daily_energy
ESP_RETURN_ON_ERROR(nvs_set_blob(handle, "daily_energy_bk", &ctx.daily_energy, sizeof(ctx.daily_energy)), TAG, "Save backup daily energy failed");
ESP_RETURN_ON_ERROR(nvs_set_u32(handle, "energy_ver_bk", version), TAG, "Save backup version failed");
ESP_RETURN_ON_ERROR(nvs_commit(handle), TAG, "Commit failed");
nvs_close(handle);
return ESP_OK;
}
// 修改加载函数实现双备份恢复
static esp_err_t bl0942_load_energy(void)
{
nvs_handle_t handle;
ESP_RETURN_ON_ERROR(nvs_open("bl0942", NVS_READWRITE, &handle), TAG, "_________________NVS open failed");
float main_energy = 0.0f;
float daily_energy = 0.0f;
float backup_energy = 0.0f;
float daily_energy_bk = 0.0f;
uint32_t main_ver = 0;
uint32_t backup_ver = 0;
uint32_t version = time(NULL);
// 读取主备份
size_t len = sizeof(main_energy);
esp_err_t main_ret = nvs_get_blob(handle, "energy_main", &main_energy, &len);
if (main_ret == ESP_ERR_NVS_NOT_FOUND)
{
ESP_LOGW(TAG, "Energy data not found in NVS, initializing to 0.0");
ctx.total_energy = 0.0f;
// 尝试写入初始值
esp_err_t main_ret_init = nvs_set_blob(handle, "energy_main", &ctx.total_energy, sizeof(ctx.total_energy));
if (main_ret_init == ESP_OK)
{
main_ret_init = nvs_commit(handle);
if (main_ret_init != ESP_OK)
{
ESP_LOGE(TAG, "Failed to commit initial energy value: 0x%x (%s)",
main_ret_init, esp_err_to_name(main_ret_init));
}
}
else
{
ESP_LOGE(TAG, "Failed to write initial energy value: 0x%x (%s)",
main_ret_init, esp_err_to_name(main_ret_init));
}
}
else
{
ESP_LOGE(TAG, "load energy_main data: 0x%x (%s)", main_ret, esp_err_to_name(main_ret));
}
// 读取ctx.daily_energy
len = sizeof(daily_energy);
esp_err_t daily_ret = nvs_get_blob(handle, "daily_energy", &daily_energy, &len);
if (daily_ret == ESP_ERR_NVS_NOT_FOUND)
{
ESP_LOGW(TAG, "Daily energy data not found in NVS, initializing to 0.0");
// 尝试写入初始值
esp_err_t daily_ret_init = nvs_set_blob(handle, "daily_energy", &daily_energy, sizeof(daily_energy));
if (daily_ret_init == ESP_OK)
{
daily_ret_init = nvs_commit(handle);
if (daily_ret_init != ESP_OK)
{
ESP_LOGE(TAG, "Failed to commit initial daily energy value: 0x%x (%s)",
daily_ret_init, esp_err_to_name(daily_ret_init));
}
}
else
{
ESP_LOGE(TAG, "Failed to write initial daily energy value: 0x%x (%s)",
daily_ret_init, esp_err_to_name(daily_ret_init));
}
}
else
{
ESP_LOGE(TAG, "load daily energy data: 0x%x (%s)", daily_ret, esp_err_to_name(daily_ret));
}
// 读取主备份版本
esp_err_t main_ver_ret = nvs_get_u32(handle, "energy_ver", &main_ver);
if (main_ver_ret == ESP_ERR_NVS_NOT_FOUND)
{
ESP_LOGW(TAG, "energy_ver data not found in NVS, initializing to 0.0");
// 尝试写入初始值
esp_err_t main_ret_init = nvs_set_u32(handle, "energy_ver", version);
if (main_ret_init == ESP_OK)
{
main_ret_init = nvs_commit(handle);
if (main_ret_init != ESP_OK)
{
ESP_LOGE(TAG, "Failed to commit initial energy value: 0x%x (%s)",
main_ret_init, esp_err_to_name(main_ret_init));
}
}
else
{
ESP_LOGE(TAG, "Failed to write initial energy value: 0x%x (%s)",
main_ret_init, esp_err_to_name(main_ret_init));
}
}
else
{
ESP_LOGE(TAG, "load energy_ver: 0x%x (%s)", main_ret, esp_err_to_name(main_ret));
}
// 读取次备份
len = sizeof(backup_energy);
esp_err_t backup_ret = nvs_get_blob(handle, "energy_backup", &backup_energy, &len);
if (backup_ret == ESP_ERR_NVS_NOT_FOUND)
{
ESP_LOGW(TAG, "Backup energy data not found in NVS, initializing to 0.0");
ctx.total_energy = 0.0f;
// 尝试写入初始值
esp_err_t backup_ret_init = nvs_set_blob(handle, "energy_backup", &ctx.total_energy, sizeof(ctx.total_energy));
if (backup_ret_init == ESP_OK)
{
backup_ret_init = nvs_commit(handle);
if (backup_ret_init != ESP_OK)
{
ESP_LOGE(TAG, "Failed to commit initial backup energy value: 0x%x (%s)",
backup_ret_init, esp_err_to_name(backup_ret_init));
}
}
else
{
ESP_LOGE(TAG, "Failed to write initial backup energy value: 0x%x (%s)",
backup_ret_init, esp_err_to_name(backup_ret_init));
}
}
else
{
ESP_LOGE(TAG, "load backup energy data: 0x%x (%s)", backup_ret, esp_err_to_name(backup_ret));
}
// 读取次备份日用电量
len = sizeof(daily_energy_bk);
esp_err_t daily_bk_ret = nvs_get_blob(handle, "daily_energy_bk", &daily_energy_bk, &len);
if (daily_bk_ret == ESP_ERR_NVS_NOT_FOUND)
{
ESP_LOGW(TAG, "Backup daily energy data not found in NVS, initializing to 0.0");
// 尝试写入初始值
esp_err_t daily_bk_ret_init = nvs_set_blob(handle, "daily_energy_bk", &daily_energy_bk, sizeof(daily_energy_bk));
if (daily_bk_ret_init == ESP_OK)
{
daily_bk_ret_init = nvs_commit(handle);
if (daily_bk_ret_init != ESP_OK)
{
ESP_LOGE(TAG, "Failed to commit initial backup daily energy value: 0x%x (%s)",
daily_bk_ret_init, esp_err_to_name(daily_bk_ret_init));
}
}
else
{
ESP_LOGE(TAG, "Failed to write initial backup daily energy value: 0x%x (%s)",
daily_bk_ret_init, esp_err_to_name(daily_bk_ret_init));
}
}
else
{
ESP_LOGE(TAG, "load backup daily energy data: 0x%x (%s)", daily_bk_ret, esp_err_to_name(daily_bk_ret));
}
esp_err_t backup_ver_ret = nvs_get_u32(handle, "energy_ver_bk", &backup_ver);
if (backup_ver_ret == ESP_ERR_NVS_NOT_FOUND)
{
ESP_LOGW(TAG, "Backup energy version data not found in NVS, initializing to 0.0");
// 尝试写入初始值
esp_err_t backup_ret_init = nvs_set_u32(handle, "energy_ver_bk", version);
if (backup_ret_init == ESP_OK)
{
backup_ret_init = nvs_commit(handle);
if (backup_ret_init != ESP_OK)
{
ESP_LOGE(TAG, "Failed to commit initial backup energy value: 0x%x (%s)",
backup_ret_init, esp_err_to_name(backup_ret_init));
}
}
else
{
ESP_LOGE(TAG, "Failed to write initial backup energy value: 0x%x (%s)",
backup_ret_init, esp_err_to_name(backup_ret_init));
}
}
else
{
ESP_LOGE(TAG, "load backup energy version data: 0x%x (%s)", backup_ver_ret, esp_err_to_name(backup_ver_ret));
}
// 选择最新有效数据
if (main_ret == ESP_OK && backup_ret == ESP_OK)
{
ctx.total_energy = (main_ver >= backup_ver) ? main_energy : backup_energy;
}
else if (main_ret == ESP_OK)
{
ctx.total_energy = main_energy;
}
else if (backup_ret == ESP_OK)
{
ctx.total_energy = backup_energy;
}
else
{
ctx.total_energy = 0.0f;
ESP_LOGW(TAG, "No valid energy data found, initialized to 0");
}
if (daily_ret == ESP_OK && daily_bk_ret == ESP_OK)
{
ctx.daily_energy = (main_ver >= backup_ver) ? daily_energy : daily_energy_bk;
}
else if (daily_ret == ESP_OK)
{
ctx.daily_energy = daily_energy;
}
else if (daily_bk_ret == ESP_OK)
{
ctx.daily_energy = daily_energy_bk;
}
else
{
ctx.daily_energy = 0.0f;
ESP_LOGW(TAG, "No valid daily energy data found, initialized to 0");
}
ESP_LOGI(TAG, "Loaded total energy: %d.%04d kWh, daily energy: %d.%04d kWh",
(int)ctx.total_energy, (int)(ctx.total_energy * 10000) % 10000,
(int)ctx.daily_energy, (int)(ctx.daily_energy * 10000) % 10000);
nvs_close(handle);
ctx.initialized = true;
return ESP_OK;
}
// 3. 优化数据解析任务
void bl0942_task(void *pvParameters)
{
uint8_t buf[23];
while (1)
{
if (lwrb_get_full(&lwrb_bl0942) >= sizeof(buf))
{
lwrb_peek(&lwrb_bl0942, 0, buf, sizeof(buf));
// 协议头验证 (0x55 after non-0x55)
if (buf[0] == 0x55)
{
char buffer[70]; // 23个元素 * 3字符(每个"%02x ") + 结束符 = 69+1
int pos = 0;
for (int i = 0; i < 23; i++) {
pos += snprintf(buffer + pos, sizeof(buffer) - pos, "%02x ", buf[i]);
}
ESP_LOGI(TAG, "%s", buffer);
// 校验和验证
uint32_t checksum = 88;
uint8_t checksum_ret = 0;
for (int i = 0; i < 22; i++)
checksum += buf[i];
checksum_ret = ~(checksum & 0xFF);
if (checksum_ret == buf[22])
{
// 解析有效数据
parse_bl0942_data(buf, &frame);
// 处理脉冲计数
if (ctx.initialized)
{
uint32_t delta = calculate_pulse_delta(frame.pf_counter, ctx.last_pulse);
float energy_delta = (float)delta / (float)calculate_pulse_per_kwh(&frame);
ctx.total_energy += energy_delta;
ctx.daily_energy += energy_delta; // 仅内存计算
ctx.last_pulse = frame.pf_counter;
// 定期保存
if (xTaskGetTickCount() * portTICK_PERIOD_MS - ctx.last_save >= SAVE_INTERVAL)
{
ESP_LOGI(TAG, "%d.%04d kWh", (int)ctx.total_energy, (int)(ctx.total_energy * 10000) % 10000);
bl0942_save_energy();
ctx.last_save = xTaskGetTickCount() * portTICK_PERIOD_MS;
}
}
lwrb_skip(&lwrb_bl0942, sizeof(buf));
continue;
}
else
{
lwrb_skip(&lwrb_bl0942, 1);
ESP_LOGW(TAG, "checksum skipping 1 byte");
}
}
else
{
lwrb_skip(&lwrb_bl0942, 1);
ESP_LOGW(TAG, "start skipping 1 byte");
}
// 延时1ms
vTaskDelay(pdMS_TO_TICKS(1));
}
if (xTaskGetTickCount() - ctx.last_send_counter >= pdMS_TO_TICKS(1000))
{
// 每秒发送一次串口数据
char data_str[2] = {0x58, 0xAA}; // 发送数据
uart_write_bytes(UART_PORT_NUM, data_str, sizeof(data_str));
ctx.last_send_counter = xTaskGetTickCount();
}
}
}
void reset_energy_data(void)
{
// 重置ctx.total_energy和ctx.daily_energy
ctx.total_energy = 0.0f;
ctx.daily_energy = 0.0f;
ctx.last_pulse = 0; // 重置脉冲计数
ctx.last_save = xTaskGetTickCount() * portTICK_PERIOD_MS; // 更新保存时间
ESP_LOGI(TAG, "Energy data reset to 0.0 kWh");
// 保存重置后的数据到NVS
bl0942_save_energy();
}
// 4. 新增辅助函数
static uint32_t calculate_pulse_delta(uint32_t current, uint32_t last)
{
return (current >= last) ? (current - last) : (BL0942_COUNTER_MAX - last + current + 1);
}
static float calculate_pulse_per_kwh(bl0942_frame_t *frame_p)
{
// 计算每千瓦时的脉冲数 - 修正为固定值
if (MAX_C == 10)
{
// 对于10A模块,每千瓦时脉冲数应为固定值
return 16051.896f; // 四舍五入 16051.896
}
else
{
// 对于20A模块,每千瓦时脉冲数应为固定值
return 5350.632f; // 四舍五入 5350.632 0.224272576
}
}
static void parse_bl0942_data(uint8_t *data, bl0942_frame_t *frame_p)
{
// 添加调试信息
ESP_LOGI(TAG, "Raw power bytes: %02X %02X %02X", data[10], data[11], data[12]);
// 解析电流
frame_p->current_param = (data[3] << 16) | (data[2] << 8) | data[1];
if(data[3] & 0x80) // 高字节的最高位如果为1,说明电流为负数
{
frame_p->current_param = -(16777216 - frame_p->current_param);
}
if(MAX_C == 10) // 电流最大值模块类型
{
frame_p->real_current_val = frame_p->current_param * 1.218f / (305978.0f * 3.0f); // 计算有效电流
}
else
{
frame_p->real_current_val = frame_p->current_param * 1.218f / 305978.0f; // 计算有效电流
}
// 解析电压
frame_p->voltage_param = (data[6] << 16) | (data[5] << 8) | data[4];
frame_p->real_voltage_val = frame_p->voltage_param * 1.218f * 1950.51f / 37734390.0f; // 计算有效电压
frame_p->apparent_power = frame_p->real_voltage_val * frame_p->real_current_val; // 计算视在功率
// 解析功率参数 - 修正符号处理
frame_p->power_param = (data[12] << 16) | (data[11] << 8) | data[10];
ESP_LOGI(TAG, "Power param (signed): %d", frame_p->power_param);
// 正确处理24位有符号整数
if(data[12] & 0x80) // 如果最高位为1,表示负数y
{
// 有功功率为负数时,转换为补码
frame_p->power_param = (~frame_p->power_param + 1) & 0xFFFFFF; // 取补码
}
// 添加调试信息
ESP_LOGI(TAG, "Power param (signed): %d", frame_p->power_param);
ESP_LOGI(TAG, "Power param (hex): 0x%06X", frame_p->power_param & 0x00FFFFFF);
// 修正有功功率计算公式
if(MAX_C == 10) // 10A模块
{
frame_p->active_power = (float)frame_p->power_param * 1.218f * 1.218f * 1950.51f / 5411610.0f;
}
else // 20A模块
{
frame_p->active_power = (float)frame_p->power_param * 1.218f * 1.218f * 1950.51f / 1803870.0f;
}
// 确保功率因数在合理范围内
if(frame_p->apparent_power != 0)
{
frame_p->power_factor = frame_p->active_power / frame_p->apparent_power;
// 限制功率因数在合理范围内 [-1, 1]
if(frame_p->power_factor > 1.0f) frame_p->power_factor = 1.0f;
if(frame_p->power_factor < -1.0f) frame_p->power_factor = -1.0f;
}
// 计算功率pf_counter
frame_p->pf_counter = (data[15] << 16) | (data[14] << 8) | data[13];
ESP_LOGI(TAG, "CURRENT=%d.%04d A", (int)frame_p->real_current_val, (int)(frame_p->real_current_val * 10000) % 10000);
ESP_LOGI(TAG, "ACTIVE_POWER=%d.%04d W",
(int)frame_p->active_power,
(int)(fabsf(frame_p->active_power) * 10000) % 10000);
}
// 修改u_mqtt_task函数以发送累计用电量
void u_mqtt_task(void *pvParameters)
{
char __post_str[500] = {0};
// 初始化日用电量统计
time_t now;
time(&now);
struct tm *timeinfo = localtime(&now);
ctx.current_day = timeinfo->tm_mday;
while (1)
{
static int32_t res = -1;
memset(__post_str, 0, sizeof(__post_str));
// 1. 将浮点值转换为整数(单位:0.0001A, 0.01V, 0.0001W, 0.0001kWh)
// 使用round函数确保正确的四舍五入
int current_int = (int)round(frame.real_current_val * 10000);
int voltage_int = (int)round(frame.real_voltage_val * 100);
// 确保功率为正数
float active_power = frame.active_power < 0 ? -frame.active_power : frame.active_power;
int power_int = (int)round(active_power * 10000);
int daily_energy_int = (int)round(ctx.daily_energy * 10000);
int total_energy_int = (int)round(ctx.total_energy * 10000);
// 2. 构建JSON字符串
int len = snprintf(__post_str, sizeof(__post_str),
"{\"default:current\":%d.%04d,\"default:voltage\":%d.%02d,"
"\"default:active_power\":%d.%04d,\"default:day_use_energy\":%d.%04d,"
"\"default:total_energy\":%d.%04d}",
current_int / 10000, abs(current_int % 10000), // 电流 (0.0001A)
voltage_int / 100, abs(voltage_int % 100), // 电压 (0.01V)
power_int / 10000, abs(power_int % 10000), // 功率 (0.0001W)
daily_energy_int / 10000, abs(daily_energy_int % 10000), // 日用电量 (0.0001kWh)
total_energy_int / 10000, abs(total_energy_int % 10000) // 总用电量 (0.0001kWh)
);
if (len >= sizeof(__post_str)) {
ESP_LOGW(TAG, "MQTT message truncated! Required:%d, Available:%zu", len, sizeof(__post_str));
} else if (len < 0) {
ESP_LOGE(TAG, "Error formatting MQTT message: %d", len);
} else {
// 只有在格式化成功时才发送消息
ESP_LOGI(TAG, "Sending MQTT data: %s", __post_str);
_send_property_post(dm_handle, __post_str);
}
// 每日电量统计检查
time(&now);
struct tm *timeinfo = localtime(&now);
if (timeinfo->tm_mday != ctx.current_day)
{
ESP_LOGI(TAG, "New day detected, reset daily energy. Yesterday: %d.%02d kWh", (int)ctx.daily_energy, (int)(ctx.daily_energy * 100) % 100);
char day_energy_str[100] = {0};
int daily_energy_int = (int)round(ctx.daily_energy * 10000);
int day_len = snprintf(day_energy_str, sizeof(day_energy_str), "{\"default:day_energy\":%d.%04d}",
daily_energy_int / 10000, abs(daily_energy_int % 10000)); // 日用电量 (0.0001kWh));
if (day_len > 0 && day_len < sizeof(day_energy_str)) {
res = _send_property_post(dm_handle, day_energy_str);
if(res >= 0){
res = -1;
ctx.daily_energy = 0.0f;
ctx.current_day = timeinfo->tm_mday;
bl0942_save_energy();
}
}
}
vTaskDelay(pdMS_TO_TICKS(4000));
}
}
// 数据包解析任务
void bl0942_parser_task(void *pvParameters)
{
uart_event_t event;
uint8_t dtmp[RX_BUF_SIZE] = {0};
while (1)
{
if (xQueueReceive(uart_queue, (void *)&event, portMAX_DELAY))
{
bzero(dtmp, RX_BUF_SIZE);
switch (event.type)
{
// Event of UART receving data
// We'd better handler data event fast, there would be much more data events than
// other types of events. If we take too much time on data event, the queue might be full.
case UART_DATA:
{
// ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
lwrb_sz_t available = lwrb_get_free(&lwrb_bl0942);
if (available >= event.size)
{
int read_bytes = uart_read_bytes(UART_PORT_NUM, dtmp, event.size, portMAX_DELAY);
if (read_bytes > 0)
{
lwrb_sz_t written = lwrb_write(&lwrb_bl0942, dtmp, read_bytes);
}
}
}
break;
// Event of HW FIFO overflow detected
case UART_FIFO_OVF:
// ESP_LOGI(TAG, "hw fifo overflow");
// If fifo overflow happened, you should consider adding flow control for your application.
// The ISR has already reset the rx FIFO,
// As an example, we directly flush the rx buffer here in order to read more data.
uart_flush_input(UART_PORT_NUM);
xQueueReset(uart_queue);
break;
// Event of UART ring buffer full
case UART_BUFFER_FULL:
// ESP_LOGI(TAG, "ring buffer full");
// If buffer full happened, you should consider encreasing your buffer size
// As an example, we directly flush the rx buffer here in order to read more data.
uart_flush_input(UART_PORT_NUM);
xQueueReset(uart_queue);
break;
case UART_PARITY_ERR:
// ESP_LOGI(TAG, "uart parity error");
break;
// Event of UART frame error
case UART_FRAME_ERR:
// ESP_LOGI(TAG, "uart frame error");
break;
// Others
default:
// ESP_LOGI(TAG, "uart event type: %d", event.type);
break;
}
}
}
}
void bl0942_init(void)
{
// 初始化UART
uart_config_t uart_config = {
.baud_rate = BAUD_RATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
bl0942_load_energy();
// 初始化lwrb
uint8_t ret = lwrb_init(&lwrb_bl0942, lwrb_bl0942_buffer, sizeof(lwrb_bl0942_buffer));
ESP_LOGI(TAG, "lwrb init %d", ret);
uart_param_config(UART_PORT_NUM, &uart_config);
uart_driver_install(UART_PORT_NUM, RX_BUF_SIZE * 2, RX_BUF_SIZE * 2, 10, &uart_queue, 0);
// 创建解析任务
xTaskCreate(&bl0942_parser_task, "bl0942_parser", 2048, NULL, 1, &bl0942_parser_taskHandle);
// 创建一个解析任务
xTaskCreate(&bl0942_task, "bl0942", 2048, NULL, 0, &bl0942_taskHandle);
// 新建一个任务定期上传数据到mqtt平台
xTaskCreate(&u_mqtt_task, "u_mqtt_task", 2048, NULL, 0, &u_mqtt_taskHandle);
}
void bl0942_deinit(void)
{
// 删除解析任务
vTaskDelete(bl0942_parser_taskHandle);
// 删除数据处理任务
vTaskDelete(bl0942_taskHandle);
// 删除MQTT上传任务
vTaskDelete(u_mqtt_taskHandle);
}