Na zakładzie zakupiono stanowiska monitorujące NEXST-M krajowej produkcji "Nexst Technologies". W celu wizualizacji pracy agregatów pompowych,
systemu pożarowego i alarmowego, obecności napięcia na rozrusznikach, temperatury w pomieszczeniu, poziomu awaryjnego wody. Serce NEXST-M stanowi ATMEGA 1280, co stwarza możliwości do stworzenia własnego zestawu dostosowanego do konkretnych potrzeb.
Postawiono zadanie stworzenia w minimalnym czasie i przy minimalnych kosztach całkowicie autonomicznego systemu lokalnej dyspozycji do konkretnych potrzeb. Podstawa – mikrokontroler. Opracowanie i produkcja są realizowane przez sam personel.
System ma działać bez zależności od sieci komórkowych, serwerów, internetu oraz systemu zezwolenia na korzystanie z zasobów radiowych, nie wykorzystując w pracy systemów kontroli i zarządzania komputerów ani maksymalnie okresowego użycia laptopów, bez dostępu do obiektów przez długi czas (6-9 miesięcy). Konfiguracja sieci ma strukturę radialną. Dane są zbierane w jednym punkcie, a następnie przesyłane do przetworzenia przez zwykłe kanały komunikacyjne lub w postaci twardej kopii.
System ma zapewniać:
- kontrolę pracy instalacji pompowych
- automatyzację technologiczną
- ochronę przed skutkami trybów awaryjnych
- sygnalizację o trybach awaryjnych
- liczenie czasu pracy
- liczenie objętości zużytej energii elektrycznej
- kontrolę temperatury urządzeń
- system pożarowo-ochronny
- okresowe zdalne zbieranie informacji
- nieznane wymagania w przyszłości
Warunki pracy:
- terytorium zasięgu 1 km².
- bezpośrednia widoczność między obiektami
- temperatura od +50 do -50 °C
- wilgotność do 100%
- biologicznie aktywne osady (pleśń, bakterie redukujące siarczany)
- wibracje, nie więcej niż maszyny klasy 1-2 według GOST ISO 10816-1-97
- otoczenie elektromagnetyczne – przyłączenie silników elektrycznych za pomocą styków KТ 6053, aparatury miękkiego rozruchu RVS-DN, aparatury PID regulacji SIEMENS MICROMASTER, emisje w zakresie ISM i GSM zgodnie z wymaganiami dotyczącymi tych urządzeń, ręczne spawanie łukowe na obiekcie
- przekroczenie napięcia w sieci, krótkotrwałe przerwy w zasilaniu, przepięcia podczas burzy, nierównowaga fazowa przy przerwaniu przewodu WN w sieciach dystrybucyjnych 6-10 kV.
Pomimo tak rygorystycznych wymagań, realizacja jest stosunkowo prosta przy etapowym podejściu do problemu.
Wszystko to sprawiło, że jako 'mózg' projektu wybrano płytkę 'Arduino Nano 3.0'. Płytka od 'Robotdyn' ma kontroler ATMEGA 328 i niezbędny stabilizator napięcia 3,3V na
prąd 800 mA i konwerter na CH340G UART-USB.
Na początku stworzono liczniki pracy jako najważniejsze. Wcześniej stosowane przemysłowe liczniki oparte na układach PIC z beztransformatorowym schematem zasilania uległy awarii przez skoki napięcia w ciągu roku pracy. Tylko te, które były podłączone za pomocą samodzielnie wykonanych zasilaczy 5V, pozostały całe. Aby przyspieszyć montaż i umożliwić uniwersalne podłączenie, sygnał o stanie urządzeń jest pobierany z zacisków aparatów komutacyjnych, tzn. rejestracja obecności 1. fazy napięcia przy trójfazowym zasilaniu 380V. Do współpracy z kontrolerem używane jest przekaźnikowe pośrednie z cewką 220V lub optopara złożona z diody LED i fotorezystora GL5516 lub optopara PC817. Wszystkie warianty zostały przetestowane w działaniu. Diody LED zasilane są prostowanym napięciem z ograniczeniem prądu za pomocą dwóch kondensatorów SVV22 ocenionych na napięcie 630V, połączonych szeregowo dla bezpieczeństwa przy przypadkowym sprawdzaniu obwodów megomierzem.
Odczytywanie czasu pracy za pomocą wyświetlacza LCD ST7735S, przesyłanie danych w czasie rzeczywistym przez radiomodul E01-ML01DP05 na częstotliwości 2,4 MHz. Urządzenie to zawiera chip nRF24L01+ oraz wzmacniacz odbioru i nadawania RFX2401C,
moc wyjściowa do 100 mW. Anteny spiralne, obliczone na odpowiedni zakres w online-kalkulatorze Wybór typu anten są związane z eliminacją przyjmowania jednorazowo odbitych fal od otaczających konstrukcji metalowych. Elementy anteny są drukowane na drukarce 3D. Aktualny stan liczników jest zapisywany w EEPROM samego kontrolera i w przypadku nieoczekiwanego wyłączenia zasilania jest przywracany. Czasowe interwały dla licznika zapewnia układ RTC DS3231 w postaci modułu z baterią zapasową. W zasilaczu stosowane są 3 moduły, mianowicie impulsowe źródło 220/5V HLK-PM01 600mA, przetwornik z 1-5V na 5V i — kontroler akumulatora posiadający ochrony przed zwarciem, nadmiernym rozładowaniem i przeładowaniem. Wszystkie podzespoły zakupione zostały na stronie Aliexpress.
Płytka prototypowa
Licznik 4-kanałowy. Na wejściach znajdują się filtry LC w celu ochrony przed zakłóceniami w linii komunikacyjnej z użyciem skrętki. Dane o stanie obiektów kontrolnych są nieprzerwanie odczytywane co 1 sekundę i wyświetlane kolorami na LCD. Aktualizacja odczytów i zapis do pamięci nieulotnej odbywa się co 36 sekund. 36 sekund - to 1/100 godziny, w takim właśnie formacie wymagane są dane. Co 12 sekund następuje przesyłanie informacji o liczbie sekund pracy dla każdego agregatu kontrolnego. Pamięć EEPROM ma ograniczoną liczbę cykli zapisu - kasowania, według producenta, 100000 razy. Najgorszy scenariusz to ciągłe aktualizowanie przynajmniej jednej komórki. Wielkość 1. licznika to 4 bajty, to liczba w formacie long, 4 liczniki, łącznie 16 bajtów zajmuje jeden zapis. Długość pamięci układu to 1024 bajty, po 64 zapisach 4 liczników zapis zacznie się od nowa. W bibliotece EEPROM metoda EEPROM.put nie wykonuje zapisu, jeśli wartość komórki i zapisywana informacja się zgadzają, nie będzie degradacji komórek. W rezultacie czas gwarantowanej pracy pamięci wyniesie ponad 7 lat. Czas możliwej, ale niegwarantowanej pracy może być znacznie dłuższy.
Schemat ideowy
Program w Arduino IDE//12 328 байт (38%)
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#include <EEPROM.h>
#include <Wire.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(9, 10); // obiekt radio do pracy z biblioteką RF24,
// и номера выводов nRF24L01+ (CE, CSN)
#include <DS3231.h>
DS3231 rtc(SDA, SCL);
Czas t;
//#define TFT_CS 10
#define TFT_CS 8
#define TFT_RST -1 // you can also connect this to the Arduino reset
// in which case, set this #define pin to -1!
//#define TFT_DC 9 // DC=RS=A0- варианты обозначений вывода выбора регистра команд или данных.
#define TFT_DC 3
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
// Option 2: use any pins but a little slower!
#define TFT_SCLK 13 // set these to be whatever pins you like!
#define TFT_MOSI 11 // set these to be whatever pins you like!
//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
#include <avr/wdt.h>
byte shift = 52;
byte pinState;
unsigned long pump[4]; // tablica z 4 wartościami liczników sekund
float m = 3600.0;
unsigned int address = 0;
int rc; // zmienna dla liczników
unsigned long sumprim = 0;
unsigned long sumsec = 0;
byte i = 0;
byte k = 34;
unsigned int z = 0;
byte b = B00000001;
byte pumrcounter [4]; // tablica do przechowywania stanów obiektów, 1 - wyłączony, 0 - włączony.
int start = 0; //
void setup() {
rtc.begin();
radio.begin(); // Inicjujemy pracę nRF24L01+
radio.setChannel(120); // kanał transmisji danych (od 0 do 127).
radio.setDataRate (RF24_250KBPS); // prędkość transmisji danych (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS).
radio.setPALevel (RF24_PA_MAX); // moc nadajnika (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm,
// RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm)
radio.openWritingPipe (0xAABBCCDD11LL); // Otwórz rurę z identyfikatorem do transmisji danych
// Для установки времени- раскомментировать нужные строки
//rtc.setDOW(1); // День недели
//rtc.setTime(21, 20, 0); // Время, в формате 24 часа.
//rtc.setDate(29, 10, 2018); // Дата, 29 октября 2018г.
tft.initR(INITR_BLACKTAB); // inicjalizuj chip ST7735S, czarny tab
// Use this initializer (uncomment) if you’re using a 1.44" TFT
//tft.initR(INITR_144GREENTAB); // initialize a ST7735S chip, RED rcB tab
tft.setTextWrap(false); // pozwól, aby tekst wychodził poza prawą krawędź
tft.setRotation(2); // dla PCB CZERNEJ i CZERWONEJ tft.setRotation(0) lub nie.
tft.fillScreen(ST7735_BLACK); // czyszczenie ekranu
DDRD = DDRD | B00000000;
PORTD = PORTD | B11110000; // programowe podciąganie działa, wysoki poziom -
// контролируемые объекты «не работают», во все 4 старших порта D записана «1», не идет счет.
for (rc = 0; rc < 4; rc++)
{
tft.setCursor(3, rc * 10 + shift); // wyświetlanie numerów pozycji obiektów kontrolnych
tft.print(rc + 1);
}
tft.setCursor(12, 0); // wyświetlanie 3 wierszy tekstu
tft.println("DEVELOPERS & BUILD"); // dla chwalenia się
tft.setCursor(24, 10); // lub złośliwy copyright
tft.print("DEVELOPER M.M.");
tft.setCursor(28, 20);
tft.print("BUILD-ER D.D.");
//восстановление данных/////////////////////////////////////////////////////////
for (z = 0; z < 1023; z += 16) { // Iteruje przez wszystkie komórki EEPROM
//и записывает в массив из 4-х переменных pump, по 4 байта каждый счетчик, т.к.
// переменная беззнаковая лонг. Счетчиков 4, одна запись всех 4-х занимает 16 байт.
EEPROM.get(z, pump[0]); // tak, bez pętli for, mniej objętości
EEPROM.get(z + 4, pump[1]);
EEPROM.get(z + 8, pump[2]);
EEPROM.get(z + 12, pump[3]);
// присвоение нового очередного значения суммы 4-x счётчиков
sumprim = (pump[0] + pump[1] + pump[2] + pump[3]);
// сравнивается новое значение суммы 4-х счетчиков в переменной sumprim с предыдущим значением в переменной
// sumsec и если предыдущая сумма меньше или равна новой сумме, присваивается новое большее или равное
// sumsec значение.
if (sumsec <= sumprim) {
sumsec = sumprim; //
//и присваивается переменной address текущее значение z, z- это адрес начала блока в 16 байт из 4-х значений
// счетчиков, записанных в одно и то-же время ( т.к. при опросе порта записываются одновременно все его 8 бит,
// в том числе наши нужные старшие 4 бита порта D).
address = z;
}
}
// еще раз обращение к памяти еепром по адресу начала блока в 16 байт из 4-х значений счетчиков записанных
// последними, т.е. значения перед выключением или перезагрузкой по причине зависания. Запись последних
// значений счетчиков в массив из 4-х переменных pump.
EEPROM.get(address, pump[0]);
EEPROM.get(address + 4, pump[1]);
EEPROM.get(address + 8, pump[2]);
EEPROM.get(address + 12, pump[3]);
address += 16; // zwiększ adres do zapisu następnego bloku bez nadpisywania danych ostatniego zapisu
// конец восстановления данных////////////////////////////////////////////////////////////////
attachInterrupt(0, count, RISING); // pin D2, zezwolenie na działanie przerwania, co sekundę przychodzą
// импульсы от RTC DS3231 с выхода SQW
wdt_enable(WDTO_8S); // uruchomienie timera watchdog, restartuje kontroler w przypadku zawieszenia, czas,
// за которое надо подать команду сброса таймера wdt_reset( и избежать перезагрузки при нормальной работе- 8 сек.
// для тестов не рекомендуется устанавливать значение менее 8 сек.В данном случае сброс таймера происходит в пре-
// рывании, а оно каждую секунду.
}
void loop() {
// пустой цикл, здесь будет контроль за неполнофазным режимом работы эл.двигателя
}
void count() {
tft.setTextColor(ST7735_WHITE); // ustawienie koloru czcionki
t = rtc.getTime(); // odczyt czasu
tft.setCursor(5, 120); // ustawienie pozycji kursora
tft.fillRect(5, 120, 50, 7, ST7735_BLACK); // czyszczenie obszaru wyjścia czasu
tft.print(rtc.getTimeStr()); // wyświetlanie wskazań zegara
wdt_reset(); // resetowanie timera watchdog co cykl, tzn. co sekundę
for (rc = 0; rc < 4; rc++) // początek pętli sprawdzania stanu wejść
// битов порта предыдущему считанному состоянию битов порта D
{
pinState = (PIND >> 4) & (b << rc);
if (pumrcounter[rc] != pinState) { // jeśli się nie zgadza, to
pumrcounter[rc] = pinState; // przypisanie zmiennej nowego stanu bitu portu 1/0
}
// индикация состояния объектов контроля цветом
// BLUE- это небольшой глюк имеющегося экрана ( или библиотеки? ), перепутаны RGB и BGR.
if (pinState == (b << rc)) {
tft.fillRect(15, ((rc * 10 + shift)), 7, 7, ST7735_BLUE); // dla liczenia na niskim poziomie zamień GREEN na BLUE
} else {
tft.fillRect(15, ((rc * 10 + shift)), 7, 7, ST7735_GREEN); // dla liczenia na niskim poziomie zamień BLUE na GREEN
pump[rc] += 1; // dodaj 1 sekundę do licznika czasu pracy
}
}
k++;
if (k == 36) {
k = 0;
tft.fillRect(30, shift, 97, 40, ST7735_BLACK); // czyszczenie obszaru wyjścia czasu na pracy
tft.fillRect ( 60, 120, 73, 7, ST7735_BLACK); // i daty
tft.setCursor ( 60, 120 ); // ustawienie pozycji kursora
tft.print(rtc.getDateStr()); // wyświetlanie daty na ekranie LCD
for (rc = 0; rc < 4; rc ++) //wyświetlanie odczytów w całości, dziesiątych i
{
tft.setCursor ( 30, rc * 10 + shift );// setny część godziny z przesunięciem na ekranie w dół o 10 pikseli
tft.println(pump [rc] / m);
}
// запись «сырых» значений наработки (в секундах)в EEPROM //////////////////////////////
for (rc = 0; rc < 4; rc ++)
{
EEPROM.put(address, pump [rc]);
address += sizeof(float); // inkrementacja zmiennej adresu zapisu
}
}
// отправляем данные по радиоканалу из data указывая сколько байт надо отправить.
if ((k == 6 ) || (k == 18 ) || (k == 30 )) {
unsigned long data;
radio.write(&start, sizeof(start));
for ( i = 0; i < 4; i ++) {
data = pump [i ];
radio.write( &data, sizeof( data));
}
}
}
Niewielkie uwagi na koniec. Licznik działa przy niskim poziomie logicznym na wejściach.
Rezystory podciągające R2-R5 36 kΩ dla wariantu z fotorezystorami GL5516. W przypadku optoizolatora z fototranzystorem i przekaźnika, użyć 4,7-5,1 kΩ. Bootloader Arduino Nano v3.0 został wymieniony na Arduino Uno za pomocą programatora TL866A dla poprawnej pracy zegara stróżującego. Fuse'y poprawione dla pracy przy napięciu powyżej 4,3 V. Zewnętrzny obwód resetu R6 C3 nie był używany. W przykładzie programu częstotliwość nadajnika nie odpowiada nielicencjonowanemu zakresowi, zakres 2,4 MHz jest ograniczony częstotliwościami 2400.0—2483.5 MHz.
Zakres nadajnika E01-ML01DP05 wynosi 2400-2525 MHz. Szerokość pasma jednego kanału wynosi 1 MHz, przy ustawieniu prędkości jako „RF24_2MBPS” zajmie wskazany kanał radio.setChannel(120) i następny, tzn. pasmo wyniesie 2 MHz.
Źródło: habr.com
