Проблема с отображением истинного среднеквадратичного значения основного напряжения с использованием Arduino Uno и MAX7219
Я хочу отобразить истинное среднеквадратичное значение основного напряжения, используя Arduino и MAX7219. Сначала я использовал схему №1 (следующая схема) и библиотеку True RMS. Схема может успешно возвращать истинное среднеквадратичное значение и печатать его на последовательном мониторе Arduino каждые 0,5 с. Точность была приемлемой. Эта схема была запитана от ПК.
На следующем этапе я решил использовать MAX7219 (библиотека LedControl) для отображения истинного среднеквадратичного значения напряжения на 7-сегментном дисплее. Для этого я использовал схему №2. Я не знаю, что случилось. Отображаемое напряжение имело вариации. В схеме №1 максимальная погрешность составила 1 вольт (проверено мультиметром истинного среднеквадратичного значения - например, напряжение было 210 В, а напечатанное напряжение было 209 или 211 В). А вот в схеме №2 ошибка была до 10 В с быстрым изменением. Например, напряжение было около 210 В (с помощью мультиметра) в течение минуты, но отображаемое напряжение Arduino было 203, затем 209, затем 217, затем 205, затем 200, затем 215, ....
Я также использовал другой мультиметр с истинным среднеквадратичным значением для проверки первого мультиметра. Напряжение было таким же, как и первое. Проблема заключалась в том, что напряжение оставалось примерно постоянным, а Arduino показывал переменное напряжение. Проверил подаваемое напряжение с ПК. В нем нет эффективных изменений.
Я также использовал схему № 3, но у меня все еще была та же проблема. Похоже, проблема связана с использованием MAX7219. Каково решение?
Мой код (для двухцветного 7-сегментного общего анода - у меня 3 цифры):
#include <TrueRMS.h>
#include <digitalWriteFast.h> // Он использует digitalWriteFast только для целей отладки!
// https://code.google.com/archive/p/digitalwritefast/downloads
#define LPERIOD 1000 // 1000 циклов времени в нас. В этом случае 1,0 мс
#define ADC_INPUT 0 // определяем используемый входной канал АЦП
#define RMS_WINDOW 40 // окно среднеквадратичного значения из 40 отсчетов, что означает 2 периода при 50 Гц
// #define RMS_WINDOW 50 // окно среднеквадратичного значения из 50 отсчетов, что означает 3 периода при 60 Гц
#define PIN_DEBUG 4
unsigned long nextLoop;
int adcVal;
int cnt = 0;
float VoltRange = 5.00; // Значение полной шкалы установлено на 5,00 Вольт, но может быть изменено при использовании
// входная схема масштабирования перед АЦП.
Rms readRms; // создать экземпляр Rms.
// Max7219 ============================================== ================
#include "LedControl.h"
int ClockPin = 5;
int CsPin = 6;
int DinPin = 7;
LedControl lc = LedControl(DinPin, ClockPin, CsPin, 1);
// 1, так как мы используем только 1 MAX7219
void setup() {
Serial.begin(115200);
pinMode(PIN_DEBUG, OUTPUT);
// настроить автоматическое восстановление базовой линии и режим непрерывного сканирования:
readRms.begin(VoltRange, RMS_WINDOW, ADC_10BIT, BLR_ON, CNT_SCAN);
//readRms.begin(VoltRange, RMS_WINDOW, ADC_10BIT, BLR_OFF, CNT_SCAN);
// настроить без восстановления базовой линии и режим одиночного сканирования:
//readRms.begin(VoltRange, RMS_WINDOW, ADC_10BIT, BLR_OFF, SGL_SCAN);
readRms.start(); // начинаем измерение
nextLoop = micros() + LPERIOD; // Установить переменную таймера цикла для следующего интервала цикла.
// Макс7219
// ноль относится к номеру MAX7219, это ноль для 1 чипа
lc.shutdown(0, false); // отключить энергосбережение, включить отображение
lc.setIntensity(0, 15); // 15 настроек яркости (от 0 до 15 возможных значений)
lc.clearDisplay(0); // очисти экран
}
// Макс7219
byte board[1][8] = {
{
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000
}
};
// Max7219 Устройство
void ClearDisplay(int b, int digit) {
for (int i=0; i<8; i++) { // Он очищает все сегменты Digit "digit" устройства "n"
bitClear(board[b][i], 7-digit);
}
}
void Display() {
for (int i=0; i<9; i++){
lc.setRow(0, i, board[0][i]);
}
}
// Число цифр устройства точка
void SetNum(int b, int digit, int num, int dot) {
switch(num) {
case -2: // отображает "-"
bitClear(board[b][0], 7-digit); // сегмент А
bitClear(board[b][1], 7-digit); // сегмент-B
bitClear(board[b][2], 7-digit); // сегмент C
bitClear(board[b][3], 7-digit); // сегмент-D
bitClear(board[b][4], 7-digit); // сегмент-E
bitClear(board[b][5], 7-digit); // сегмент-F
bitSet(board[b][6], 7-digit); // сегмент-G
break;
case -1: // очищает дисплей
bitClear(board[b][0], 7-digit); // сегмент А
bitClear(board[b][1], 7-digit); // сегмент-B
bitClear(board[b][2], 7-digit); // сегмент C
bitClear(board[b][3], 7-digit); // сегмент-D
bitClear(board[b][4], 7-digit); // сегмент-E
bitClear(board[b][5], 7-digit); // сегмент-F
bitClear(board[b][6], 7-digit); // сегмент-G
break;
case 0:
bitSet(board[b][0], 7-digit); // сегмент А
bitSet(board[b][1], 7-digit); // сегмент-B
bitSet(board[b][2], 7-digit); // сегмент C
bitSet(board[b][3], 7-digit); // сегмент-D
bitSet(board[b][4], 7-digit); // сегмент-E
bitSet(board[b][5], 7-digit); // сегмент-F
bitClear(board[b][6], 7-digit); // сегмент-G
break;
case 1:
bitClear(board[b][0], 7-digit); // сегмент А
bitSet(board[b][1], 7-digit); // сегмент-B
bitSet(board[b][2], 7-digit); // сегмент C
bitClear(board[b][3], 7-digit); // сегмент-D
bitClear(board[b][4], 7-digit); // сегмент-E
bitClear(board[b][5], 7-digit); // сегмент-F
bitClear(board[b][6], 7-digit); // сегмент-G
break;
case 2:
bitSet(board[b][0], 7-digit); // сегмент А
bitSet(board[b][1], 7-digit); // сегмент-B
bitClear(board[b][2], 7-digit); // сегмент C
bitSet(board[b][3], 7-digit); // сегмент-D
bitSet(board[b][4], 7-digit); // сегмент-E
bitClear(board[b][5], 7-digit); // сегмент-F
bitSet(board[b][6], 7-digit); // сегмент-G
break;
case 3:
bitSet(board[b][0], 7-digit); // сегмент А
bitSet(board[b][1], 7-digit); // сегмент-B
bitSet(board[b][2], 7-digit); // сегмент C
bitSet(board[b][3], 7-digit); // сегмент-D
bitClear(board[b][4], 7-digit); // сегмент-E
bitClear(board[b][5], 7-digit); // сегмент-F
bitSet(board[b][6], 7-digit); // сегмент-G
break;
case 4:
bitClear(board[b][0], 7-digit); // сегмент А
bitSet(board[b][1], 7-digit); // сегмент-B
bitSet(board[b][2], 7-digit); // сегмент C
bitClear(board[b][3], 7-digit); // сегмент-D
bitClear(board[b][4], 7-digit); // сегмент-E
bitSet(board[b][5], 7-digit); // сегмент-F
bitSet(board[b][6], 7-digit); // сегмент-G
break;
case 5:
bitSet(board[b][0], 7-digit); // сегмент А
bitClear(board[b][1], 7-digit); // сегмент-B
bitSet(board[b][2], 7-digit); // сегмент C
bitSet(board[b][3], 7-digit); // сегмент-D
bitClear(board[b][4], 7-digit); // сегмент-E
bitSet(board[b][5], 7-digit); // сегмент-F
bitSet(board[b][6], 7-digit); // сегмент-G
break;
case 6:
bitSet(board[b][0], 7-digit); // сегмент А
bitClear(board[b][1], 7-digit); // сегмент-B
bitSet(board[b][2], 7-digit); // сегмент C
bitSet(board[b][3], 7-digit); // сегмент-D
bitSet(board[b][4], 7-digit); // сегмент-E
bitSet(board[b][5], 7-digit); // сегмент-F
bitSet(board[b][6], 7-digit); // сегмент-G
break;
case 7:
bitSet(board[b][0], 7-digit); // сегмент А
bitSet(board[b][1], 7-digit); // сегмент-B
bitSet(board[b][2], 7-digit); // сегмент C
bitClear(board[b][3], 7-digit); // сегмент-D
bitClear(board[b][4], 7-digit); // сегмент-E
bitClear(board[b][5], 7-digit); // сегмент-F
bitClear(board[b][6], 7-digit); // сегмент-G
break;
case 8:
bitSet(board[b][0], 7-digit); // сегмент А
bitSet(board[b][1], 7-digit); // сегмент-B
bitSet(board[b][2], 7-digit); // сегмент C
bitSet(board[b][3], 7-digit); // сегмент-D
bitSet(board[b][4], 7-digit); // сегмент-E
bitSet(board[b][5], 7-digit); // сегмент-F
bitSet(board[b][6], 7-digit); // сегмент-G
break;
case 9:
bitSet(board[b][0], 7-digit); // сегмент А
bitSet(board[b][1], 7-digit); // сегмент-B
bitSet(board[b][2], 7-digit); // сегмент C
bitSet(board[b][3], 7-digit); // сегмент-D
bitClear(board[b][4], 7-digit); // сегмент-E
bitSet(board[b][5], 7-digit); // сегмент-F
bitSet(board[b][6], 7-digit); // сегмент-G
break;
default:
break;
}
if (dot == 1) {
bitSet(board[b][7], 7-digit); // seg-dp
}
}
// 0-1-2-3
// Число цифр устройства Цвет точек
void SetNumWithColor(int b, int digit, int num, int dot, char color) {
switch(color) {
case 'r': // цифры 0,1,2,3 красные
SetNum(b, digit, num, dot);
SetNum(b, 4, -1, dot); // очищает все зеленые сегменты
SetNum(b, 5, -1, dot); // очищает все зеленые сегменты
SetNum(b, 6, -1, dot); // очищает все зеленые сегменты
SetNum(b, 7, -1, dot); // очищает все зеленые сегменты
break;
case 'g': // цифры 4,5,6,7 зеленые
SetNum(b, digit+4, num, dot);
SetNum(b, 0, -1, dot); // очищает все красные сегменты
SetNum(b, 1, -1, dot); // очищает все красные сегменты
SetNum(b, 2, -1, dot); // очищает все красные сегменты
SetNum(b, 3, -1, dot); // очищает все красные сегменты
break;
case 'o':
SetNum(b, digit, num, dot); // Включает красный
SetNum(b, digit+4, num, dot); // Включает зеленый
break;
default:
break;
}
Display();
}
void loop() {
adcVal = analogRead(ADC_INPUT); // прочитать АЦП.
// чтениеRms.update(adcVal); // Обновить
digitalWriteFast(PIN_DEBUG, HIGH);
readRms.update(adcVal); // для сигналов BLR_ON или DC(+AC) с BLR_OFF
// readRms.update(adcVal-512); // без автоматического восстановления базовой линии (BLR_OFF); здесь вычтите фиксированное смещение постоянного тока в единицах АЦП.
digitalWriteFast(PIN_DEBUG, LOW);
cnt++;
if (cnt >= 1500) { // 500 = публиковать каждые 0,5 с
readRms.publish();
float RMS=readRms.rmsVal;
float AccRMS=RMS*128;
int RMSout=AccRMS;
Serial.print("Vrms=");
Serial.print(RMSout);
int a1=RMSout/100;
int b1=RMSout%100;
int a2=b1/10;
int a3=b1%10;
if (RMSout<200) { // Красный
SetNumWithColor(0, 0, a1, 0, 'r'); // отображает a1 в цифре 0
SetNumWithColor(0, 1, a2, 0, 'r'); // отображает a2 в цифре 1
SetNumWithColor(0, 2, a3, 0, 'r'); // отображает a3 в цифре 2
}else if(RMSout<215){ // Оранжевый
SetNumWithColor(0, 0, a1, 0, 'o'); // отображает a1 в цифре 0
SetNumWithColor(0, 1, a2, 0, 'o'); // отображает a2 в цифре 1
SetNumWithColor(0, 2, a3, 0, 'o'); // отображает a3 в цифре 2
}else{ // Зеленый
SetNumWithColor(0, 0, a1, 0, 'g'); // отображает 1 в цифре 0
SetNumWithColor(0, 1, a2, 0, 'g'); // отображает 2 в цифре 1
SetNumWithColor(0, 2, a3, 0, 'g'); // отображает 3 в цифре 2
}
Serial.print(", Vin=");
Serial.println(RMS,4);
// float dc=readRms.dcBias;
// Serial.println(dc,4);
cnt=0;
// чтениеRms.start(); // Перезапустить сбор данных после публикации, если выбран режим одиночного сканирования.
}
while (nextLoop > micros()); // ждем окончания временного интервала цикла
nextLoop += LPERIOD; // устанавливаем время следующего цикла на текущее время + LOOP_PERIOD
}
// конец Measure_rms.ino
@soheil, 👍2
1 ответ
Не видя вашего кода, трудно догадаться полностью, но это мое предположение:
- Измерение среднеквадратичного значения должно выполняться быстро в течение короткого периода времени, чтобы зафиксировать пиковые значения формы волны переменного тока.
- Вы обновляете экран во время измерения.
- Обновления дисплея замедляют выборку формы сигнала переменного тока, что приводит к неверным значениям.
Вы должны убедиться, что выборка сигнала переменного тока происходит достаточно быстро, не делая ничего другого (много) в течение периода выборки и отображая что-либо на дисплее только тогда, когда вся выборка для текущей точки данных выполнена.< /p>
- max7219 связанный дисплей, показывающий зеркальный текст
- Разница между 3,3 В и 5 В
- Почему пассивный зуммер щелкает, а не гудит, когда установлен на ВЫСОКИЙ?
- Как получить общее среднее полученных данных
- Датчик напряжения Калибровка
- Можно ли питать Wemos D1 R2 через контакты VIN и GND?
- Гирляндное соединение нескольких блоков матрицы 4x(8x8) MAX7219
- Создать входной сигнал линейного изменения с помощью Arduino Uno
Спасибо. Перед отображением рассчитывается среднеквадратичное значение за два периода. Итак, обновление происходит после измерения и расчета. Код находится здесь (https://github.com/MartinStokroos/TrueRMS). На самом деле, я построил только A0, используя «Последовательный плоттер» Arduino. Я мог видеть, что амплитуда явно быстро меняется в цепи № 2 !!!! пока мультиметр этого не подтвердил. Но для схемы №1 этого не произошло вообще. Почему? Влияет ли Max7219 на вход A0 или синусоиду сетевого напряжения?, @soheil
Это только библиотека и примеры. Это не *ваш* код., @Majenko
Я добавил свой код. Спасибо, @soheil
@soheil ответ применим и к setup (), @Juraj