Pull to refresh

Локальная автономная система сбора данных (продолжение)

Reading time 8 min
Views 5.1K
Начало на данном сайте по ссылке.

Самым удобным для использования вариантом съёма информации о включении пускателя оказался вариант с оптопарой PC817.

Принципиальная схема
image alt

Платы содержат по три одинаковых схемы, всё помещено в коробки из ABS пластика, размер 100х100 мм.

Фото оптопар
image alt

При подключении к пусковым аппаратам с полупроводниковыми вентилями их ток утечки достаточен для открытия РС817 и будет ложное срабатывание счётчика. Для исключения такой ситуации последовательно в цепь светодиода оптопары и светодиода индикации работы добавляется ещё один. Для этого размыкается перемычка J1 и впаивается дополнительный светодиод LED1.

Приёмная часть выполнена на

сторона 1
image alt

сторона 2
image alt

макетной плате подключаемой к ARDUINO MEGA 2560. Для этого используется двухрядный разъём на торце. В качестве устройства отображения информации используется имеющий резистивный тач и датчик температуры экран с разрешением 240х400

HX8352B.
image alt

Причём разъём к ICSP на плате экрана демонтирован и не используется гнездо для микро- SD. Дело в том, что «родное» гнездо SD нельзя применить по причине конфликта на шине SPI. Для флеш- карты был применен отдельный кардридер имеющий в составе стабилизатор 3,3В и буферную микросхему с тремя состояниями выходов 74LVS125A. Вот тут ждали меня грабли. Буфер с тремя состояниями, но работал или E01-ML01DP5 или кардридер. В комментариях библиотеки SdFat разглядел предупреждение о несовместимости с другими устройствами. Был удалён конвертер уровней на TXS0108E и заменён перемычками, т.к. E01-ML01DP5 толерантен к 5В сигналам- не помогло. С помощью осциллографа выявлено пропадание сигнала на линии MISO при подключении кардридера. При внимательном рассмотрении было установлено, что входы разрешающих сигналов ОЕ 4-х каналов 74LVS125A были просто припаяны к общему проводу и ни о каком третьем состоянии речи быть не могло. Буферная микросхема использовалась как примитивный преобразователь уровней от 5В к 3.3В с использованием резисторов 3,3 КОм включенных последовательно с сигнальными линиями. Кроме линии MISO. Её выходной нижний ключ вероятно притягивал сигналы к уровню «земли». Определив что разрешающий сигнал линии MISO- это вывод 13, он был оторван от дорожки и

припаян
image alt

между выводом входа (9) 74LVS125A выбора устройства CS и резистором согласования. Теперь если нет обращения к карте памяти, MISO- буфер отключается и не мешает работе другого устройства.

Схема макетной платы
image alt

Приёмник в работе
image alt

Для подключения часов на DS3231 используется программная шина I2C (TWI).

Программа Arduino IDE
// IMPORTANT: Adafruit_TFTLCD LIBRARY MUST BE SPECIFICALLY
// CONFIGURED FOR EITHER THE TFT SHIELD OR THE BREAKOUT BOARD.
// SEE RELEVANT COMMENTS IN Adafruit_TFTLCD.h FOR SETUP.
//by Open-Smart Team and Catalex Team
//catalex_inc@163.com
//Store:   http://dx.com
//           https://open-smart.aliexpress.com/store/1199788
//Demo Function: Display graphics, characters
//Arduino IDE: 1.6.5
// Board: Arduino UNO R3, Arduino Mega2560,Arduino Leonardo

// Board:OPEN-SMART UNO R3 5V / 3.3V, Arduino UNO R3, Arduino Mega2560
//3.2INCH TFT:
// https://www.aliexpress.com/store/product/3-2-TFT-LCD-Display-module-Touch-Screen-Shield-board-onboard-temperature-sensor-w-Touch-Pen/1199788_32755473754.html?spm=2114.12010615.0.0.bXDdc3
//OPEN-SMART UNO R3 5V / 3.3V:
// https://www.aliexpress.com/store/product/OPEN-SMART-5V-3-3V-Compatible-UNO-R3-CH340G-ATMEGA328P-Development-Board-with-USB-Cable-for/1199788_32758607490.html?spm=2114.12010615.0.0.ckMTaN

#include <Adafruit_GFX.h>    // Core graphics library
//#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#include "SdFat.h"           // Use the SdFat library
SdFat SD;
SdFile file;
File myFile;
#define SD_CS_PIN SS

#include <SPI.h>                                               // Подключаем библиотеку для работы с шиной SPI
#include <nRF24L01.h>                                          // Подключаем файл настроек из библиотеки RF24
#include <RF24.h>                                              // Подключаем библиотеку для работы с nRF24L01+
RF24           radio(47, 49);

#include <DS3231.h>

DS3231  rtc(27, 25);
Time  t;

uint16_t   r = 6000;
uint32_t    k = 0;

volatile unsigned long data;
float leb_1;
float leb_2;
float leb_3;
float leb_4;

uint8_t        pipe;
int rc = 0;

uint8_t time_sec_prev;
uint8_t time_day_prev;

//***********************************************//
// If you use OPEN-SMART TFT breakout board                 //
// Reconmmend you to add 5V-3.3V level converting circuit.
// Of course you can use OPEN-SMART UNO Black version with 5V/3.3V power switch,
// you just need switch to 3.3V.
// The control pins for the LCD can be assigned to any digital or
// analog pins...but we'll use the analog pins as this allows us to
//----------------------------------------|
// TFT Breakout  -- Arduino UNO / Mega2560 / OPEN-SMART UNO Black
// GND              -- GND
// 3V3               -- 3.3V
// CS                 -- A3
// RS                 -- A2
// WR                -- A1
// RD                 -- A0
// RST                -- RESET
// LED                -- GND
// DB0                -- 8
// DB1                -- 9
// DB2                -- 10
// DB3                -- 11
// DB4                -- 4
// DB5                -- 13
// DB6                -- 6
// DB7                -- 7

// Assign human-readable names to some common 16-bit color values:
#define	BLACK   0x0000
#define	BLUE    0x001F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF
#define GRAY    0x8C51
#define GRAYD   0x39E7

//Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
// If using the shield, all control and data lines are fixed, and
// a simpler declaration can optionally be used:
// Adafruit_TFTLCD tft;
uint16_t g_identifier;

String dataString;
//String numfileMonth ="1.txt";
char perv [] = {"2.txt"};
//String *numfileMonth="1.txt" (sizeof (numfileMonth));
///////////////////////////////////////////////////////////////////

void setup(void) {

  rtc.begin();

  // Для установки времени- раскомментировать нужные строки
  // rtc.setDOW(6);               // День недели
  // rtc.setTime(22, 04, 0);      // Время, в формате 24 часа.
  // rtc.setDate(4, 5, 2019);   // Дата, 29 октября 2018г.

  Serial.begin(2000000);
//////// Инициализация экрана
  tft.begin(0x65);
  tft.reset();
  tft.setRotation(0);
  tft.cp437(true);
//////////////////Вывод имен, принадлежности оборудования, название организации
  tft.fillScreen(BLACK);
  tft.setTextColor(WHITE);
  tft.setTextSize(2);
  tft.setCursor (8, 0);
  tft.println ("DEVELOPERS & BUILD" );
  tft.setCursor (30, 20);
  tft.print (utf8rus("Конструктор В.В." ));
  tft.setCursor (40, 40);
  tft.print (utf8rus("Токарь И.И." ));
  delay (2000);

  radio.begin();                             // Инициируем работу nRF24L01+
  radio.setChannel(120);                     // Указываем канал приёма данных (от 0 до 127)
  radio.setDataRate     (RF24_250KBPS);      // Указываем скорость передачи данных (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS), RF24_1MBPS - 1Мбит/сек
  radio.setPALevel      (RF24_PA_MAX);       // Указываем мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm)
  radio.openReadingPipe (1, 0xAABBCCDD11LL); // Открываем 1 трубу с идентификатором 1 передатчика 0xAABBCCDD11, для приема данных
                                             // Открываем 2 трубу с идентификатором 2 передатчика 0xAABBCCDD22, для приема данных
  radio.startListening  ();                  // Включаем приемник, начинаем прослушивать открытые трубы
  //  radio.stopListening   ();
////////Вывод служебной информации
  tft.fillScreen(BLACK);
  tft.setCursor (8, 0);
  tft.setTextSize(1);
////////Начало инициализации SD карты
  Serial.println("Initial SD card");
  tft.println("Initial SD card");
  tft.setCursor (8, 10);
////////Инициализация карты
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("initial failed!");
    tft.fillRect ( 8 , 10 , 85 , 7 , RED);
    tft.setTextColor(BLACK);
    tft.println("Initial failed!");
    return;
  }
  tft.setTextColor(WHITE);
  Serial.println("initialization done");
  tft.println("Initialization done");
  delay (2000);
////////Считывание времени- даты и присвоение их переменным
  t = rtc.getTime();
  time_sec_prev = t.sec;
  time_day_prev = t.date;
////////Вывод даты принудительно, что б не ждать смены даты для индикации
  tft.setCursor (  180 , 0 );              // установка позиции курсора
  tft.fillRect ( 178 , 0 , 65 , 7 , GRAY); // очистка области вывода времени
  tft.setTextSize(1);
  tft.print(rtc.getDateStr());
////////Вывод названия объектов контроля
  tft.setTextSize(2);
  tft.setCursor (60, 25);
  tft.println (utf8rus("Лебёдки I"));
////////Создание файла лога и вывод результата попытки создания
  tft.setTextSize(1);
  tft.setCursor(130, 10); // если файл лога 2.txt создан, то будет продолжена запись в файл
  if (SD.exists (perv)) {
    //tft.setCursor(0, 90);
    tft.println(perv);
    Serial.println(perv);
  } else {
    myFile = SD.open(perv, FILE_WRITE);  // если файла  2.txt нет, то он будет создан
    myFile.close();
    tft.println(perv);
    Serial.println(perv);
  }  
}

void loop(void) {
////////Проверка существования запроса вывода лога в монитор СОМ- порта
  if (Serial.available() > 0) {
   
////////И если принят любой символ, то вывод лога в монитор порта
    File myFile = SD.open(perv);
    // if the file is available, write to it:
    if (myFile) {
      while (myFile.available()) {
        Serial.write(myFile.read());
      }
      myFile.close();
    }
    else {
      Serial.println("error opening .txt");
    }
  }
////////Считывание времени
  t = rtc.getTime();
  tft.setTextColor(WHITE);
////////Если время изменилось, то вывод новых показаний часов
  if ( time_sec_prev != t.sec) {
    tft.setCursor (  120 , 0 );     // установка позиции курсора
    tft.fillRect ( 118 , 0 , 50 , 7 , GRAY); // очистка области вывода времени
    tft.setTextSize(1);
    tft.print(rtc.getTimeStr());    // вывод показаний часов
    time_sec_prev = t.sec;
  }
////////Если дата изменилась, то вывод новой даты
  if ( time_day_prev != t.date) {
    tft.setCursor (  180 , 0 );     // установка позиции курсора
    tft.fillRect ( 178 , 0 , 65 , 7 , GRAY); // очистка области вывода даты
    tft.setTextSize(1);
    tft.print(rtc.getDateStr());    // вывод показаний даты
    time_day_prev = t.date;
  }
////////Если доступен радиоприём, то
  if (radio.available(&pipe)) {
////////проверка заполнения буфера приёма,
    radio.read(&data, sizeof(data));
////////если доступен нужный адрес передатчика, то
    if (pipe == 1) {
////////ждём синхронизирующую последовательность нулей для определения
//начала блока данных
      if ( data == 0000 ) {
        rc = 0;
      } else {
        rc ++;
      }
////////Запись значений счётчиков и расчёт их в 10 и 100-х долях часа
      if ( rc == 1 ) {
        leb_1 = data / 3600.0;
      }

      if ( rc == 2 ) {
        leb_2 = data / 3600.0;
      }

      if ( rc == 3 ) {
        leb_3 = data / 3600.0;
      }

      if ( rc == 4 ) {
        leb_4 = data / 3600.0;
      }
    }
  }
  r ++;
  k ++; // просто счётчик 
  //////// С определённой условием периодичностью обновление данных
  if ( r >= 6500) {
    tft.setTextSize(2);
    tft.fillRect ( 0 , 41 , 180 , 64 , GRAYD);
    Serial.println ("Lebedki I");
    tft.setCursor (0, 41);
    tft.println (leb_1);
    Serial.println (leb_1);
    tft.println (leb_2);
    Serial.println (leb_2);
    tft.println (leb_3);
    Serial.println (leb_3);
    tft.println (leb_4);
    Serial.println (leb_4);
    Serial.println (k);
    r = 0;
  }
////////Запись данных в лог на SD каждые 10 мин.
  if ((t.min % 10 == 0) && ( t.sec == 0)) {
    tft.setTextSize(1);
    tft.setCursor(200, 10);
    tft.setTextColor(BLACK);
////////Создание строки в формате .csv
    String dataString = String (rtc.getDateStr()) + ", "+(rtc.getTimeStr()) + ", " + (leb_1) + ", " + (leb_2)
                        + ", " + (leb_3) + ", " + (leb_4) + ", ";
////////Запись в файл и вывод результатов процесса записи
    myFile = SD.open(perv, FILE_WRITE); // если файла с именем "2.txt" - нет, то он будет создан.
    if (myFile) {
      myFile.println(dataString);
      myFile.close();
      tft.fillRect ( 198 , 8 , 42 , 10 , GREEN);
      tft.println("SD OK");
      Serial.println("SD OK");
      delay (900); // задержка, иначе записывает 13 одинаковых показаний, пока секунда не пройдёт
    } else {
      tft.fillRect ( 198 , 8 , 42 , 10 , RED);
      tft.println("SD ERR");
      Serial.println("SD ERR");
    }
  }
}

Программа перекодировки символов
/* Recode russian fonts from UTF-8 to Windows-1251 */

String utf8rus(String source)
{
  int i,k;
  String target;
  unsigned char n;
  char m[2] = { '0', '\0' };

  k = source.length(); i = 0;

  while (i < k) {
    n = source[i]; i++;

    if (n >= 0xC0) {
      switch (n) {
        case 0xD0: {
          n = source[i]; i++;
          if (n == 0x81) { n = 0xA8; break; }
          if (n >= 0x90 && n <= 0xBF) n = n + 0x30;//0x2F
          break;
        }
        case 0xD1: {
          n = source[i]; i++;
          if (n == 0x91) { n = 0xB8; break; }
          if (n >= 0x80 && n <= 0x8F) n = n + 0x70;//0x6F
          break;
        }
      }
    }
    m[0] = n; target = target + String(m);
  }
return target;
}

Программа перекодировки символов для вывода кириллицы библиотекой Adafruit_GFX помещается в одну папку с основной программой. Еще надо в Adafruit_GFX заменить файл glcdfont.с с другим шрифтом. Здесь библиотека с требуемой заменой. Подробнее о русификации легко ищется в интернете.

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

Первые элементы работают уже более полугода и пережили зиму. Последняя конструкция на 9 контролируемых агрегатов работает с 5 марта и по ней идет регистрация времени наработки уже официально.
Tags:
Hubs:
+15
Comments 14
Comments Comments 14

Articles