ESP8266+BL0937电能计量芯片
1. BL0937计量芯片的介绍
BL0937的应用电路图
BL0937的外围电路图
2. ESP8266与BL0937芯片的引脚连接
[tr]ESP引脚BL0937引脚[/tr]GPIO3SEL
GPIO4CF
GPIO5CF1
3. 程序设计思路
采用系统时间实现单周期测量
假设GPIO外部中断类型为下降沿触发,设下降沿数量为num=0,则测量逻辑如下所示:
[tr]下降沿个数周期数[/tr]10
21
故在第一个下降沿到来和第二个下降沿到来时获取系统时间,此为单周期时间,然后清零重新计数。多个外部中断时需要注意不同外部中断的下降沿时间间隔,防止持续进入某个外部中断。
2. 采用定时器实现平均测量
定时器测量时需要注意应该采用硬件定时器,时钟源为NMI时钟源,此时钟源优先级高于外部中断,可保证定时的准确性。
4. 需要注意的问题
打开中断之后,下降沿可能不会立即触发中断,一种是加延时,具体时间要根据负载而定;一种方法是执行while循环,判断计时时间是否到达。总的来说,整个过程对于周期的测量并不准确,误差在2以内。
5. 功率电能完整代码
#include “user_main.h”
#include “osapi.h”#include “os_type.h”
#include “driver/uart.h”
#include “user_interface.h”
#include “spi_flash.h”
#include “espconn.h”
#include “user_config.h”
#include “hal_key.h”
#include “tosee_common.h”
#include “tosee_led.h”
#include “config.h”
#include “power.h”
#include “test.h”
#include “ets_sys.h”
#include “ip_addr.h”
#include “mem.h”
#include “user_main.h”
#include “hw_timer.h”int num1;
//功率脉冲int num2;
//电能脉冲float Fcf;
//功率float P;
//W,kWHfloat W;
//定义电压电流转换系数int Kp = 15;
int Kw = 10;
int flag=0;
int flag1=0;
void ICACHE_FLASH_ATTR bl_interrupt()
{
unsigned int gpio_status = 0;
gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
//获取中断状态
ETS_GPIO_INTR_DISABLE();
//关中断
//GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
//清中断标志位
if(gpio_status & BIT(4))
{
num1=num1+1;
//PW 脉冲个数
num2=num2+1;
}
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
if(flag==0)
{
ETS_GPIO_INTR_ENABLE();
}
else{
ETS_GPIO_INTR_DISABLE();
}
}
void ICACHE_FLASH_ATTR PW_handler()
{
if (Fcf 《 6780)
{
P = Fcf * Kp; //W
W = num2 * Kw; //kWh
flag1=1;
}
else
{
P = 0;
//P=0标志过流
W = num2 * Kw;
//kWh
flag1=1;
}
}
void hw_test_timer_cb(void)
{
flag=1;
}
void ICACHE_FLASH_ATTR hz_handler()
{
Fcf=num1/5.0;
//Hz}void ICACHE_FLASH_ATTR pw_init()
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
GPIO_DIS_OUTPUT(4);
//GPIO4和GPIO5使能上拉
PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO4_U);
//GPIO4中断配置
ETS_GPIO_INTR_DISABLE();
ETS_GPIO_INTR_ATTACH(&bl_interrupt, NULL);
gpio_pin_intr_state_set(GPIO_ID_PIN(4), GPIO_PIN_INTR_NEGEDGE);
//硬件定时器
hw_timer_init(1,0);
hw_timer_set_func(hw_test_timer_cb);
hw_timer_arm(2000000);
//us,2s
ETS_GPIO_INTR_ENABLE();
//开中断
while(1)
{
if(flag==1)
{ ETS_GPIO_INTR_DISABLE();
hz_handler();
PW_handler();
os_printf(“P=%d,W=%d,num1=%d,num2=%d------n”,P,W,num1,num2);
if(flag1==1){num1=0;
}
}
}
}
7.电压电流测量完整代码
#include “ets_sys.h”
#include “osapi.h”
#include “ip_addr.h”
#include “espconn.h”
#include “mem.h”
#include “user_interface.h”
#include “smartconfig.h”
#include “airkiss.h”
#include “driver/uart.h”
#include “hw_timer.h”int num0 = 0;
//电流电压脉冲float Fcf1 = 0;
//电流电压Hzint U=0;int I=0;
//V,mA//定义电压电流转换系数int Ku = 220;
float Ki = 0.18;
int flag=0;
int flag1=0;
/* * 脉冲中断计数函数 */
void ICACHE_FLASH_ATTR bl_interrupt()
{
unsigned int gpio_status = 0;
gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
//获取中断状态 ETS_GPIO_INTR_DISABLE();
//关中断
//GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
//清中断标志位 if(gpio_status & BIT(5))
{
num0 = num0 + 1;
}
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
if(flag==0)
{
ETS_GPIO_INTR_ENABLE();
}
else
{
ETS_GPIO_INTR_DISABLE();
}
}
void ICACHE_FLASH_ATTR bl_select()
{
if(GPIO_ID_PIN(3)==0)
{
I = Fcf1 * Ki; //mA
GPIO_OUTPUT_SET(GPIO_ID_PIN(3), 1);
}
else
{
GPIO_OUTPUT_SET(GPIO_ID_PIN(3), 0);
U = Fcf1 * Ku; //mA
}
flag1=1;}
void hw_test_timer_cb(void)
{
flag=1;
}
void ICACHE_FLASH_ATTR hz_handler()
{
Fcf1=num0/1.0; //Hz}
void ICACHE_FLASH_ATTR Time_UI_init()
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_GPIO3);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);
GPIO_DIS_OUTPUT(5);
GPIO_OUTPUT_SET(GPIO_ID_PIN(3), 0);
//GPIO3=0
//GPIO4和GPIO5使能上拉
PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO5_U);
//GPIO5中断配置
ETS_GPIO_INTR_DISABLE();
ETS_GPIO_INTR_ATTACH(&bl_interrupt, NULL);
gpio_pin_intr_state_set(GPIO_ID_PIN(5), GPIO_PIN_INTR_NEGEDGE);
//硬件定时器
hw_timer_init(1,0);
hw_timer_set_func(hw_test_timer_cb);
hw_timer_arm(2000000); //us,2s
ETS_GPIO_INTR_ENABLE();
//开中断 while(1)
{
if(flag==1)
{
ETS_GPIO_INTR_DISABLE();
hz_handler();
bl_select();
if(flag1==1){num0=0;
}
}
}
}
8. 需要解决的问题
计算问题
ESP8266的基础计算没有了解过,但是在整个程序中发现计算有误。(1)中断执行函数中{num1=num1+1; num2=num2+1;},这两句程序只会执行第一个,不明白什么原因;(2)主程序中最后判断是否对num1清零。这条程序会先于hz_handler()和PW_handler()函数执行。虽然执行条件未达到。这个也不明白;(3)貌似ESP8266会优先执行赋值语句;同一个函数下两条计算语句会只执行第一条。
参数类型问题
默认P=x.x(W),W=x.xx(kWh)。那么设置计算函数的时候要注意各个参数的类型。
ESP8266+BL0937电能计量芯片
1. BL0937计量芯片的介绍
BL0937的应用电路图
BL0937的外围电路图
2. ESP8266与BL0937芯片的引脚连接
[tr]ESP引脚BL0937引脚[/tr]GPIO3SEL
GPIO4CF
GPIO5CF1
3. 程序设计思路
采用系统时间实现单周期测量
假设GPIO外部中断类型为下降沿触发,设下降沿数量为num=0,则测量逻辑如下所示:
[tr]下降沿个数周期数[/tr]10
21
故在第一个下降沿到来和第二个下降沿到来时获取系统时间,此为单周期时间,然后清零重新计数。多个外部中断时需要注意不同外部中断的下降沿时间间隔,防止持续进入某个外部中断。
2. 采用定时器实现平均测量
定时器测量时需要注意应该采用硬件定时器,时钟源为NMI时钟源,此时钟源优先级高于外部中断,可保证定时的准确性。
4. 需要注意的问题
打开中断之后,下降沿可能不会立即触发中断,一种是加延时,具体时间要根据负载而定;一种方法是执行while循环,判断计时时间是否到达。总的来说,整个过程对于周期的测量并不准确,误差在2以内。
5. 功率电能完整代码
#include “user_main.h”
#include “osapi.h”#include “os_type.h”
#include “driver/uart.h”
#include “user_interface.h”
#include “spi_flash.h”
#include “espconn.h”
#include “user_config.h”
#include “hal_key.h”
#include “tosee_common.h”
#include “tosee_led.h”
#include “config.h”
#include “power.h”
#include “test.h”
#include “ets_sys.h”
#include “ip_addr.h”
#include “mem.h”
#include “user_main.h”
#include “hw_timer.h”int num1;
//功率脉冲int num2;
//电能脉冲float Fcf;
//功率float P;
//W,kWHfloat W;
//定义电压电流转换系数int Kp = 15;
int Kw = 10;
int flag=0;
int flag1=0;
void ICACHE_FLASH_ATTR bl_interrupt()
{
unsigned int gpio_status = 0;
gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
//获取中断状态
ETS_GPIO_INTR_DISABLE();
//关中断
//GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
//清中断标志位
if(gpio_status & BIT(4))
{
num1=num1+1;
//PW 脉冲个数
num2=num2+1;
}
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
if(flag==0)
{
ETS_GPIO_INTR_ENABLE();
}
else{
ETS_GPIO_INTR_DISABLE();
}
}
void ICACHE_FLASH_ATTR PW_handler()
{
if (Fcf 《 6780)
{
P = Fcf * Kp; //W
W = num2 * Kw; //kWh
flag1=1;
}
else
{
P = 0;
//P=0标志过流
W = num2 * Kw;
//kWh
flag1=1;
}
}
void hw_test_timer_cb(void)
{
flag=1;
}
void ICACHE_FLASH_ATTR hz_handler()
{
Fcf=num1/5.0;
//Hz}void ICACHE_FLASH_ATTR pw_init()
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
GPIO_DIS_OUTPUT(4);
//GPIO4和GPIO5使能上拉
PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO4_U);
//GPIO4中断配置
ETS_GPIO_INTR_DISABLE();
ETS_GPIO_INTR_ATTACH(&bl_interrupt, NULL);
gpio_pin_intr_state_set(GPIO_ID_PIN(4), GPIO_PIN_INTR_NEGEDGE);
//硬件定时器
hw_timer_init(1,0);
hw_timer_set_func(hw_test_timer_cb);
hw_timer_arm(2000000);
//us,2s
ETS_GPIO_INTR_ENABLE();
//开中断
while(1)
{
if(flag==1)
{ ETS_GPIO_INTR_DISABLE();
hz_handler();
PW_handler();
os_printf(“P=%d,W=%d,num1=%d,num2=%d------n”,P,W,num1,num2);
if(flag1==1){num1=0;
}
}
}
}
7.电压电流测量完整代码
#include “ets_sys.h”
#include “osapi.h”
#include “ip_addr.h”
#include “espconn.h”
#include “mem.h”
#include “user_interface.h”
#include “smartconfig.h”
#include “airkiss.h”
#include “driver/uart.h”
#include “hw_timer.h”int num0 = 0;
//电流电压脉冲float Fcf1 = 0;
//电流电压Hzint U=0;int I=0;
//V,mA//定义电压电流转换系数int Ku = 220;
float Ki = 0.18;
int flag=0;
int flag1=0;
/* * 脉冲中断计数函数 */
void ICACHE_FLASH_ATTR bl_interrupt()
{
unsigned int gpio_status = 0;
gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
//获取中断状态 ETS_GPIO_INTR_DISABLE();
//关中断
//GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
//清中断标志位 if(gpio_status & BIT(5))
{
num0 = num0 + 1;
}
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
if(flag==0)
{
ETS_GPIO_INTR_ENABLE();
}
else
{
ETS_GPIO_INTR_DISABLE();
}
}
void ICACHE_FLASH_ATTR bl_select()
{
if(GPIO_ID_PIN(3)==0)
{
I = Fcf1 * Ki; //mA
GPIO_OUTPUT_SET(GPIO_ID_PIN(3), 1);
}
else
{
GPIO_OUTPUT_SET(GPIO_ID_PIN(3), 0);
U = Fcf1 * Ku; //mA
}
flag1=1;}
void hw_test_timer_cb(void)
{
flag=1;
}
void ICACHE_FLASH_ATTR hz_handler()
{
Fcf1=num0/1.0; //Hz}
void ICACHE_FLASH_ATTR Time_UI_init()
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_GPIO3);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);
GPIO_DIS_OUTPUT(5);
GPIO_OUTPUT_SET(GPIO_ID_PIN(3), 0);
//GPIO3=0
//GPIO4和GPIO5使能上拉
PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO5_U);
//GPIO5中断配置
ETS_GPIO_INTR_DISABLE();
ETS_GPIO_INTR_ATTACH(&bl_interrupt, NULL);
gpio_pin_intr_state_set(GPIO_ID_PIN(5), GPIO_PIN_INTR_NEGEDGE);
//硬件定时器
hw_timer_init(1,0);
hw_timer_set_func(hw_test_timer_cb);
hw_timer_arm(2000000); //us,2s
ETS_GPIO_INTR_ENABLE();
//开中断 while(1)
{
if(flag==1)
{
ETS_GPIO_INTR_DISABLE();
hz_handler();
bl_select();
if(flag1==1){num0=0;
}
}
}
}
8. 需要解决的问题
计算问题
ESP8266的基础计算没有了解过,但是在整个程序中发现计算有误。(1)中断执行函数中{num1=num1+1; num2=num2+1;},这两句程序只会执行第一个,不明白什么原因;(2)主程序中最后判断是否对num1清零。这条程序会先于hz_handler()和PW_handler()函数执行。虽然执行条件未达到。这个也不明白;(3)貌似ESP8266会优先执行赋值语句;同一个函数下两条计算语句会只执行第一条。
参数类型问题
默认P=x.x(W),W=x.xx(kWh)。那么设置计算函数的时候要注意各个参数的类型。
举报