Главная » Измерения
Призовой фонд
на ноябрь 2017 г.
1. Термометр Relsib WT51
Рэлсиб
2. 1000 руб
PCBWay
3. Тестер компонентов LCR-T4
Паяльник
4. 200 руб.
От пользователей

16 канальный логгер измерений потребления переменного тока из сети 220В

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

Основными требованиями были:

  • неинвазивный способ измерения тока
  • использование датчика SCT-013-030
  • 16 каналов измерений
  • введение лога всех измерений вместе с датой и временем на SD карточку
  • питание от внешнего блока питания 12В
  • подключение датчиков с помощью пайки проводов на плате

После неких раздумий были оговорены и согласованы некоторые компоненты. Это микроконтроллер ATmega328, модуль RTC DS3231 и модуль для работы с microSD (ведь сейчас доступнее достать microSD, а разницы то нет).

Микросхемы DS3231 в нашем городе не нашлось, но зато Arduino модулей DS3231 просто навалом. Поэтому использовался такой вот модуль RTC:

RTC модуль DS3231

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

  • Питание у нас от внешнего блока питания на 12В, а значит нам нужен стабилизатор напряжения на 5В.
  • Контроллер с необходимой обвязкой(кварц, подтягивающие резисторы и т.д.)
  • RTC модуль
  • microSD модуль
  • А также интерфейс UART для передачи данных на ПК, и интерфейс для внутрисхемного программирования контроллера по SPI 

Всё чего не хватает в этом списке, это схема подключения датчиков SCT-013-030, и схема реализации 16 каналов измерений (ведь у ATmega328 всего несколько ножек для аналогового измерения, и то некоторые заняты интерфейсом I2C, 27 и 28 ножки).

Давайте по очереди. Сначала разберемся с датчиком тока.

Датчик тока SCT-013-030

По своей сути этот датчик является измерительным трансформатором тока. Датчик меряет силу переменного тока. Внутри датчика мы уже имеем встроенное сопротивление в 62 Ом, в результате чего на выходе мы имеем напряжение от 0 до 1 В в зависимости от измеряемого тока 0-30 А. Проблема в том что и на выходе датчика у нас получается переменное напряжение 0 - 1 В(если по простому то от -1 до +1 В). А это не подходит нам, так как контроллер не поймет отрицательного напряжения. Простейшим способом избавиться от этого, это было сдвинуть это напряжение к средней точке с помощью делителя напряжения, как показано на части схемы ниже. С помощью делителя на 2 выводе датчика мы получим 2.5 В.

SCT-013-030 scheme

Таким образом на 1 выводе в точке "CH1" мы будем получать напряжение от 1.5 до 3.5 В (то-есть 2.5 В +-, те 0-1 В что выдает датчик).

Далее я стал думать, как бы организовать 16 каналов измерений. Тогда я вспомнил об одной микросхеме, которую я использовал на своей дипломной работе - CD4052, аналоговый 8-и канальный мультиплексор/демультиплексор.

CD4052-img

В нашем случае данную микросхему разумно использовать как мультиплексор, то-есть справа мы имеем входы X0-X3 и Y0-Y3 и слева выходы X и Y. В результате при использовании двух таких микросхем мы бы смогли измерять 16 каналов с помощью 4 аналоговых ножек контроллера. Но добравшись до даташита такого чуда, я обнаружил более для меня удобного его брата - CD4051.

CD4051-img

Где использовав две таких микросхемы, ми сможем измерить все 16 каналов только с помощью двух аналоговых ножек контроллера.

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

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

Следующим этапом стало проектирование печатной платы, товарищ указал необходимые размеры и форму платы. И процесс начался. За один-два дня плата была разведена, вытравлена, спаяна и готова к работе. Файл печатной платы прикреплен в формате Sprint Layout к статье ниже.

Фото вытравленной и спаянной платы.

Плата-фото-1Плата-фото-3

А также необходимо указать что и куда подключается на плате.

Подключения для платы

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

Для начала попробую продемонстрировать работу всего лишь с одним датчиком тока SCT-013-030:

#define AVRG_VOLT 2.50

float voltage0 = (analogRead(A0) * 5.0)/1024.0; 
current = fabs(voltage0 - AVRG_VOLT) * 30;

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

пропорция для тока

, где Коррекция средней точки

, так как нам не важно направление измеряемого тока.

А значит:

 Формула определения тока

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

Неправильный график

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

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

Формула действующего значения

А если быть точными, то проще всего будет для расчета взять все мгновенные значения за один период. Так как частота сети у нас 50 Гц, то период будет равен:

Период 

Период будет равен 0.02 с, или же 20 мс. Поэтому нам достаточно на протяжении 20 мс измерять мгновенные значения, после чего найти их среднее квадратическое значение.

Поэтому был написан вот такой вот код реализующий простенький алгоритм уже для измерения действующего значения сразу всех каналов(весь код можно просмотреть ниже и во вложениях к статье):

unsigned char i = 0;
  for(i=0; i<8; i++)
  {
    Set_CHANNELs(i);
    f_50hz_time = millis();
    unsigned long k_rms = 0;
    float Irms_0=0.0f, Irms_1=0.0f;
    while(f_50hz_time+20>=millis())
    {
      float voltage0 = (analogRead(A0) * 5.0)/1024.0; 
      float voltage1 = (analogRead(A1) * 5.0)/1024.0;
      Irms_0 += sq((voltage0 - AVRG_VOLT) * 30);
      Irms_1 += sq((voltage1 - AVRG_VOLT) * 30);
      k_rms++;
    }
    ADC_data[i] = sqrt(Irms_0/k_rms);
    ADC_data[i+8] = sqrt(Irms_1/k_rms);
  }

Нормальный график

 

Да, такая картина уже больше похожа на правду. Поэтому на этом можем и остановится. Давайте приведем весь листинг кода программы:

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

DS3231  rtc(SDA, SCL);            
File myFile;

//CONSTANTs
#define AVRG_VOLT 2.50

//PINs
#define A 5
#define B 6
#define C 7
#define INH 8
#define SS_PIN 10

//MACROSes
#define GET_DATA() rtc.getDateStr(FORMAT_SHORT, FORMAT_LITTLEENDIAN, '-')
#define GET_TIME() rtc.getTimeStr(FORMAT_LONG)

float ADC_data[16] = {0};

unsigned long write_time;
unsigned long f_50hz_time;
unsigned long DelayTime = 1000;

byte UART_Time[6] = {0,0,0,0,0,0};
unsigned char index_time = 0;

void ADC_measure(void);
void WriteDataToSD(void);
void ReadAllFiles(void);
void WriteDataToUART(void);

void get_commands(void);


void setup() {
  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  
  pinMode(INH, OUTPUT);
  digitalWrite(INH, HIGH);
  
  pinMode(SS_PIN, OUTPUT);
  write_time = millis();

  Serial.begin(115200);
  delay(100);
  Serial.println("Before RTC init");
  rtc.begin();
  Serial.println("After RTC init");
  if(!SD.begin(SS_PIN)) 
  {
    Serial.println("SD card init fail.");
  }
}


void loop() {
  get_commands();
  ADC_measure();
  WriteDataToSD();
}




void Set_CHANNELs(unsigned char number)
{
  digitalWrite(INH, HIGH);
   switch (number)
  {
   case 0:digitalWrite(C,0);
          digitalWrite(B,0);
          digitalWrite(A,0);
          break;
   case 1:digitalWrite(C,0);
          digitalWrite(B,0);
          digitalWrite(A,1);
          break;
   case 2:digitalWrite(C,0);
          digitalWrite(B,1);
          digitalWrite(A,0);
          break;
   case 3:digitalWrite(C,0);
          digitalWrite(B,1);
          digitalWrite(A,1);
          break;
   case 4:digitalWrite(C,1);
          digitalWrite(B,0);
          digitalWrite(A,0);
          break;
   case 5:digitalWrite(C,1);
          digitalWrite(B,0);
          digitalWrite(A,1);
          break;
   case 6:digitalWrite(C,1);
          digitalWrite(B,1);
          digitalWrite(A,0);
          break;
   case 7:digitalWrite(C,1);
          digitalWrite(B,1);
          digitalWrite(A,1);
          break;
   default: break;
  }
  digitalWrite(INH, LOW);
}

void ADC_measure(void)
{
  unsigned char i = 0;
  for(i=0; i<8; i++)
  {
    Set_CHANNELs(i);
    f_50hz_time = millis();
    unsigned long k_rms = 0;
    float Irms_0=0.0f, Irms_1=0.0f;
    while(f_50hz_time+20>=millis())
    {
      float voltage0 = (analogRead(A0) * 5.0)/1024.0; 
      float voltage1 = (analogRead(A1) * 5.0)/1024.0;
      Irms_0 += sq((voltage0 - AVRG_VOLT) * 30);
      Irms_1 += sq((voltage1 - AVRG_VOLT) * 30);
      k_rms++;
    }
    ADC_data[i] = sqrt(Irms_0/k_rms);
    ADC_data[i+8] = sqrt(Irms_1/k_rms);
  }
}

void WriteDataToSD(void)
{
  unsigned char i = 0;
  myFile = SD.open(GET_DATA(), FILE_WRITE);
  if((write_time+DelayTime) < millis())
  {
    if(myFile)
    {
      for(i=0; i<16; i++)
      {
        myFile.print(GET_DATA()); myFile.print(';'); myFile.print(GET_TIME()); myFile.print(';'); myFile.print(i+1); myFile.print(';'); myFile.print(ADC_data[i]); myFile.println(';');
      }
      Serial.println("Success writing data to FILE");
    }
    else
    {
      Serial.println("Error read file from SD card");
    }
    write_time = millis();
  }
  myFile.close();
}

void ReadAllFiles(void)
{
  File dir = SD.open("/");
  dir.rewindDirectory();
  File myFile = dir.openNextFile();
  while(myFile)
  {
    Serial.print("\n\r File name: "); Serial.println(myFile.name());
    while(myFile.available())
    {
      Serial.write(myFile.read());
    }
    myFile.close();
    myFile = dir.openNextFile();
  }
  
  Serial.println("NO MORE FILES");
}

void WriteDataToUART(void)
{
  unsigned char i = 0;
  if( (write_time+DelayTime) < millis())
  {
    Serial.println();
    Serial.print(GET_DATA()); Serial.print(" "); Serial.println(GET_TIME());
    for(i=0; i<16; i++)
    {
      Serial.print("CH "); Serial.print(i); Serial.print(": "); Serial.print(ADC_data[i]); Serial.print(" A");Serial.print("\n\r");
    }
    write_time = millis();
  }
}

void get_commands(void)
{
  char cmd;
  if(Serial.available())
  {
    cmd = Serial.read();
  }
  
  switch(cmd)
  {
    case 't':
    {
      //DD MM YY - Day Month Year, HH MM SS - Hours Minutes Seconds
      Serial.println("Input date and time at this format -> DD MM YY HH MM SS ");
      while(!Serial.available());
      while((Serial.available()))
      {
        UART_Time[index_time] = byte(Serial.parseInt());
        index_time++;
      }
      rtc.setDate(UART_Time[0], UART_Time[1], UART_Time[2]);
      rtc.setTime(UART_Time[3], UART_Time[4], UART_Time[5]);
      index_time = 0;
      Serial.print("Date and time set to "); Serial.print(GET_DATA()); Serial.print(" "); Serial.println(GET_TIME());
      break;
    }
    case 'r':
    {
      ReadAllFiles();
      break;
    }
    default:break;
  }
}

Дополнительная информация.

Лог на карточку введется таким образом: каждый день создается новый файл с именем в виде даты(например "15-10-17") и в этот файл построчно пишутся данные в формате

ДАТА;ВРЕМЯ;№ КАНАЛА;ЗНАЧЕНИЕ

Также работать с устройством можно с помощью терминала по COM-порту.

Например для настройки часов достаточно отправить команду в виде символа 't', после чего указать дату и время в формате DD MM YY HH MM SS. Все действия сопровождаются подсказками.

Или же можно считать все лог-файлы с помощью команды 'r'.

Исходник прошивки и печатная плата прикреплены к статье.

Список радиоэлементов

Обозначение Тип Номинал Количество ПримечаниеМагазинМой блокнот
U$1 МК AVR 8-бит
ATmega328P Automotive
1 Поиск в LCSCВ блокнот
U1 Линейный регулятор
LM1117-N
1 5VПоиск в LCSCВ блокнот
U$2, U$6 Мультиплексор/демультиплексор
CD4051B
2 Поиск в LCSCВ блокнот
DS3231 Arduino Module1 Поиск в LCSCВ блокнот
microSD Arduino Module1 Поиск в LCSCВ блокнот
U$11-U$26 Датчик токаSCT-013-03016 Поиск в LCSCВ блокнот
Резисторы
R1, R5, R14-R47 Резистор
10 кОм
34 0805Поиск в LCSCВ блокнот
Конденсаторы
C1 Электролитический конденсатор470 мкФ x 25 В1 Поиск в LCSCВ блокнот
C6 Электролитический конденсатор10 мкФ x 16 В1 Поиск в LCSCВ блокнот
C2, C3, C8, C9, C11, C14, C15, C21 Конденсатор100 нФ8 0805Поиск в LCSCВ блокнот
C24-C39 Электролитический конденсатор10 мкФ х 10 В16 Поиск в LCSCВ блокнот
С10 Конденсатор10 нФ1 0805Поиск в LCSCВ блокнот
С12,С13 Конденсатор22 пФ2 0805Поиск в LCSCВ блокнот
Другое
L1 Катушка индуктивности10 мкГн1 0805Поиск в LCSCВ блокнот
Q1 Кварцевый резонатор16 МГц1 Поиск в LCSCВ блокнот
JP1, JP2 Штыревой разъем PLS1х101 Поиск в LCSCВ блокнот
Добавить все

Скачать список элементов (PDF)

Прикрепленные файлы:

Теги:

Опубликована: 0 1
Я собрал 0 0
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 0 Проголосовало: 0 чел.

Комментарии (7) | Я собрал (0) | Подписаться

0
Публикатор #
На форуме автоматически создана тема для обсуждения статьи.
Ответить
0
andro #
Хорошая работа, респект!
Ответить
0

[Автор]
vadim18081997 #
Да, спасибо. Здесь еще очень много пространства для маневров, так сказать. Доработать, и оптимизировать еще можно очень много всего. Применять другие трансформаторы тока, а то эти уж больно по карману бьют.
Попробовать перевести все это на STMку, которая в пару раз дешевле АТмеги. Вообщем в плане удешевления есть куда двигаться. Ну и круто было бы еще сделать общение с компьютером с помощью своего ПО с удобным графическим интерфейсом, а не просто по терминалу.
Это все так планы на будущую доработку, мало ли кому еще может пригодится такое устройство.
Ответить
0
oleg #
Спасибо за статью, как раз надо собрать аналогичный логгер, только для записи напряжения сети.
Ответить
0

[Автор]
vadim18081997 #
Пожалуйста. Если что обращайтесь, так как я всегда не против помочь кому-то или поучаствовать в каких то проектах.
Ответить
0
walhi #
Штука прикольная. Есть несколько доработок, которые хотелось бы увидеть. Всегда есть рядом 220В. Почему бы не питаться от него. Для удаленной работы нужен RS485 с промышленным протоколом Modbus, В нем вроде даже возможность передачи истории и файлов есть. Если будет процессор попроизводительнее, то можно раз в день предыдущие файлы сжимать.
Относительно формата времени. Лучше использовать метку unix (количество секунд с 01.01.1970 00:00:00). Места гораздо меньше занимает.
Ответить
0

[Автор]
vadim18081997 #
Спасибо за внимание. Согласен с вами, доработать еще есть что.
А насчет 220В, то это знакомый попросил чтобы был внешний БП 220В/12В.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется электрическая мощность?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Мультиметр DT9205A
Мультиметр DT9205A
Набор начинающего радиолюбителя Конструктор - темброблок на LM1036
вверх