Вольтметр-самописец

Тема в разделе "Глядите, что я сделал", создана пользователем sagis, 26 дек 2013.

  1. sagis

    sagis Нерд

    Возникла необходимость мониторить напряжение в сети 220В в течении суток, для этого было собрано следующее устройство. В качестве датчика использован Трансформатор с выпрямителем от зарядки мобильника, из которого выкинута схема стабилизации, плюс делитель на резисторах.
    [​IMG]
    Ну и собственно написан скетч
    Код (Text):
    //Подключаем библиотеки
    #include <SD.h> //Библиотека для чтения, записи SD карты
    #include <DS1307RTC.h>// Библиотеки
    #include <Time.h> // для работы
    #include <Wire.h> // часов

    const int chipSelect = 10;
    int analogPin =0; // объявляем пин датчика
    //————————————————————————
    void setup()
    {

      Serial.begin(9600); // инициализация com порта

      Serial.print("Initializing SD card…");
      pinMode(10, OUTPUT);
      if (!SD.begin(chipSelect)) {//инициализация SD карты
        Serial.println("Card failed, or not present");
        return;
      }
      Serial.println("card initialized.");
    }
    //————————————————————————
    void loop()
    {
      tmElements_t tm;

      String dataString = "";//объявляем переменную в которой будем хранить данные

      RTC.read(tm);// читаем данные с часов
      dataString+=(tmYearToCalendar(tm.Year));// читаем год и пишем в буфер
      dataString+= "/";
      dataString+= (tm.Month); // читаем месяц и пишем в буфер
      dataString+= "/";
      dataString+= (tm.Day); // читаем день и пишем в буфер
      dataString+= " ";
      dataString+= (tm.Hour);// читаем час и пишем в буфер
      dataString+= ":";
      dataString+= (tm.Minute);// читаем минуты и пишем в буфер
      dataString+= " ";

      int sensor = analogRead(analogPin)/3.58;// читаем данные с датчика и делим на коэффициент из пункта 2
      dataString += String(sensor);// дописываем в буфер

      File dataFile = SD.open("log.txt", FILE_WRITE);//Открываем SD для записи

      if (dataFile) {

        dataFile.println(dataString);// Пишем буфер на карту

        dataFile.close();

        Serial.println(dataString);

        delay(300000); //ждем 5 минут

      }
      else {
        Serial.println("error opening log.txt");
      }
    }
    Вроде работает нормально, выслушаю конструктивную критику
     
    Последнее редактирование: 29 дек 2013
    OldKryptos, Securbond, ИгорьК и ещё 1-му нравится это.
  2. Megakoteyka

    Megakoteyka Оракул Модератор

    1. Можно было использовать sprintf для форматирования строки. Примерно так:
    Код (Text):
    char buf[64];
    sprintf(buf, "%2d:%2d:%2d voltage = %3.3fV\n", hh, mm, ss, voltage);
    У такого подхода следующие плюсы:
    - не используется динамическая память -> система работает более стабильно и предсказуемо
    - все поля в строках всегда будут одинаковой ширины, что упростит автоматический разбор файла в дальнейшем
    - меньше кода

    2. Строке
    Код (Text):
    int analogPin = 0; // объявляем пин датчика
    место рядом со строкой
    Код (Text):
    const int chipSelect = 10;
    Кстати, почему 0, а не A0?

    3. Перед публикацией исходников нажимайте Ctrl+T в Arduino IDE, пожалуйста.
     
    9xA59kK и sagis нравится это.
  3. sagis

    sagis Нерд

    Просто функция analogRead() работает с аналоговыми входами
    А вот с sprintf интересно попробовать, Спасибо.
     
    Последнее редактирование: 26 дек 2013
  4. Megakoteyka

    Megakoteyka Оракул Модератор

    Аналоговые входы - это же и есть А0-А5.
    Код стал выглядеть гораздо читабельней, так держать! :)
     
  5. sagis

    sagis Нерд

    Ваш вариант мне даже больше понравился, итого скетч переписал плюс убрал общение с компом так как устройство работает автономно в другом месте,
    плюс повесил светодиод на 5 пин который светится при наличии ошибок и гаснет при их устранении
    Код (Text):
    //Подключаем библиотеки
    //Библиотека для чтения, записи SD карты
    #include <SD.h>            
    // Библиотеки для работы часов
    #include <DS1307RTC.h>      
    #include <Time.h>            
    #include <Wire.h>
    // объявляем пин датчика
    int analogPin =0;            
    const int chipSelect = 10;
    //буфер
    char dataString [64];        
    // пин светодиода
    int led = 5;              

    //————————————————————————
    void setup()
    {

      //инициализация SD карты
      pinMode(10, OUTPUT);
      if (!SD.begin(chipSelect)) {
        digitalWrite(led, HIGH);
        return;
      }

      digitalWrite(led, LOW);
    }
    //————————————————————————
    void loop()
    {
      tmElements_t tm;
      // читаем данные с часов
      RTC.read(tm);                          
      // читаем данные с датчика и делим на коэффициент
      int sensor = analogRead(analogPin)/3.58;
      //разбираем данные и пишем в буфер
      sprintf(dataString, "%4d/%2d/%2d %2d:%2d %3d",tmYearToCalendar(tm.Year),tm.Month,tm.Day,tm.Hour,tm.Minute,sensor);
      //Открываем SD для записи
      File dataFile = SD.open("log.txt", FILE_WRITE);
      //пишем буфер на карту
      if (dataFile) {
        dataFile.println(dataString);
        dataFile.close();
        digitalWrite(led, LOW);
        //ждем 5 минут
        delay(300000);
      }
      else {

        digitalWrite(led, HIGH);
      }
    }
     
    Спасибо за помощь
     
  6. Димa

    Димa Нуб

    Здравствуйте, можно подробную схему датчика.
     
  7. Андрей01

    Андрей01 Нерд

    Подскажите пожалуйста, ошибка компиляции для платы, это где то нет точек?
    exit status 1
    Ошибка компиляции для платы Arduino Uno.
     
  8. RonAD

    RonAD Нерд

    Вам необходимо присоединиться к библиотеке RTC1307 здесь:
    https://github.com/PaulStoffregen/DS1307RTC
     
  9. Андрей01

    Андрей01 Нерд

    у меня версия 1.8.4. всё равно ругается. Библиотеку скачал зип архивом и установил
     
  10. b707

    b707 Гуру

    это не все сообщение об ошибке.
    Выложите сообщение полностью - там должно быть написано, в какой строке ошибка и в чем, собственно, она заключается
     
  11. RonAD

    RonAD Нерд

    У меня была такая же ошибка без установки RTC1307.h
    Теперь компилируется без проблем.
    Версия 1.8.2

    Sketch uses 14554 bytes (45%) of program storage space. Maximum is 32256 bytes.
    Global variables use 1152 bytes (56%) of dynamic memory, leaving 896 bytes for local variables. Maximum is 2048 bytes.
     
  12. b707

    b707 Гуру

    блин! еще один знаток :)
    Какая ТАКАЯ ЖЕ ОШИБКА у вас была? :) Ардуина пишет
    Код (C++):
    Ошибка компиляции для платы Arduino Uno.
    на любую ошибку!
     
  13. RonAD

    RonAD Нерд

    Жалобы к разработчикам программного обеспечения IDE К сожалению, Arduino тупо указывает на ошибки и различные аномалии.
     
  14. b707

    b707 Гуру

    А может слово "тупо" не к разработчикам относится?
    Почему у других Ардуино ИДЕ подробно показывает. где именно и в чем ошибка:
    [​IMG]

    а у вас оно "тупит? :)

    Может это кто-то другой тупит и просто не включил подробный вывод сообщений об ошибках в опциях?
     
    Feofan и Un_ka нравится это.
  15. RonAD

    RonAD Нерд

    Я знаю, я сам тупой

    Я имел в виду только плохой редактор /editor
    в Аrduino
    без ошибок и подсказок.
    Cинтаксические ошибки следует немедленно исправлять.
     
  16. Андрей01

    Андрей01 Нерд

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

    Андрей01 Нерд

    Код (Text):

    #include <SPI.h>
    #include <Wire.h>
    #include <SD.h>
    #include <LiquidCrystal_I2C.h>
    File _sd1DF;
    String _sd1TS;
    LiquidCrystal_I2C _lcd1(0x27, 16, 2);
    int _dispTempLength1=0;
    boolean _isNeedClearDisp1;
    bool _sd1SVOS2 = 0;
    int _disp2oldLength = 0;
    bool _gen1I = 0;
    bool _gen1O = 0;
    unsigned long _gen1P = 0UL;
    bool _trgrt1 = 0;
    bool _trgrt1I = 0;
    int _disp1oldLength = 0;
    void setup()
    {
    Wire.begin();
    delay(10);
    _lcd1.init();
    _lcd1.backlight();
    SD.begin(2);
    SPI.begin();
    pinMode(10, OUTPUT);
    }
    void loop()
    {
    if (_isNeedClearDisp1) {_lcd1.clear(); _isNeedClearDisp1= 0;}
    if (!(0)) {
    _dispTempLength1 = (String("Privet ot PERM!")).length();
    if (_disp1oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
    _disp1oldLength = _dispTempLength1;
    _lcd1.setCursor(0, 1);
    _lcd1.print(String("Privet ot PERM!"));
    } else {
    if (_disp1oldLength > 0) {_isNeedClearDisp1 = 1; _disp1oldLength = 0;}
    }
    if (!(0)) {
    _dispTempLength1 = (((String( (analogRead (0)), DEC)))).length();
    if (_disp2oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
    _disp2oldLength = _dispTempLength1;
    _lcd1.setCursor(int((16 - _dispTempLength1)/2), 0);
    _lcd1.print(((String( (analogRead (0)), DEC))));
    } else {
    if (_disp2oldLength > 0) {_isNeedClearDisp1 = 1; _disp2oldLength = 0;}
    }
    if (!(0)) {if (! _gen1I) { _gen1I = 1; _gen1O = 1; _gen1P =  millis(); } } else { _gen1I = 0 ;  _gen1O= 0;  } if (_gen1I ) { if (_gen1O) { if ( _isTimer( _gen1P , 500 )) { _gen1P = millis(); _gen1O = 0; } } else  { if ( _isTimer( _gen1P , 1000 )) {  _gen1P = millis(); _gen1O = 1;  } } }
    if (_gen1O) { if (_trgrt1I) { _trgrt1 = 0;} else {_trgrt1 = 1; _trgrt1I = 1;} } else {_trgrt1 = 0; _trgrt1I = 0;};
    if(_trgrt1)
    {if(! _sd1SVOS2) {
    _sd1TS = "log;";
    _sd1TS+= "String;";_sd1TS+= ";";
    _sd1TS+= (String( (analogRead (0)), DEC));
    _sd1TS+= ";";
    _sd1TS+= ";";
    _sd1DF = SD.open("1.log", FILE_WRITE);
    if (_sd1DF) {_sd1DF.println(_sd1TS); _sd1DF.close();}
    _sd1SVOS2 = 1;}}
    else
    {if( _sd1SVOS2) {_sd1SVOS2 = 0; }}
    }
    bool _isTimer(unsigned long startTime, unsigned long period )
      {
      unsigned long currentTime;
    currentTime = millis();
    if (currentTime>= startTime) {return (currentTime>=(startTime + period));} else {return (currentTime >=(4294967295-startTime+period));}
      }
    Код рабочий, по записи на флешку надо проверять. Нет часов. Пин входа А2, в низу просто послание, 2 строка. Данные выдаются от 0 до 1021 у меня. Попозже скину уже с перерасчетом в 5 вольт. Делал не в иде. Если вдуг не пойдёт, пишите скину ссылку на яндекс диск.
     
  18. Андрей01

    Андрей01 Нерд

    Код (C++):

    #include <SPI.h>
    #include <Wire.h>
    #include <SD.h>
    #include <LiquidCrystal_I2C.h>
    File _sd1DF;
    String _sd1TS;
    LiquidCrystal_I2C _lcd1(0x27, 16, 2);
    int _dispTempLength1=0;
    boolean _isNeedClearDisp1;
    bool _sd1SVOS2 = 0;
    int _disp2oldLength = 0;
    bool _gen1I = 0;
    bool _gen1O = 0;
    unsigned long _gen1P = 0UL;
    bool _trgrt1 = 0;
    bool _trgrt1I = 0;
    int _disp1oldLength = 0;
    void setup()
    {
    Wire.begin();
    delay(10);
    _lcd1.init();
    _lcd1.backlight();
    SD.begin(2);
    SPI.begin();
    pinMode(10, OUTPUT);
    }
    void loop()
    {
    if (_isNeedClearDisp1) {_lcd1.clear(); _isNeedClearDisp1= 0;}
    if (!(0)) {
    _dispTempLength1 = (String("Privet ot PERM!")).length();
    if (_disp1oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
    _disp1oldLength = _dispTempLength1;
    _lcd1.setCursor(0, 1);
    _lcd1.print(String("Privet ot PERM!"));
    } else {
    if (_disp1oldLength > 0) {_isNeedClearDisp1 = 1; _disp1oldLength = 0;}
    }
    if (!(0)) {
    _dispTempLength1 = (((String( (analogRead (0)), DEC)))).length();
    if (_disp2oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
    _disp2oldLength = _dispTempLength1;
    _lcd1.setCursor(int((16 - _dispTempLength1)/2), 0);
    _lcd1.print(((String( (analogRead (0)), DEC))));
    } else {
    if (_disp2oldLength > 0) {_isNeedClearDisp1 = 1; _disp2oldLength = 0;}
    }
    if (!(0)) {if (! _gen1I) { _gen1I = 1; _gen1O = 1; _gen1P =  millis(); } } else { _gen1I = 0 ;  _gen1O= 0;  } if (_gen1I ) { if (_gen1O) { if ( _isTimer( _gen1P , 500 )) { _gen1P = millis(); _gen1O = 0; } } else  { if ( _isTimer( _gen1P , 1000 )) {  _gen1P = millis(); _gen1O = 1;  } } }
    if (_gen1O) { if (_trgrt1I) { _trgrt1 = 0;} else {_trgrt1 = 1; _trgrt1I = 1;} } else {_trgrt1 = 0; _trgrt1I = 0;};
    if(_trgrt1)
    {if(! _sd1SVOS2) {
    _sd1TS = "log;";
    _sd1TS+= "String;";_sd1TS+= ";";
    _sd1TS+= (String( (analogRead (0)), DEC));
    _sd1TS+= ";";
    _sd1TS+= ";";
    _sd1DF = SD.open("1.log", FILE_WRITE);
    if (_sd1DF) {_sd1DF.println(_sd1TS); _sd1DF.close();}
    _sd1SVOS2 = 1;}}
    else
    {if( _sd1SVOS2) {_sd1SVOS2 = 0; }}
    }
    bool _isTimer(unsigned long startTime, unsigned long period )
      {
      unsigned long currentTime;
    currentTime = millis();
    if (currentTime>= startTime) {return (currentTime>=(startTime + period));} else {return (currentTime >=(4294967295-startTime+period));}
      }
     
    В верхней строке параметр в аналоге, во второй строке перерасчёт в вольты. Странно у меня вообще параметр в (v) просел, показывает 4в, что реально учитывая питание с юсб
     
  19. b707

    b707 Гуру

    и так видно, что не в ИДЕ. Такую бредятину только FLProg генерить умеет. угадал?
    Бросайте эту фигню, учитесь лучше сами программировать, а не картинки-мурзилки рисовать
     
    Feofan, Igor68 и parovoZZ нравится это.
  20. Андрей01

    Андрей01 Нерд

    Правильно, но смотрите шире!!, надо быстро что то проверить, фл прог, нарисовал и вперёд, потом реинжиниринг никто не отменял, есть проекты где часть кода из иде и фл прога. Главное работает. А вот по надёжности - увы. Ардуину надо заменять на другой процессор. Для дома и быта хватает за глаза.