Основное внимание при проектировании оборудования интеллектуальных розеток WiFi IoT уделяется измерению мощности. По этой причине я напишу отдельный пост в блоге, чтобы объяснить схему проектирования и принцип реализации измерения мощности.
Для измерения мощности был выбран чип BL0942 компании Shanghai Belling. Основные причины: простая конструкция аппаратного решения, хорошая точность измерения и отсутствие необходимости в калибровке, низкая цена и простой метод программного драйвера.
BL0942 может измерять такие параметры, как ток, эффективное значение напряжения, активная мощность, активная электрическая энергия и т. д. Он может выводить эффективное значение быстрого тока (для защиты от перегрузки по току), а также выходной сигнал и другие функции. Могут быть периферийные компоненты. калибруются, если они соответствуют определенным условиям. Конечно, калибровка BL0942 также поддерживается.
Характеристики чипа следующие:
В этом проекте используется пакет SSOP10L и драйвер UART.
Этот проект считывает или устанавливает регистр микросхемы BL0942 через шину UART. Описание регистра показано на рисунке ниже:
Характеристики связи UART чипа BL0942 следующие:
Пакет TSSOP14L может поддерживать функцию выбора чипа устройства. Адресные контакты выбора аппаратного чипа — [A2_NCS, A1], а дополнительные устройства — 0–3. Он может поддерживать 4 штуки BL0942, подвешенных на шине UART для передачи данных, занимая только один интерфейс UART MCU.
В режиме связи UART сначала отправьте 8-битный идентификационный байт (0x58) или (0xA8), (0x58) — байт идентификации операции чтения, (0xA8) — байт идентификации операции записи, а затем отправьте байт адреса регистра для определения Доступ Адрес регистра (см. список регистров BL0942), один кадр передачи данных завершен, и BL0942 снова входит в режим связи.
Существует два типа структур кадров: кадры операций записи и кадры операций чтения.
Формат кадра операции записи следующий:
Время записи данных UART хоста показано на рисунке ниже. Хост сначала отправляет командный байт {1,0,1,0,1,0,A2,A1}, затем отправляет необходимый регистровый байт (ADDR). записываются, а затем последовательно отправляются байты данных (сначала младший байт, последним старший байт, если действительные байты данных меньше 3 байтов, недопустимые биты заполняются 0) и, наконец, байт контрольной суммы.
{1,0,1,0,1,0,A2,A1} — это байт идентификации кадра для операции записи. Предположим, {A2,A1}=10, адрес устройства 2, байт идентификации кадра равен 0xAA.
ADDR — это внутренний адрес регистра BL0942, соответствующий операции записи.
CHECKSUM байтдля({1,0,1,0,1,0,A2,A1}+ADDR+DATA[7:0]+DATA[15:8]+DATA[23:16])&0xFF Отрицать.
Формат кадра операции чтения следующий:
Время чтения данных UART хоста показано на рисунке ниже. Хост сначала отправляет командный байт {0,1,0,1,1,0,A2,A1}, затем отправляет необходимый байт адреса регистра (ADDR). быть прочитан, а затем BL0942 отправляет байты данных последовательно (сначала младший байт, последний старший байт, если действительные байты данных меньше 3 байтов, недопустимые биты заполняются 0) и, наконец, байт контрольной суммы.
{0,1,0,1,1,0,A2,A1} — байт идентификации кадра для операции чтения. Предположим, что {A2,A1}=10, адрес устройства равен 2, а байт идентификации кадра — 0x5A.
ADDR — это внутренний адрес регистра BL0942, соответствующий операции чтения.
CHECKSUM байтдля({0,1,0,1,1,0,A2,A1}+ADDR+DATA[7:0]+DATA[15:8]+DATA[23:16])&0xFF Отрицать.
Примечание. Адрес устройства пакета SSOP10L равен 0, то есть {A2,A1}=00.
Требования к времени показаны на рисунке ниже:
Этот проект считывает параметры измерения электрической энергии BL0942, которые предназначены для чтения полного пакета данных электрических параметров.
С помощью команды «{0,1,0,1,1,0,A2,A1}+ 0xAA» BL0942 вернет полный пакет данных электрических параметров. Возвращенный пакет данных имеет общий размер 22 байта и занимает около 48 мс при использовании скорости 4800 бит/с.
Формат пакета полностью электрических параметров следующий:
checksum=(({0,1,0,1,1,0,A2,A1} + 0x55 + data1_l + data1_m + data1_h +…….)& 0xff), а затем нажмите Отрицать.
Скорость передачи данных можно настроить с помощью регистра режима UART_RATE_SEL (MODE[9:8]) и вывода SCLK_BPS. Каждый раз, когда микросхема включается, значение сброса RATE_SEL равно 0x0. В это время скорость передачи данных определяется на основе вывода SCLK_BPS.
Чип BL0942 имеет некоторые встроенные механизмы защиты, а именно:
BL0942 в основном разделен на две части: аналоговая обработка сигналов и обработка цифровых сигналов. Аналоговая часть в основном включает в себя двухканальный PGA, двухканальный сигма-дельта АЦП, встроенные часы (внутренние часы), включение/сброс (включение питания). /reset), LDO и другие соответствующие аналоговые модули, цифровая часть — это модуль цифровой обработки сигналов (DSP).
Ток и напряжение пропускаются через аналоговый модуль усилителя (PGA) и высокоточное аналого-цифровое преобразование (АЦП) для получения двух каналов 1-битного ШИМ в цифровой модуль. Цифровой модуль проходит через понижающий преобразователь. фильтр выборки (SINC3), фильтр верхних частот (HPF), смещение канала. Настройте калибровку и другие модули для получения необходимых данных о форме сигнала тока и данных о форме сигнала напряжения (I_WAVE, V_WAVE).
Собранные данные о форме тока и напряжения нагрузки обновляются со скоростью 7,8 тыс. Каждые выборочные данные представляют собой 20-битное число со знаком и сохраняются в регистре формы сигнала (I_WAVE, V_WAVE) соответственно. Конфигурация скорости SPI превышает 375 Кбит/с. значение формы сигнала одного канала можно считывать непрерывно.
Примечание. Регистр имеет длину 24 бита. Если цифр недостаточно, старшие биты заполняются нулями.
Формула расчета активной мощности:
Среди них 𝐼(𝐴), 𝑉(𝑉) — эффективное значение (м В) входного сигнала канала, φ — фазовый угол сигнала переменного тока I(A), V(V), Vref — встроенный при опорном напряжении типичное значение составляет 1,218 В.
Этот регистр указывает, является ли текущая активная мощность положительной или отрицательной мощностью. Бит[23] — это знаковый бит. Бит[23]=0, текущая мощность положительная, Бит[23]=1, текущая мощность отрицательная. сила, дополнение формы.
BL0942 имеет запатентованную функцию защиты от подводных лодок, гарантирующую, что мощность шума на уровне платы не будет накапливать мощность при отсутствии входного тока.
Регистр порогового значения противодействия постепенному увеличению активной мощности (WA_CREEP) представляет собой 8-битное беззнаковое число, значение по умолчанию — 0BH. Соответствующее соотношение между этим значением и значением регистра активной мощности показано в следующей формуле. Когда абсолютное значение входного сигнала активной мощности меньше этого значения, выходная активная мощность устанавливается на 0. Это позволяет в условиях холостого хода, даже при наличии небольшого шумового сигнала, значение, выводимое в регистр активной мощности, равно 0, и электрическая энергия не накапливается.
WA_CREEP может быть установлен в соответствии со значением регистра мощности WATT. Их соответствующее соотношение следующее:
Примечание. Когда текущий канал находится в противолодочном состоянии, действующее значение тока канала не измеряется и также обрезается до 0.
BL0942 обеспечивает измерение импульса электрической энергии. Активная мгновенная мощность интегрируется в зависимости от времени для получения активной энергии и дальнейшего вывода калибровочного импульса CF. Регистр CF_CNT хранит количество импульсов выходной мощности CF, как показано на рисунке ниже:
Потребляемая мощность может быть считана непосредственно из регистра подсчета импульсов активной энергии CF_CNT, или количество импульсов может быть подсчитано напрямую с вывода CF1/CF2/ZX с помощью прерывания ввода-вывода после настройки регистра OT_FUNX, когда период CF. меньше 160 мс, импульс с рабочим циклом 50 %, если длительность больше или равна 160 мс, фиксированная длительность импульса высокого уровня составляет 80 мс.
CF_EN — главный переключатель для вывода импульсов энергии. После выключения CF_CNT прекращает подсчет, а вывод CF1/CF2/ZX прекращает выводить подсчет импульсов энергии.
Вы можете использовать регистр CF_CNT_CLR_SEL, чтобы выбрать, следует ли очищать регистр счетчика CF (CF_CNT) после чтения. Режим накопления энергии импульса можно выбрать через CF_CNT_ADD_SEL.
Примечание. Регистр CF_CNT по умолчанию настроен на режим накопления абсолютного значения импульсов энергии.
Время накопления каждого импульса CF следующее:
Где WATT — соответствующее значение регистра активной мощности (WATT).
Действующие значения каналов тока и напряжения показаны на рисунке ниже. После прохождения через квадратную цепь (X 2), фильтр нижних частот (LPF_RMS) и корневую цепь (ROOT) мгновенное значение. получают эффективное значение RMS_t, а затем получают среднее значение для двух каналов (I_RMS и V_RMS).
Установите MODE[3].RMS_UPDAT_SEL, вы можете выбрать среднее время обновления эффективного значения 400 мс или 800 мс, значение по умолчанию — 400 мс.
Когда канал находится в противолодочном состоянии, эффективное значение текущего канала равно нулю.
Формула преобразования текущей эффективной стоимости:
Формула преобразования действующего значения напряжения:
𝑉𝑟𝑒𝑓 — опорное напряжение, типичное значение — 1,218 В.
Примечание. I(A) — это входной сигнал (м В) между контактами IP и IN, а V(V) — входной сигнал (м В) контакта VP.
BL0942 может быстро собирать эффективное значение тока для реализации функции обнаружения перегрузки по току. I_WAVE_F принимает абсолютное значение, накапливает полупериод или время цикла и сохраняет его в регистре I_FAST_RMS. Оно сравнивается с текущим пороговым регистром быстрого эффективного значения I_FAST_RMS_TH, а затем выдает прерывание по току через вывод.
Установите порог быстрого эффективного значения (т. е. порог сверхтока) через регистр порогового значения быстрого эффективного значения I_FAST_RMS_TH.
Сравните бит[23:8] регистра I_FAST_RMS с порогом перегрузки по току I_FAST_RMS_TH [15:0]. Если он больше или равен установленному порогу, на выводе индикации сигнала перегрузки по току CF1/CF2/ZX выводится высокий уровень. CF1/CF2/ZX устанавливаются регистром конфигурации выхода OT_FUNX.
Установите цикл быстрого обновления RMS через регистр цикла быстрого обновления RMS I_FAST_RMS_CYC. Среди них частота может быть выбрана как 50H или 60Гц в соответствии с настройкой MODE[5]. Если вы выберете 50 Гц, время обновления по умолчанию составит 1 цикл, то есть 20 мс. Например, при выборе самого быстрого накопления за 0,5 такта ошибка регистра I_FAST_RMS будет относительно большой.
Следует отметить, что алгоритмы быстрого эффективного значения и эффективного значения различны. Быстрое эффективное значение используется только для оценки больших сигналов. Быстрые измерения среднеквадратичного значения при слабых сигналах будут неточными из-за включения компонентов смещения постоянного тока. Если вам нужно удалить компонент смещения постоянного тока, установите FAST_RMS_SEL(MODE[4])=1 и выберите форму сигнала после HPF для I_WAVE_F.
Установите частоту переменного тока с помощью MODE[5].
BL0942 обеспечивает обнаружение перехода напряжения и тока через нуль. Сигнал перехода через ноль может выводиться через вывод CF1/CF2/ZX. Ноль на выходе соответствует положительному полупериоду сигнала, а вывод 1 представляет отрицательную половину. цикл формы волны. Задержка фактического входного сигнала составляет 570 мкс.
Настройте выходной контакт через OT_ FUNX (пакет SSOP10L имеет только CF1).
Если эффективное значение напряжения или тока слишком низкое, выходной сигнал обнаружения перехода через ноль будет нестабильным.
Когда старшие 5 бит действующего значения напряжения V_RMS равны 0, V_ZX_LTH_F равен 1, что указывает на то, что эффективное значение напряжения слишком низкое, менее 1/32 полной шкалы, и индикация перехода напряжения через ноль отключается. и остается 0.
Когда старшие 6 бит текущего эффективного значения I_RMS равны 0, I_ZX_LTH_F равен 1, что указывает на то, что текущее эффективное значение слишком низкое, менее 1/64 полной шкалы, и текущая индикация перехода через нуль отключается. и остается на уровне 0.
BL0942 имеет функцию определения частоты сетевого напряжения, которая обновляется каждые несколько установленных циклов (FREQ_CYC), и обнаруживается полноволновая форма волны напряжения.
Разрешение измерения линейного напряжения составляет 2 мкс/младший бит (тактовая частота 500 к Гц), что эквивалентно 0,01% при частоте сети 50 Гц или 0,012% при частоте сети 60 Гц. Соотношение преобразования между регистром сетевого напряжения (FREQ) и фактической частотой сетевого напряжения:
В режиме по умолчанию fs=500 к Гц; для сети с частотой 50 Гц измеренное значение FREQ составляет 20000 (десятичное число), а для сети с частотой 60 Гц измеренное значение FREQ составляет 16667 (десятичное число).
Кроме того, когда эффективное значение напряжения ниже порога определения перехода через ноль, обнаружение частоты сетевого напряжения отключается.
Используйте Arduino IDE для управления ESP8266 для периодического чтения полного пакета данных электрических параметров. Исходный файл выглядит следующим образом:
/******************************************************************************
*
* File Name : bl0942.cpp
*
* Functional Description:
* файл библиотеки драйверов bl0942
*
* Change Logs:
* Date Author Notes explain
* 2022-12-6 yangjunjie V1.0
*
*******************************************************************************/
/******************************************************************************
* Include files
******************************************************************************/
#include "bl0942.h"
/******************************************************************************
* Global variable definitions
******************************************************************************/
static char serial_data[SERIAL_RX_MAXLEN];
// Последовательный порт получает дескриптор очереди данных
extern struct tk_queue serial_receive_dataqueue;
// Этот параметр еще не используется и может использоваться в качестве вторичного калибровочного устройства.
static float adjust_volrate = 1;
static float adjust_currentrate = 1;
static float adjust_powerrate = 1;
/******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/
static void sendCommand(void);
static status_t receiveData(void);
/******************************************************************************
* function realize
******************************************************************************/
/**
******************************************************************************
** \brief Инициализируйте чип BL0942.
**
** \param никто
**
** \retval никто
**
******************************************************************************/
void Init_BL0942(void)
{
Serial.begin(4800, SERIAL_8N1); // 4800bps никто не проверит
Serial.setTimeout(30); // настройки Таймаут последовательного порта на 30мс
memset(serial_data, 0, SERIAL_RX_MAXLEN);
}
/**
******************************************************************************
** \brief Обновляется раз в секунду, считывается последовательно (напряжение, ток, мощность)
**
** \param никто
**
** \retval никто
**
******************************************************************************/
void Updata_BL0942(void)
{
sendCommand(); // Отправить команду
receiveData(); // Обработка данных приема последовательного порта
}
/**
******************************************************************************
** \brief последовательный порт Отправить командуполучать Выбирать Электрический женьшеньданные
**
** \param никто
**
** \retval никто
**
******************************************************************************/
static void sendCommand(void)
{
Serial.write((byte)0X58);
Serial.write((byte)0XAA);
}
/**
******************************************************************************
** \brief Получайте и анализируйте инструкции электрических параметров, полученные через последовательный порт.
**
** \param никто
**
** \retval STATUS_SUCCESS:данные校验成功 STATUS_ERROR: проверка данных не удалась.
**
******************************************************************************/
static status_t receiveData(void)
{
status_t ret = STATUS_SUCCESS;
bool temp_flag = false, receive_flag = false;
char temp_data = 0X00;
uint8_t data_index = 0X00;
uint8_t checksum = 0X58;
char temp_serial_data[SERIAL_RX_MAXLEN];
while(Serial.available())
{
temp_data = (char)Serial.read();
if(temp_data == 0X55) // Определить заголовок кадра
{
temp_flag = true;
}
if(temp_flag == true)
{
temp_serial_data[data_index++] = temp_data;
}
if (data_index >= SERIAL_RX_MAXLEN)
{
// tk_queue_push_multi(&serial_receive_dataqueue, temp_serial_data, SERIAL_RX_MAXLEN); // Загрузить длину данных в кеш
data_index = 0;
temp_flag = false;
receive_flag = true;
// memset(temp_serial_data, 0, SERIAL_RX_MAXLEN);
}
else
{
receive_flag = false;
}
}
// Прием прерываний не используется, режим кэширования временно не используется, эта функция зарезервирована.
// if(tk_queue_empty(&serial_receive_dataqueue) == false) // В кэше есть данные
// {
// tk_queue_pop_multi(&serial_receive_dataqueue, temp_serial_data, SERIAL_RX_MAXLEN); // Получить извлеченные из кэша
if(receive_flag == true)
{
for(uint8_t i = 0; i < SERIAL_RX_MAXLEN - 1; i++) // 校验данные
{
checksum += temp_serial_data[i];
}
checksum = ~(checksum & 0XFF);
if(checksum == temp_serial_data[SERIAL_RX_MAXLEN - 1])
{
memcpy(serial_data, temp_serial_data, SERIAL_RX_MAXLEN);
Log.verboseln("serial receive OK");
}
else
{
Log.errorln("serial receive ERROR");
ret = STATUS_ERROR;
}
}
return ret;
}
/**
******************************************************************************
** \brief получать Выбиратьтекущий **
** \param никто
**
** \retval текущийданные **
******************************************************************************/
float getCurrent(void)
{
uint32_t parm = 0;
float current = 0.0;
parm = ((uint32_t)serial_data[3] << 16) + ((uint32_t)serial_data[2] << 8) + serial_data[1];
current = (float)parm * V_REF * adjust_currentrate * 1000 / (305978 * RL_CURRENT); // mA
return current;
}
/**
******************************************************************************
** \brief Получить Выбирать напряжение
**
** \param никто
**
** \retval Напряжениеданные **
******************************************************************************/
float getVoltage(void)
{
uint32_t parm = 0;
float voltage = 0.0;
parm = ((uint32_t)serial_data[6] << 16) + ((uint32_t)serial_data[5] << 8) + serial_data[4];
voltage = (float)parm * V_REF * (R2_VOLTAGE + R1_VOLTAGE) * adjust_volrate / (73989 * R1_VOLTAGE * 1000);
return voltage;
}
/**
******************************************************************************
** \brief Обнаружение перегрузки по току, быстро собирает эффективное значение тока для реализации функции обнаружения перегрузки по току.
**
** \param никто
**
** \retval Текущие быстрые эффективные значения
**
******************************************************************************/
float getFastCurrent(void)
{
uint32_t parm = 0;
parm = ((uint32_t)serial_data[9] << 16) + ((uint32_t)serial_data[8] << 8) + serial_data[7];
float fcurrent = (float)parm * V_REF * adjust_currentrate * 1000 / (305978 * RL_CURRENT); // mA
return fcurrent;
}
/**
******************************************************************************
** \brief Усиление Выбирать активную мощность
**
** \param никто
**
** \retval Активная мощностьданные
**
******************************************************************************/
float getActivePower(void)
{
uint32_t parm = 0;
float power = 0.0;
parm = ((uint32_t)serial_data[12] << 16) + ((uint32_t)serial_data[11] << 8) + serial_data[10];
if (1 == bitRead(serial_data[12], 7))
{
parm = 0xFFFFFF - parm + 1; // Выбирать补码 }
power = (float)parm * adjust_powerrate * V_REF * V_REF * (R2_VOLTAGE + R1_VOLTAGE) / (3537 * RL_CURRENT * R1_VOLTAGE * 1000);
return power;
}
/**
******************************************************************************
** \brief Получить Выбирать потребление электроэнергии
**
** \param никто
**
** \retval Потребление электроэнергииданные
**
******************************************************************************/
float getEnergy(void)
{
uint32_t parm = 0;
float energy = 0.0;
parm = ((uint32_t)serial_data[15] << 16) + ((uint32_t)serial_data[14] << 8) + serial_data[13];
energy = (float)parm * 1638.4 * 256 * V_REF * V_REF * (R2_VOLTAGE + R1_VOLTAGE) / (3600000.0 * 3537 * RL_CURRENT * R1_VOLTAGE * 1000);
return energy;
}
/**
******************************************************************************
** \brief Функция определения частоты линейного напряжения
**
** \param никто
**
** \retval Частота сетевого напряженияданные
**
******************************************************************************/
float getFREQ(void)
{
uint32_t parm = 0;
float FREQ = 0.0;
parm = ((uint32_t)serial_data[18] << 16) + ((uint32_t)serial_data[17] << 8) + serial_data[16];
if (parm > 0)
{
FREQ = 500 * 1000 * 2 / (float)parm;
}
return FREQ;
}
/**
******************************************************************************
** \brief рабочий статус
**
** \param никто
**
** \retval рабочий статусданные
**
******************************************************************************/
uint8_t getSTATUS(void)
{
return (uint8_t)serial_data[19];
}
/******************************************************************************/
/* EOF (not truncated) */
/******************************************************************************/
Заголовочный файл выглядит следующим образом:
/******************************************************************************
*
* File Name : bl0942.h
*
* Functional Description:
* файл библиотеки драйверов bl0942
*
* Change Logs:
* Date Author Notes explain
* 2022-12-6 yangjunjie V1.0
*
*******************************************************************************/
#ifndef __BL0942_H__
#define __BL0942_H__
/******************************************************************************/
/* Include files */
/******************************************************************************/
#include <Arduino.h>
#include "tk_queue.h"
/* C binding of definitions if building with C++ compiler */
#ifdef __cplusplus
extern "C"
{
#endif
//@{
/******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
#define V_REF 1.218
#define RL_CURRENT 1 // 0,001 Ом, единица миллиом
#define R2_VOLTAGE 1950 // 390К*5, ед. для К Евро
#define R1_VOLTAGE 0.51 // 0,51К, ед. для тыс. евро
#define SERIAL_RX_MAXLEN 23
/******************************************************************************
** Local type definitions ('typedef')
******************************************************************************/
/******************************************************************************
* Global variable definitions ('extern')
******************************************************************************/
// Определить, пуста ли очередь
extern bool tk_queue_empty(struct tk_queue *queue);
// Поместите (поставьте в очередь) несколько элементов в очередь данных.
extern uint16_t tk_queue_push_multi(struct tk_queue *queue, char *pval, uint16_t len);
// Извлечь (удалить из очереди) несколько элементов из очереди данных
extern uint16_t tk_queue_pop_multi(struct tk_queue *queue, char *pval, uint16_t len);
/*****************************************************************************
* Function definitions - global ('extern') and local ('static')
******************************************************************************/
// Инициализируйте чип BL0942.
void Init_BL0942(void);
// Обновляется раз в секунду, считывается последовательно (напряжение, ток, мощность)
void Updata_BL0942(void);
// получать Выбиратьтекущийfloat getCurrent(void);
// Получить Выбирать напряжение
float getVoltage(void);
// Обнаружение перегрузки по току, быстро собирает эффективное значение тока для реализации функции обнаружения перегрузки по току.
float getFastCurrent(void);
// Усиление Выбирать активную мощность
float getActivePower(void);
// Получить Выбирать потребление электроэнергии
float getEnergy(void);
// Функция определения частоты линейного напряжения
float getFREQ(void);
// рабочий статус
uint8_t getSTATUS(void);
//@}
#ifdef __cplusplus
}
#endif
#endif /* __BL0942_H__ */
/******************************************************************************/
/* EOF (not truncated) */
/******************************************************************************/
Компания Shanghai Belling также предоставляет микросхему измерения мощности, требующую калибровки: BL0937.
При определении продукта BL0937 учитывает, что производители интеллектуальных розеток не являются профессиональными производителями измерительных приборов, не имеют профессионального и дорогостоящего калибровочного оборудования и имеют относительно низкие требования к точности измерения электрической энергии. Они предоставляют только справочную информацию об электричестве, но не предоставляют ее. используйте его в качестве стандарта выставления счетов. Интеллектуальной розетке необходимо только считывать мощность, напряжение, ток и измерять накопленную мощность на основе мощности. Поэтому нет необходимости в сложном протоколе связи между BL0937 и MCU для считывания регистра измерительного чипа в режиме реального времени. Калибровка точности дозирования также относительно проста, достаточно установить номинальную мощность. Калибровочный коэффициент калибруется под нагрузкой и не требует сложного калибровочного оборудования.
Схема применения решения BL0937 выглядит следующим образом и после реальных испытаний она стабильна и надежна:
Заинтересованные друзья могут изучить это решение. Поскольку оно не используется в этом проекте, я не буду вдаваться в подробности.