В статье предлагается конструкция прибора способного вести длительную регистрацию медленных изменений действующего напряжения в бытовой электросети. Прибор выполнен на основе аппаратной платформы Arduino, собранные данные сохраняются на MicroSD карту.

Внешний вид устройства
Внешний вид устройства

ВНИМАНИЕ! В приборе присутствует опасное для жизни напряжение, какие-либо манипуляции с устройством, можно проводить, только обеспечив видимый разрыв с электрической сетью.

Стабильность напряжения в бытовой электросети важна для надежной работы многих электроприборов. Однако далеко не всегда значение напряжения отвечает всем необходимым стандартам, особенно если электросети протяженные, их оборудование устарело, а качество обслуживания вызывает вопросы. В таких условиях потребителю стоит задуматься о приобретении стабилизаторов или источников бесперебойного питания. Однако такое оборудование стоит довольно дорого и перед его покупкой стоит произвести мониторинг изменений напряжения в сети. В простейшем случае для такого мониторинга достаточно относительно точного мультиметра и блокнота [1], но проведение такого рода измерений в ручном режиме отнимет много времени, а значит собрать по настоящему исчерпывающую информацию будет непросто. Предлагаемый автором прибор по сути и представляет такой автоматизированный вольтметр с запоминающим устройством, который дает возможность собрать минимальную информацию о качестве электропитания, когда использование профессиональных вольтамперфазометров неоправданно.

Электрическая принципиальная схема устройства
Электрическая принципиальная схема устройства

Основой прибора является плата MassDuino UNO, которая в целом аналогична Arduino UNO, но имеет ряд заметных отличий [2], самым важным из которых в данном случае является 12-разрядный АЦП вместо 10-разрядного у Arduino UNO [3]. В цепь питания установлен предохранитель FU1, рассчитанный на ток 200 мА. Питание платы осуществляется от исследуемой электросети через понижающий трансформатор T1 230/12 В с номинально допустимым током второй обмотки 500 мА. Ко вторичной обмотке T1 подключен диодный мост VD1 типа RS205. Для сглаживания пульсаций предусмотрен LC-фильтр, собранный на готовом дросселе L1 с индуктивностью примерно 300 мГн и батарее фильтрующих конденсаторов C1-C2 типа К50-24 емкостью 10000 мкФ, рассчитанных на напряжение 16В. Питание подается на плату MassDuino UNO через контакт Vin, который предназначен для питания платы от внешнего нестабилизированного источника. Модуль для MicroSD карты питается от стабилизатора платы MassDuino UNO, для работы с этим модулем задействованы 4, 11, 12 и 13 цифровые порты MassDuino UNO. Так как у платы MassDuino UNO каждый контакт представляет собой параллельно включенные гнездо и штыревой контакт, то модуль для работы с MicroSD картой подключен при помощи шестипроводного шлейфа без применения пайки. Трансформатор T2 служит для измерения напряжения сети, это понижающий трансформатор 230/10 В с номинально допустимым током второй обмотки 300 мА. Ко вторичной обмотке T2 подключен диодный мост VD2 типа RS605. Для сглаживания пульсаций предусмотрен LC-фильтр, собранный на готовом дросселе L2 с индуктивностью примерно 30 мГн и пленочных конденсаторах C3-C4 типа К73-17 емкостью 470 нФ, рассчитанных на напряжение 63В. Конденсатор C5 типа К10-7в имеет емкость 47 нФ и рассчитан на напряжение 50 В. Напряжение на этих конденсаторах составляет около 8 В, при этом АЦП MassDuino UNO может работать с напряжением в диапазоне 0-5 В, поэтому измеряемое напряжение подается на делитель, собранный на прецизионных резисторах R1-R4 типа ПТМН-0,5 сопротивлением 10 кОм. Одно плечо делителя образовано резистором R1, а другое тремя параллельно включенными резисторами R3-R4, т. о. на порт A0 платы MassDuino UNO поступает напряжение около 2 В. Так, как в цепи вторичной обмотки трансформатора T2 отсутствуют конденсаторы большой емкости или стабилизаторы напряжения, то изменение напряжения на порту A0 относительно быстро меняется вслед за изменением напряжения в питающей сети, т. о. измерив напряжение на выводе A0 можно сравнительно просто определить действующее значение напряжения в сети. Конденсатор C6 типа КТК емкостью 300 пФ располагается рядом с резисторами R1-R4 делителя и призван уменьшить возможные наводки возникающие в измерительной цепи.

Устройство собрано в корпусе старого компьютерного блока питания стандарта AT (для любителей ретрокомпьютеров отмечу, что данный блок попал ко мне уже в частично разукомплектованном и полностью нерабочем состоянии), при этом его штатный разъем питания типа AC-016 оставлен на месте, а все остальное содержимое удалено.

Размещение компонентов устройства в корпусе
Размещение компонентов устройства в корпусе

На месте разъема типа PX0675/63 расположена пластина с держателем типа ДП1ЦМ для предохранителя FU1.

Колодка предохранителя и разъем питания прибора
Колодка предохранителя и разъем питания прибора

Трансформаторы T1 и T2 закреплены в корпусе при помощи хомутов из металлической перфорированной ленты. Диодный мост VD1 и конденсаторы C1-C2, размещены на самодельной печатной плате.

В измерительной цепи диодный мост VD2 размещен на его штатном радиаторе. Радиатор непосредственно прикреплен к корпусу. Разумеется, этот радиатор избыточен, но он дает возможность надежно закрепить диодный мост VD2 и не оставляет ни какой возможности того, что протекающего по нему ток вызовет нагрев этого электронного компонента, который теоретически может привести к изменению параметров диодного моста VD2. Плата с дросселем L2 и конденсаторами C3, C4, C5 взята готовая из старого блока питания, она крепится к корпусу при помощи мебельного уголка МК 16х16х12 мм. Делитель напряжения на резисторах R1-R4 собран на самодельной плате. Также на этой же плате находится конденсатор C6.

Плата делителя напряжения, плата MassDuino UNO и модуль для MicroSD карты размещены на фигурной пластине, вырезанной из органического стекла толщиной 5 мм.

Модуль для работы с MicroSD картой размещен перпендикулярно крепежной пластине, так, чтобы разъем для MicroSD карты располагался напротив отверстия, которое в корпусе блока питания служило для вывода проводов питания. Это позволяет вынимать MicroSD карту без снятия крышки корпуса.

Размещение microSD карты в корпусе прибора
Размещение microSD карты в корпусе прибора

Для надежного крепления этого модуля была изготовлена отдельная прямоугольная крепежная пластина из органического стекла толщиной 5 мм, к основной крепежной пластине она фиксируется при помощи пары мебельных уголков МК 16х16х12 мм.

В общем виде алгоритм работы прибора довольно прост: при подаче питания проверяется наличие MicroSD карты, а затем через равные промежутки времени производится измерение напряжения питающей сети, а на MicroSD карту записываются результаты измерения.

Код программы
/*
На основе кода из примера
  SD card datalogger
   created  24 Nov 2010
 modified 9 Apr 2012
 by Tom Igoe
  
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4
*/
              
// voltmetr
// Цифровой вольтметр


#include <SPI.h>
#include <SD.h>
#include <TimerOne.h>

const int chipSelect = 4;
const int dt = 10; //задержка во времени, предназначенная ограничить запись измерений на SD карту одним измерением в секунду
int sensor; //переменная для хранения результата, считанного с АЦП
int vA=0; // переменная для хранения значения считанного с порта А0
int portA=0; // входное напряжение считываем с порта А0

unsigned long k = 0; // счетчик количества измерений
int n = 300; //номер последнего элемента в массиве VL[], счет начинается с 0
int VL[301]; //массив для хранения результатов измерения 
int sort; //вспомогательная переменная для сортировки
int i,j; //счетчики в массивах и циклах

void setup()                     
{
 
  // Open serial communications and wait for port to open:
  Serial.begin(1200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  Serial.print("Initializing SD card...");
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
  
  pinMode(13, OUTPUT); //встроенный светодиод используем для индикации процесса измерения
  
  Timer1.initialize(1000000);
  Timer1.attachInterrupt(Volt);
}

void loop()                      
{
  digitalWrite(13, LOW); // светодиод по умолчанию погашен  
}


void Volt()
{
    digitalWrite(13, HIGH); // светодиод загорается в начале цикла измерения  
     
    String dataString = "";
    String dataString_volt = "";
    String dataString_volt_A = "";
    k = k+1; // счетчик измерений
     
    for (i = 0; i <= n; i = i + 1)  
    {
      sensor = analogRead(portA); // считываем с АЦП значение на основе которого будем рассчитывать напряжение в сети
      VL[i] = sensor-81; // 81 - шумы установки при нулевом напряжении на входе 
    
      //Serial.print(VL[i]);
      //Serial.print(' ');
      
    }
  
    // вывод считанных значений до сортировки (для отладки)
    /*
    for (i = 0; i <= n; i = i + 1) 
    {
      Serial.print(VL[i]);
      Serial.print(' ');
    }
    Serial.println();
    */

    //Сортировка пузырьком
    for (i = 0; i <= n; i = i + 1) 
    {
      for (j = 0; j <= n; j = j + 1) 
      {
        if (VL[i] < VL[j]) 
        {
          sort = VL[i];
          VL[i] = VL[j];
          VL[j] = sort;
        }
      }
    }

    // вывод массива после сортировки (для отладки)
    /*
    for (i = 0; i <= n; i = i + 1) 
    {
       Serial.print(VL[i]);
       Serial.print(' ');
    }
    Serial.println();
    */
    
    // VL[n/2+1] -  медианное среднее, середина отсортированного массива       
    dataString += String(VL[n/2+1]); // получение строки, содержащей значение считанное с АЦП
    dataString_volt_A += String(VL[n/2+1] * 1.221);  // конвертируем показания из аналогового порта в милливольты
    dataString_volt += String(VL[n/2+1]*1.221*0.106); // получение строки, содержащей значение напряжения сети в вольтах 0.106=220/2080, где 220 - напряжение в сети, 2080 - соответствующее сетевому напряжению 220 В напряжение на входе АЦП (в мВ)
     
    // open the file. note that only one file can be open at a time,
    // so you have to close this one before opening another.
    File dataFile = SD.open("datalog.txt", FILE_WRITE);

    // if the file is available, write to it:
    if (dataFile) {
      dataFile.print(k); // запись на SD карту, номера измерения, приблизительно соответствующего одному измерению в секунду
      dataFile.print(" ");
      dataFile.print(dataString); //запись на SD карту результата работы АЦП за вычетом шумов
      dataFile.print(" ");
      dataFile.print(dataString_volt_A); //запись на SD карту результата работы АЦП в милливольтах
      dataFile.print(" ");
      dataFile.println(dataString_volt); //запись на SD карту напряжения расчитанного по результатам работы АЦП
      dataFile.close();
       
      // повторения вывода в последовательный порт (для отладки)
      /*Serial.print(k);
      Serial.print(" ");
      Serial.print(dataString);
      Serial.print(" ");
      Serial.print(dataString_volt_A);
      Serial.print(" ");
      Serial.println(dataString_volt);*/
       
    }
    // if the file isn't open, pop up an error:
    else {
      Serial.println("error opening datalog.txt");
    }    
}

Программа, управляющая устройством, создана в среде Arduino IDE. В начале программы подключаются необходимые сторонние библиотеки, инициализируются переменные и назначаются номера портов для внешних устройств (1-34 строки кода). В строках с 36 по 57 располагается функция setup в которой устанавливается скорость обмена по последовательному порту, проверяется наличие MicroSD карты, инициализируется 13 цифровой порт, к которому подключен встроенный светодиод и устанавливается промежуток времени между прерываниями по таймеру. Следует отметить, что хотя в коде указано, что таймер должен срабатывать каждую секунду, но на деле измерение производится примерно раз в пять секунд. Причины данной аномалии автору не ясны, в любом случае в работе данного прибора важно, чтобы измерения проводились достаточно часто и через равные интервалы времени. В функции loop (59-62 строки) располагается только одна команда на гашение светодиода, подключенного к 13 цифровому порту. Основная часть кода (65-152 строки) это процедура обработки прерывания Volt. В строке 67 дается команда на зажигание светодиода, подключенного к 13 цифровому порту, т. о. по периодическому миганию этого светодиода можно отслеживать работу программы. Команда delay в коде программы не используется, в качестве времени задержки выступает время обработки прерывания. Пока процедура выполняется светится встроенный светодиод платы, когда прерывание обработано светодиод гаснет по команде из функции loop. Так как время обработки прерывания довольно велико, то кратковременную вспышку светодиода можно заметить. В строках 69-71 инициализируются строки которые будут использоваться для записи на MicroSD карту, в строке 72 располагается счетчик общего количества измерений, проведенных с момента подачи питания или последней перезагрузки. В строках 74-82 расположен цикл в котором происходит опрос порта A0 и заполнение массива VL, который, затем используется для вычисления среднего значения. В строках 84-92 размещен цикл для вывода через последовательный порт необработанных результатов измерений, эта часть кода необходима только на этапе отладки. В строках 94-106 расположен алгоритм для сортировки массива VL методом пузырька [4, 5, 6]. В строках 108-116 размещен цикл для вывода через последовательный порт отсортированного массива VL, эта часть кода также нужна только на этапе отладки. В отсортированном массиве средний элемент представляет собой медианное среднее по данной выборке измерений [7]. Для дальнейших вычислении будем использовать медианное среднее. В строке 119 в dataString помещаем это медианное среднее, в строке 120 в dataString_volt_A помещаем результат работы АЦП пересчитанный в милливольты. Значение напряжения на входе АЦП можно измерить вольтметром и сравнить с рассчитанным значением, это полезно при наладке прибора. Автор использовал мультиметр VICTOR 88B [8]. В строке 121 производится расчёт действующего напряжения в электросети. В строке 125 для записи открывается файл на MicroSD карте. В строках 128-151 располагается ветвление, проверяющее можно ли вести запись данных в файл, в котором либо производит запись, либо выдается информацию об ошибке. В строках 129-136 производится запись на MicroSD карту текущего номера измерения, медианного значения выданного АЦП и рассчитанных на его основе напряжений на входе АЦП и действующего значения напряжения в сети. В строках 138-145 производится дублирование вывода в последовательный порт, эта часть кода нужна только при отладке.

Наладка собранного прибора состоит в том, чтобы изменяя константы в строках 77, 120 и 121 добиться того, чтобы в файл записывались значения напряжения, мало отличающиеся от результатов измерения выполненных внешним "эталонным" прибором.

По результатам работы программы на MicroSD карте оказывается сформирован текстовой файл данных, который можно использовать для дальнейшей обработке информации.

Фрагмент файла с результатами измерений

1 -10 -12.21 -1.29
2 -6 -7.33 -0.78
3 -7 -8.55 -0.91
4 1785 2179.48 231.03
5 1774 2166.05 229.60
6 1786 2180.71 231.15
7 1804 2202.68 233.48
8 1793 2189.25 232.06
9 1835 2240.53 237.50
10 1780 2173.38 230.38
11 1762 2151.40 228.05
12 1753 2140.41 226.88
13 1785 2179.48 231.03
14 1773 2164.83 229.47
15 1775 2167.27 229.73
16 1764 2153.84 228.31
17 1754 2141.63 227.01
18 1797 2194.14 232.58
19 1785 2179.48 231.03
20 1776 2168.50 229.86

На основе этих данных можно построить график изменения напряжения в электросети. Для построения простых графиков хорошо подходит утилита Gnuplot [9, 10], для которой надо написать несложный скрипт.

Скрипт Gnuplot
set terminal png large font arial size 800,600
set grid
unset key
set out "Volt.png" 
plot [:500] [200:250] "DATALOG.TXT" using 1:4 with lines lt 1

pause -1

Результатом работы этого скрипта будет изображение с графиком, где по горизонтальной оси отложено время для первых 500 измерений, а по вертикальной оси отсчитывается измеренное значение напряжения в диапазоне от 300 до 250 В. Для построения графика в файле "DATALOG.TXT" берутся данные из 1 и 4 столбцов. На примере такого графика видно, что согласно показаниям самодельного прибора действующее значение напряжения со временем немного изменяется, но остается в переделах нормы.

График изменения напряжения питания
График изменения напряжения питания

Вертикальная линия в начале графика соответствует моменту подачи питания на трансформаторы. Конструкция устройства допускает его питание через разъем microUSB на плате MassDuino UNO, при этом напряжение питания также поступает и на модуль для работы с microSD картой. Таким образом при условии питания регистрирующей части от пауэрбанка можно регистрировать изменения напряжения в самых широких пределах, даже когда напряжение в электросети не будет достаточным для питания данного прибора.

Источники

1. КАКОЙ стабилизатор напряжения ЛУЧШЕ для ВАШЕГО дома ? - URL: https://www.youtube.com/watch?v=YdVtvv28mdo

2. MassDuino UNO: распиновка, подключение и работа с платой. - URL: https://2shemi.ru/massduino-uno-raspinovka-podklyuchenie-i-rabota-s-platoy/?ysclid=m2rizw7f38299110024

3. Блум Д. Изучаем Arduino: инструменты и методы технического волшебства: Пер. с англ. СПб.: БХВ-Петербург, 2015. 336 с.

4. Пузырьковая сортировка и все-все-все. - URL: https://habr.com/ru/articles/204600/

5. Описание алгоритмов сортировки и сравнение их производительности. - URL: https://habr.com/ru/articles/335920/

6. Сортировка массива. - URL: https://arduino.ru/forum/programmirovanie/sortirovka-massiva

7. Савельев В. Статистика и котики. М.: АСТ, 2018. 122 с. - URL: https://elementy.ru/nauchno-populyarnaya_biblioteka/433745/Statistika_i_kotiki

8. МУЛЬТИМЕТР VICTOR 88B. - URL: https://radioskot.ru/publ/izmeriteli/multimetr_victor_88b/15-1-0-1525

9. Gnuplot и с чем его едят. - URL: https://habr.com/ru/companies/ruvds/articles/517450/

10. http://www.gnuplot.info

Комментарии (16)


  1. Soorin
    28.10.2024 06:54

    Как показывает мой опыт сборки и использования подобных регистраторов (у меня записывают давление воды и текущее время с часов на DS3231(1307) с батарейкой), карту памяти лучше использовать Endurance. Обычная сдыхает очень быстро при "ежесекундной" записи.


    1. YMA
      28.10.2024 06:54

      Или поставить ионисторы в цепь питания и писать блоками покрупнее - хоть раз в полчаса, на сколько памяти хватит, предусмотрев экстренный сброс данных на флешку при отключении питания.


      1. Soorin
        28.10.2024 06:54

        В моей задаче нужно было иметь возможность в любое время забрать SD-карту с данными. Описывать в коде накопитель данных с дампом, например, по кнопке я посчитал лишним.

        P.S. Код нашёл :-D Пишет дату/время и данные в файл .txt (FAT16)


    1. Denev Автор
      28.10.2024 06:54

      Обычная сдыхает очень быстро при "ежесекундной" записи.

      На деле там запись идет примерно раз в 5 с. Неужели такое может быстро повредить SD-карты, учитывая, что каждый раз запись дополняется, а не производится поверх предыдущих данных?


  1. HEXFFFFFFFF
    28.10.2024 06:54

    Мне не понятен смысл данной статьи. Я проффесионально занимаюсь разаботкой подобных устройств( и софтом и железом). Тут речь об уровне школьной поделки, а не о проффесиональном подходе. В принципе подобное соберет и пятикалсник из кружка робототехники. А людям наверно было бы интерестно как решать такие задачи с проффесианальным, а не с дилетанским подходом. Если решать такую задачу проффесионально то стоит использовать совсем другие подходы.

    Я бы взял за основу esp32 , в нем много оперативки, встроенного флеша, wi-fi и блютус. Внешний ADC избыточен, есть свой 12ти разрядный. Собранные данные можно будет сразу просматревать на смартфоне или отправлять на сервер. Можно строить графики и таблицы непосредственно на вебинтерфейсе чипа. Так же избыточна флешка, встроенной в чип памяти хватит для хранения миллионов измерений. Так же нет смысла в трансформаторном питании, можно использовать любой импульсный ас-dc модуль. Не стоит использовать arduino IDE, он сильно снижает ваши возможности разработки. А вот arduino sdk использовать можно. Так же даже такой простейший проект требует использования freeRtos. Так же код стои разделять на юниты и использовать классы. Это сильно олегчает программирование. Так же в схематехнике стоит уделить внимание аналоговой части, сильных шумов и смещений если все правильно сделано не должно быть, а слабые шумы гасятся за счет интегрирования.

    В целом идея интерестная, но при проффесиональном подходе устройство получится очень компактным, с меньшем колличеством деталей и гораздо более функциональным.

    Если речь о функциональном концепте ( то что сделал автор) то работы на несколько вечеров. Если делать полностью готовое решение которое можно массово штамповать в Китае, то такая разработка делается за 2-3 месяца...


    1. iliasam
      28.10.2024 06:54

      "Внешний ADC избыточен, есть свой 12ти разрядный"
      Насколько я знаю, встроенный АЦП в ESP32 довольно убогий. Там есть зоны нечувствительности и нелинейности. Калибровки - та еще морока.
      https://w4krl.com/esp32-analog-to-digital-conversion-accuracy/

      "Так же избыточна флешка"
      С SD-карты зато удобно данные забирать на ПК.
      "Можно строить графики и таблицы непосредственно на вебинтерфейсе чипа"
      Но функциональность будет ограничена прошивкой, текстовые данные можно обработать как угодно в каком угодно софте.


      1. HEXFFFFFFFF
        28.10.2024 06:54

        Да. Ацп убогий, но для задачи измерить 220в с точностью до 0.5 а может и 0.1в с небольшой скоростью пойдет.

        Тот же текстовый или в любом другом формате лог можно скачивать через тот же вебинтерфейс.


    1. Denev Автор
      28.10.2024 06:54

       Тут речь об уровне школьной поделки, а не о проффесиональном подходе. 

      В целом, так и есть, поэтому первым хабом идет "Электроника для начинающих".

       В принципе подобное соберет и пятикалсник из кружка робототехники. 

      Я с детьми много работаю, поэтому должен отметить, что в данном случае вы находитесь в плену профессиональной деформации. Талантливый и увлеченный школьник, повторить такое может, но не в пятом классе, и хотя устройство и не опаснее лабораторного блока питания из книги Борисова "Юный радиолюбитель", но вы скорее всего не захотите быть тем педагогом у которого на занятиях дети имеют дело с опасным для жизни напряжением.

      Я бы взял за основу esp32 , в нем много оперативки, встроенного флеша, wi-fi и блютус. 

      Может и так, но arduino я знаю гораздо лучше чем esp32.

      Так же в схематехнике стоит уделить внимание аналоговой части, сильных шумов и смещений если все правильно сделано не должно быть, а слабые шумы гасятся за счет интегрирования.

      Не подскажите, что по существу я сделал не так? LC-фильтр я поставил, конденсаторы разных типов использовал, длину проводов где смог уменьшил. Мне правда интересно, как можно устройство улучшить.

      В целом идея интерестная, но при проффесиональном подходе устройство получится очень компактным, с меньшем колличеством деталей и гораздо более функциональным.

      Безусловно. я не могу тягаться с командой профессионалов, я сделал устройство на базе того, что знал и на базе того, что лежало в моей радиолюбительской "сокровищнице". Вы же не думаете, что я предлагаю кому-то сейчас на полном серьезе ставить в промышленное устройство, например, конденсаторы К50-24? Сделал я это устройство, когда посмотрел на ценник вольтамперфазометров и понял, что для моих целей подобный аппарат явно избыточен.


      1. HEXFFFFFFFF
        28.10.2024 06:54

        Так esp32 это то же arduino. Вообще вы путаете понятия. Есть arduino IDE, очень убогая штука, крайне не рекомендую. Есть платы arduino, это по сути девкиты различных чипов, есть atmega ( то что вы видимо называете arduino), есть esp32, есть stm итд. Есть arduino sdk, у нее замечательное ядро, его с некоторыми натяжками можно использовать для проф. решений. Это sdk является оберткой над sdk чипа и дает возможность работать с разными чипами используя один и тот же код. Те при использовании arduino sdk для вас переход с atmega на esp или stm будет практически не заметен, код останется почти таким же. И есть arduino библиотеки, их много, но все они в основном деманстрационные, призваны только продемонстрировать подход для реализации чего ни будь. Но эти библиотеки можно "допиливать" и на их основе писать проффесиональные решения, это сильно быстрее чем писать с нуля.

        Откуда у вас шумы можно только предпологать, но мне кажется что скорей всего проблема с землей. У вас я так понимаю нет гальванической развязки между 220в и контроллером. Скорей всего есть какие то разности потенциалов земли входа и контроллера, отсюда перекос. Для начала замкните вход на землю и посмотрите что считывает АЦП, должен быть 0 или почти 0. Так же стоит помотреть высокочастотные помехи по земле, это делается осциллографом. Так же на входе АЦП должны быть вч фильтры ( несколько паралельных керамических конденсатров разной емкости - 1мф, 0.1мф, 100нф, 100пф итд) часто это сильно помагает. А вот индуктивность может наоборот вносить помехи "разгоняя" ВЧ составляющую. Так же наблюдал, например, такую картину- если на какой либо ноге МК даже через резистор подано напряжение выше напряжения питания это тут же сбивает все АЦП в чипе.


  1. iliasam
    28.10.2024 06:54

    RTC в такой проект так и просится - данные времени полезны, когда пишутся долговременные логи. Можно уникальные названия файлам давать.

    Насколько я понял, функция Volt() вызывается из прерывания. Обычно в разработке софта для MCU из прерываний большие функции стараются не вызывать.


    1. Denev Автор
      28.10.2024 06:54

      Здесь большая часть программы это процедура обработки прерывания, я так сделал потому, что как я понимаю, прерывание по таймеру даст более стабильную периодичность записи по сравнению с использованием задержки. За пределами прерывания почти ни какого кода и нет, прерывание ни чему не помешает, главное, чтобы период между запусками прерываний по таймеру был больше времени обработки прерывания.


      1. iliasam
        28.10.2024 06:54

        По прерыванию обычно флаг ставят, сигнализирующий основной программе, то что прерывание произошло.
        "За пределами прерывания почти ни какого кода и нет"
        В Arduino, если не ошибаюсь, есть скрытые от пользователя прерывания - UART и TIM0.
        Пока программа выполняет длительное прерывание, остальные прерывания не будут обрабатываться.


        1. zatim
          28.10.2024 06:54

          По прерыванию обычно флаг ставят, сигнализирующий основной программе, то что прерывание произошло.

          Не первый раз уже слышу о таком подходе. В чем суть таких манипуляций? Ведь тогда теряется весь смысл использования прерывания - отреагировать на событие сразу же как оно произошло. А тут еще надо заводить отдельный флаг, расходовать на него память. А в итоге программа отреагирует на событие только потом, где то в основном цикле, когда доберется до опроса этого флага. И далее, если все равно опрашивается флаг, то зачем заводить для этого новый, отдельный флаг, почему бы тогда не опрашивать уже существующий аппаратный флаг, а прерывание и вовсе выключить? Предвижу ответ - так вы пытаетесь бороться с приоритетами и коллизиями прерываний. Но ведь у современных ядер есть весьма гибкие настройки приоритетов и всего остального, почему бы не воспользоваться ими? Да и у старых ядер, где всего этого не было, тоже не припомню особых проблем.

          Пока программа выполняет длительное прерывание, остальные прерывания не будут обрабатываться.

          Ну, наверное, не остальные [ВСЕ], а только конкретно того, обработка которого идет в настоящий момент.


          1. iliasam
            28.10.2024 06:54

            У вас в MassDuino UNO архитектура - AVR.
            Обратимся к документации производителя - https://developerhelp.microchip.com/xwiki/bin/view/products/mcu-mpu/8-bit-avr/structure/interrupts/
            "When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled."

            В Arduino, насколько я знаю, прерывание TIM0 используется для подсчета времени в системны функциях. Так что длительное выполнение других прерываний нарушит счет времени.

            В принципе, просто флаг ставить - действительно, мало пользы, вместо этого можно анализировать состояние регистров в loop(). Более правильное решение, когда требуется серьезное быстродействие - запуск другого аппаратного модуля, например, запуск АЦП из прерывания таймера. В итоге может выйти целая цепочка из прерываний, и только в одном из них, при выполнении каких-то нескольких условий, будет выставляться флаг в ОЗУ.


            1. zatim
              28.10.2024 06:54

              Вы совершенно верно привели цитату. Но, вот буквально в следующем предложении там пишут что:

              The user software can write logic one to the I-bit to enable nested inter-
              rupts. All enabled interrupts can then interrupt the current interrupt routine. The I-bit is
              automatically set when a Return from Interrupt instruction – RETI – is executed.

              То есть, если сильно надо, то пользователь может не дожидаться окончания обработки текущего прерывания и вручную (первой же командой, например) разрешить глобальные прерывания. И счет времени нарушен не будет.


  1. LeToan
    28.10.2024 06:54

    Тем, кто предпочитает готовые устройства, подойдут регистраторы MI1AC, например.