基于ESP32-C3驱动BL0942电参数采集模块Arduino代码

 

1.全部代码

// ESP32-C3 UART1 配置
#define UART1_RX_PIN 4  //接BL0942模块的T引脚
#define UART1_TX_PIN 3  //接BL0942模块的R引脚
#define BAUDRATE 9600   //波特率9600

#define MAX_C 10 //BL0942模块电流最大值,购买10A的这里写10;购买其他规格的写20或者30都可以
//#define MAX_C 20 

// 定时器设置
unsigned long previousMillis = 0;//用来记录当前系统时间,用于计算延时
const long interval = 1000;  // 1秒间隔

char datatosend[2]={0x58,0xAA};//发送读取BL0942数据包指令
int uart_time=0,uart_flag=0;//串口接收超时和接收完成标志

// 串口缓冲区
uint8_t rxBuffer[256];//用于接收串口1的数据
int bufferIndex = 0;//用于标记接收串口1的数据长度

// 硬件串口实例
HardwareSerial SerialPort(1);  // UART1

void setup() 
{
  // 初始化调试串口0(Serial0 - 默认引脚)用于输出解析后的电参数数据
  Serial.begin(9600);
  // 初始化UART1-连接BL0942模块,读取原始电参数数据
  SerialPort.begin(BAUDRATE, SERIAL_8N1, UART1_RX_PIN, UART1_TX_PIN);
  // 设置串口1中断回调函数
  SerialPort.onReceive(serial1ReceiveCallback);
  //串口打印数据
  Serial.println("ESP32-C3 UART1 Receiver BL0942");

}

void loop() 
{
  // 定时发送处理
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval)//间隔1秒读取一次电参数数据
  {
    previousMillis = currentMillis;
    SerialPort.write(datatosend,2);//发送读取指令给BL0942模块
  }
  
  // 处理接收到的数据
  if(uart_flag)
  {
    processReceivedData();
    uart_flag=0;
  }

}

// 串口1接收中断回调函数
void serial1ReceiveCallback() 
{
  while (SerialPort.available()) //判断串口1缓存区是否有数据
  {
    uint8_t receivedByte = SerialPort.read();//读出1个字节数据
    if(bufferIndex==0&&receivedByte!=0x55)//判断第一个数据是否为0x55
    {
      continue;//等待正确的帧头
    }
    if (bufferIndex < sizeof(rxBuffer) - 1)//检查数据有没有超出数组,防止溢出
    {
      rxBuffer[bufferIndex++] = receivedByte;//把数据存入rxBuffer
    } 
    else 
    {
      // 缓冲区满,丢弃最旧的数据(简单处理)
      bufferIndex = 0;
    }
    if(bufferIndex>=23)//收到23个字节后,标记接收完成
    {
      uart_flag=1;
    }

  }
}

// 处理接收到的数据并把结果转发到串口0
void processReceivedData() 
{
  char str[100];
  uint8_t i=0,check_num=0;
    uint32_t count=88;
    uint32_t V_REG=0,P_REG=0,PF_COUNT=0;
    int32_t C_REG=0;
    double V1=0,C1=0,P1=0,P2=0,P3=0,E_con=0;

  // 在串口0显示原始数据
  Serial.print("Received: ");
  // 以十六进制和ASCII格式显示
  for (i = 0; i < bufferIndex; i++) 
  {
    if (rxBuffer[i] < 0x10) Serial.print("0"); // 前导零
    Serial.print(rxBuffer[i], HEX);
    Serial.print(" ");
  }
  Serial.print("\r\n");//串口0打印BL0942的原始数据

  for(i=0;i<22;i++)//求和,用来计算校验码
  {
    count = count + rxBuffer[i];
  }
  check_num=~(count&0xFF);//取最后一个字节,然后按位取反

  if(check_num==rxBuffer[22])//校验数据是正确
    {
        //printf("Check_OK\r\n");
        C_REG=rxBuffer[3]*65536+rxBuffer[2]*256+rxBuffer[1];//计算电流寄存器
        if(MAX_C==10)//电流最大值模块类型,你购买的是10A还是20A模块
        {
            C1=C_REG*1.218/(305978*3);//计算有效电流
        }
        else
        {
            C1=C_REG*1.218/(305978);//计算有效电流
        }
        
        V_REG=rxBuffer[6]*65536+rxBuffer[5]*256+rxBuffer[4];//计算电压寄存器
        V1=V_REG*1.218*1950.51/37734390;//计算有效电压
        
        P2=V1*C1;//P2为视在功率,视在功率=有效电压*有效电流
        
        P_REG=rxBuffer[14]*65536+rxBuffer[13]*256+rxBuffer[12];//计算有功功率寄存器
        if(rxBuffer[14]&0x80)//高字节的最高位如果为1,说明有功功率为负数,如果不做处理可能会出现很大很大的数值
        {
            P_REG=-(16777216-P_REG);
        }
        if(MAX_C==10)//电流最大值模块类型,你购买的是10A还是20A模块
        {
            P1=P_REG*1.218*1.218*1950.51/5411610;//计算有功功率/
        }
        else
        {
            P1=P_REG*1.218*1.218*1950.51/1803870;//计算有功功率
        }
        if(P2!=0)
            P3=P1/P2;//计算功率因数;功率因数=有功功率/视在功率
        
        PF_COUNT=rxBuffer[15]*65536+rxBuffer[14]*256+rxBuffer[13];//计算已用电量脉冲数
        if(MAX_C==10)//电流最大值模块类型,你购买的是10A还是20A模块
        {
            E_con=PF_COUNT/16051.896;//计算已用电量,16051.896为固定值,和选购的量程有关
        }
        else
        {
            E_con=PF_COUNT/5350.632;//计算已用电量,5350.632为固定值,和选购的量程有关
        }
    sprintf(str,"C=%0.3fA;V=%0.2fV;P1=%0.2fW;P2=%0.2fW;P3=%0.1f;E_con=%0.4fkWh\r\n",C1,V1,P1,P2,P3,E_con);
        Serial.print(str);
    }
    else
    {
        Serial.print("Check Error\r\n");//校验数据有误,校验数据出错
    }
  bufferIndex = 0;
}

注意芯片需要选择ESP32C3;代码实测编译可用,如编译报错,可能是软件设置不对,建议百度一下报错原因。

2.硬件接线说明

ESP32C3模块BL0942模块
3.3 3V3
4 T
3 R
G G

image

购买ESP32-C3supermini模块的要注意购买带有内置flash的,部分商家卖的不带flash需要外接flash才能使用。

image

image

image

购买BL0942模块需要看最大电流,需要修改代码开头的#define MAX_C 10宏定义;默认的是10A的规格;一般来说10A最大功率是2200W,一般用电器基本都可以了。

image

 10A和20A模块硬件上区别只有采样电阻阻值大小的区别,其他都一样的。10A的采样电阻阻值是3毫欧,电阻丝印R003;20A的采样电阻阻值是1毫欧(实际测量最大电流是30A),电阻丝印R001;

image

 

 3.烧录测试

烧录完成后,打开串口监听就能看到输出数据了。Received是BL0942模块返回的原始数据,C是有效电流,V是有效电压,P1是有功功率,P2是视在功率,P3是功率因数,E_con是已用电量。

image

 BL0942模块不需要接220V交流电也会输出数据的,只不过数据都是0。

4.代码讲解

 

image

image

 

image

 

image

image

 原始数据对应的格式:

810db46fb2d7ec5cb8b56979b1f6dbd3

 

 校验码:

103-109行是校验计算比对,我们看一下BL0942手册对校验码的公式:

也就是把前面22个字节相加然后加上0x58;接着&0xFF(取最后一个字节),然后按位取反就得出校验码了。代码里面count在定义的时候赋值是88,也就是16进制的0x58。代码中‘~’就是按位取反的作用。

有效电流:

112-120行是计算有效电流的过程,下图是BL0942应用指南手册的计算公式说明;

 

 

电流有效值寄存器值就是返回的数据包里面的第1,2,3字节;RL就是采样电阻的阻值;

所以10A量程的电流=寄存器值*1.218/(305978*0.003*1000);简化一下就是代码里面的公式了

20A量程的电流=寄存器值*1.218/(305978*0.001*1000);简化一下就是代码里面的公式了

有效电压:

122-125行是有效电压和视在功率的计算;手册上的公式如下:

10A和20A规格的模块在电压采样使用的阻值是一样的,所以计算公式是一样的。

根据手册提供的公式可以推导出有效电压的计算公式为:

视在功率:

视在功率=有效电压x有效电流;这个是直接计算的,和数据包数据没有直接关联。

有功功率:

127-141行是有功功率和功率因数计算;

注意:有功功率寄存器是有符号的,需要考虑负数的情况,不然会出现超级大功率数值的情况!!

 

在手册上的有功功率计算公式为:

转换一下得到10A的计算公式:

20A的计算公式:

功率因数:

功率因数=有功功率/视在功率;这个是直接计算的,和数据包数据没有直接关联。

用电量:

 

143-151行是用电量计算,下图为手册提供的公式:

这个公式是每一个脉冲对应的用电量;把Vref和R1,R2,RL代入公式计算:

20A每个电能脉冲对应电量=1213675716105.732 / 6493932000000000 = 0.0001868938=1/5350.632;

同理,10A的公式:


posted @ 2025-11-28 10:02  Knight20  阅读(0)  评论(0)    收藏  举报