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

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Начало на данном сайте по ссылке.

Самым удобным для использования вариантом съёма информации о включении пускателя оказался вариант с оптопарой 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) {
    if (1 == Serial.read());
////////И если принята "1"- то вывод
    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 марта и по ней идет регистрация времени наработки уже официально.
Источник: https://habr.com/ru/post/451154/


Интересные статьи

Интересные статьи

Сегодня мы снова решили поделиться достижениями ведущих мегаполисов в организации жизни горожан. В прошлом посте речь шла об инфраструктуре умного транспорта, современных телекоммуник...
Библиотека pandas — это один из лучших инструментов для разведочного анализа данных. Но это не означает, что pandas — это универсальное средство, подходящее для решения любых задач. В частности, ...
Мой коллега Рафаэль Григорян eegdude недавно написал статью о том, зачем человечеству потребовалась ЭЭГ и какие значимые явления могут быть зарегистрированы в ней. Сегодня в продолжение темы нейр...
Есть вопросы, которые мы задавали либо пытались на них ответить: почему небо синее, сколько звезд на небосводе, кто сильнее — белая акула или косатка и т.д. А есть вопросы, которые мы не зада...
Ссылка на первую часть.      Глава 2. Марсианская мечта      Глава 3. Дух Империи Глава 2. Марсианская мечта     По небольшому холму на поверхности Марса, оставляя неглубокие следы на кра...