式传使用此非接触感器测量交流电流和功率因数。它是 Seeed Grove I2C 50/60HZ 交流电流和功率因数模块。
对于能源管理项目,我希望有一种简单的方法来测量交流电流和功率因数,最好是非接触式的,可以很容易地连接到设备和移除而无需直接连接到任何高压电路。
我还想要一个 I2C 模块,它封装了所有传感复杂性并让我的主 MCU 处理通信。
这个传感器模块是我参加Seeed Grove 传感器共同发明活动的一部分,这对任何人来说都是一个让您梦想中的传感器成为现实的好机会。
对于交流电源,以瓦特为单位的视在功率就是电压乘以电流。这是用于计算导线在传导电流时会发热多少的功率。视在功率的单位是 VA,即伏安。
负载使用的实际功率通常小于视在功率,因为一些功率会被电容或电感电路元件反射。在测量交流电感或电容负载(例如电机或计算机电源)时,以瓦特为单位的实际功率由公式 P = V * I * cos theta 表示。功率的单位通常是瓦特或千瓦。
Cos θ 也称为功率因数,其中 θ 表示电流的相移或延迟。对于感性或容性负载,电流滞后或超前施加的电压。对于纯电阻负载,θ 为 0,因此 cos θ 为 1。对于电感负载,功率因数通常在 0.8 到 1.0 的范围内。也就是说,有功功率 [kW] 小于施加电压乘以电流 [VA]。
对于此传感器,可以使用非接触式电流互感器 (CT) 检测交流电流。感谢一篇关于DIY 非接触式交流电压检测器的 instructables 文章,我了解到可以使用高阻抗数字逻辑缓冲器以非接触方式测量交流电压信号的相位。在音频方面,这意味着测量电路中的嗡嗡声。可以测量电压和电流之间的相位差来计算功率因数。
我喜欢在我的项目中使用 I2C 传感器。它们使测量变得容易,它们处理所有的物理、信号调节、模数转换、校准,并提供一个允许轻松访问数字化数据的接口。访问传感器的任何代码都没有所有这些复杂性。此外,您可以将多个 I2C 传感器放在同一条 2 线总线上。
我发现 Microchip ATtiny tinyAVR 2 系列非常适合实现 I2C 传感器。它是一款微型 8 位 MCU,具有高级差分 ADC、可编程异步逻辑,并且可以以极低的功耗运行。
简化示意图
使用差分 ADC,测量电流相对容易,您只需测量电阻两端的电压降。对于交流电流,您需要在 50 或 60HZ 周期内对电流进行多次采样,并计算采样的均方根平均值。AC 电压信号的相位可以用连接到高阻抗数字逻辑缓冲器的天线线测量,该缓冲器是 ATtiny 可配置定制逻辑 (CCL) 外设的一部分。
将 100A 50mA CT 夹在载流导线周围,从而连接它。CT 有一个 3.5mm 插头。将其连接到插孔。将插孔线与 20 欧姆负载电阻并联连接到 B- 和 B+ 端子。如果使用 0-1Vac CT(内置负载电阻),请勿连接 20ohm 负载电阻。
将电源线天线线缠绕到相同的载流电线或电缆上。将其连接到引脚 RX1。不要将电线的导体连接到任何东西,它只是用胶带粘在绝缘载流电线或电缆上。该天线线感测电压 (emf)。
插入 Grove 连接器并连接到您的 MCU,例如 ESP32。
#include <Arduino.h>
#include <Wire.h>
#include "I2C_AC_Current.h"
AC_Current hct20;
void setup()
{
Serial.begin(115200);
hct20.begin(21,22); // SDA, SCL. 21,22 for ESP32
}
void loop()
{
hct20.read();
Serial.print("Current: ");
Serial.print(hct20.getCurrent());
Serial.print(" PF: ");
Serial.println(hct20.getPF());
delay(1000);
}
安慰
Current: 1.30 PF: 0.96
如果假设电压通常是恒定的,则可以计算功率,例如:
const float voltage = 240;
float real_power_watts = voltage * hct20.getCurrent() * hct20.getPF();
值得庆幸的是,Spence Konde 已经为 ATTiny 2 系列编写了一个Arduino 内核,这使得编写传感器代码变得更加容易。该内核提供诸如 setup()、loop() 函数、串行对象、I2C 从 ISR 函数和用于访问许多芯片外设的库等功能。
传感器固件代码可以在github 上找到。
setup() 函数启动 ADC、I2C 客户端,并安装请求和响应回调。
void setup()
{
...
setupLogic();
ADC_init();
Wire.onReceive(receiveHandler);
Wire.onRequest(requestHandler);
Wire.begin(SHT2x_ADDRESS);
...
}
逻辑库设置芯片的自定义可配置逻辑以侦听 IN2、引脚 PA2 上的电压信号。
void setupLogic()
{
...
Logic0.enable = true; // Enable logic block 0
Logic0.input0 = in::masked; // PA0 masked
Logic0.input1 = in::masked; // PA1 TX1 masked
Logic0.input2 = in::pin; // PA2 RX1 voltage sense
Logic0.output = out::disable; // Disable logic block 0 output pin PA4
Logic0.filter = filter::disable; // No output filter enabled
Logic0.truth = 0x01; // Set truth: HIGH only if input low
Logic0.edgedetect = edgedetect::enable; // Enable edge detection
Logic0.attachInterrupt(&voltageSenseISR,CHANGE);
Logic0.init();
// Start the AVR logic hardware
Logic::start();
}
它在每次级别更改时调用中断服务例程,每秒发生 50-60 次。当 ADC 对电流进行采样时,此中断会启动循环定时器,并在电流下一次过零时存储迭代次数。这个数字在校准时与电压和电流信号之间的相移成正比。
主 loop() 函数每秒对当前信号采样一次,持续 20 毫秒,并在每个通道上调用 add_sample()。
hardware_fast_sample_chABC(MAX_SAMPLES,chA,chB,chC); // samples for 20ms
add_sample() 函数在看到下一个电流过零时保存电压相位计数。它将每次迭代的当前样本的平方加到两个 bin 中,一个 bin 用于 60HZ 信号,另一个 bin 用于剩余的 50HZ 信号。通过检查哪个 bin 具有平衡信号来选择正确 bin 的结果。
void add_sample(int16_t diff) {
_crossguard--;
_phaseCounter++; // set to zero in ISR
if(((diff ^ _lastSample) & _crossguard) >> 15) {
// If crossed unambiguously (one but not both samples negative and crossGuard negative)
_crossguard = 10;
if (_phaseTriggered == 1) { // on first call after phase mark.
_phaseTriggered++;
_phaseCount = _phaseCounter;
}
}
uint32_t sq = ((uint32_t)diff*(uint32_t)diff);
if (_tickNum < SAMPLES_PER_60HZ_CYCLE) {
_sum2_60 += sq;
_n_60++;
if (diff >= 0) { _p++; }
if (diff < 0) { _n++; }
} else {
_sum2_e += sq;
_n_e++;
if (diff >= 0) { _pe++; }
if (diff < 0) { _ne++; }
}
_tickNum++;
_lastSample = diff;
return;
}
在主循环中,每秒一次,RMS 电流(安培)被缩放并存储在全局变量中以供 I2C 从 ISR 读取。
功率因数也被缩放并存储在全局变量中。
当检测到 I2C 请求时,将调用 receiveHandler,并保存请求字节(命令)。
void receiveHandler(int numbytes)
{
if (numbytes > 0) {
// Called on a Write address, data
g_i2c_command = Wire.read();
}
}
稍后,调用 requestHandler 并缓冲响应以写入线路。
void requestHandler()
{
if ((g_i2c_command == SHT2x_GET_TEMPERATURE_NO_HOLD) ) {
Wire.write((uint8_t)(g_temperature >> 8));
Wire.write((uint8_t) g_temperature);
uint8_t buf[] = { (uint8_t)(g_temperature>>8), (uint8_t) g_temperature };
Wire.write(sht20_crc8(buf, 2));
} else if ((g_i2c_command == SHT2x_GET_HUMIDITY_NO_HOLD) ) {
Wire.write((uint8_t)(g_humidity >> 8));
Wire.write((uint8_t) g_humidity);
uint8_t buf[] = { (uint8_t)(g_humidity>>8), (uint8_t) g_humidity };
Wire.write(sht20_crc8(buf, 2));
}
}
未来的计划是支持 3 个通道,向 I2C 接口添加通道细节,并降低传感器功耗。
我期待着使用此模块通过监控各种电力负载来帮助节省能源。
感谢您的关注,我很乐意听到任何评论,或者如果您觉得这有用。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !