Skocz do zawartości
szczepulek

Arduino Mega2560 + Ethernet + DS18B20 + 7-seg. moduł LED TM1637 - Pomiar temperatury i wysyłanie do bazy SQL

Pomocna odpowiedź

@szczepulek nie chodziło mi o obrażanie się, ani kogokolwiek innego. Po prostu pojawiła się negatywna opinia nie o samej bibliotece, ale osobie - czyli autorze tej biblioteki mówiąc dokładniej. Moim zdaniem powinniśmy takich opinii unikać. Można skomentować czyjś kod, ale pisanie o kimś że jest kiepski w tym co robi jest co najmniej nieeleganckie. Co więcej wyrażając takie opinie o innych powinniśmy być świadomi, że to może sprowokować kogoś do oceny nas - i to niekoniecznie zgodnej z własną samooceną.

  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

Niestety mam problem jak ugryźć MENU, ale na 4 cyfrowym wyświetlaczu LCD. Nie znalazłem w internetach czegoś takiego, na LCD tego mnóstwo.

exit , dn, up , ok   --klawisze podlaczone na jakichs tam pinach..

domyslnie wyswietlana temperatura

[20*5]

klik 'ok' >>

- [AL:30]

klik 'up'  do drugiej opcji

- [L 07]

klik 'up'/ 'dn' przenosi ponownie do [AL:30]   // 30 wartość pobrana z eeprom(alarmHigh,0)

Będąc na [L 07]  // 07 pobrane z eeprom(liniaNr,1)

klik ok >> edycja numeru linii 'up' +1,' dn' -1

podczas wejscia do menu, po 5 sek nieaktywnosci powrot do wyswietlania temperatury.

klik 'ok' >> zapis do eeprom (liniaNr,1)

tak samo na pozycji AL edycja +/- 1. I zapis.

po kliknieciu 'exit'

 

PS.: tak tak, wiem.. wykorzystam już millis() a delay w odstawkę. Przynajmniej te w moim kodzie nie bibliotekach.

Edytowano przez szczepulek

Udostępnij ten post


Link to post
Share on other sites
3 godziny temu, szczepulek napisał:

za każdym razem jak spoglądam na kod, widzę nieścisłości.. i rzeczy które można lepiej sprawniej zrobić,

Za każdym razem gdy zajrzysz do kodu widzisz, ze można coś poprawić, nawet jak to miganie led, bo np można dodać obsługę watchodoga. Innym razem obsługę wyjątków (w AVR to chyba tylko przerwanie od watchdoga). Później zauważysz, ze parę bajtów zaoszczędzisz jak zadeklarujesz void main() a nie int main(). Tak można poprawiać i udoskonalać w nieskończoność. Niestety, poprawki mają swoje konsekwencje jak ponowne testy produktu a testowanie ma swoją, najczęściej wysoka (mówimy o dobrym testowaniu) cenę. Z tego powodu, wiele projektów nie jest zmieniane na ARM tylko nadal robią to AVR, bo produkt jest pewny a konsekwencje błędu mogą być bardzo dotkliwe. Na ile dotkliwe, to wystarczy zapoznać się z protokołem SAS i uświadomić do czego jest używany.

Udostępnij ten post


Link to post
Share on other sites

Menu dla 7 segmentowego wyświetlacza.. a no właśnie, nie wiem skąd wcześniej brało mi się 8 segmentowy 😅😅

może ze względu na kropkę występującą DP, ale mniejsza z tym, i tak wiemy o co chodzi..

 

W poszukiwaniu jakiegoś przykładu na tych wyświetlaczach, no ne znalazłem takowego.. (przykładu)

  Podjąłem się próby przekształcenia bardzo uproszczonego Menu dla LCD pod moje potrzeby..

i tak oto to wygląda:

#include <TM1637Display.h>

/* ! ! ! ! ! ! ! ! ! !  ! !!  !! ! ! ! !  !
 * UWAGA MODYFIKACJA KODU Z LCD NA LED 7 segmentowy 4-digit
 * 
 *  ! ! ! !  ! !! ! !  ! !  ! ! !!  ! 
 * 
*  kod oryginalny https://github.com/FritzenLab/LCD-Screen-Menu-System/tree/master/LCD-Screen-Menu
 * 
 * Made by Clovis Fritzen in 05/06/2017
 * http://www.FritzenMaker.com
 * http://www.FritzenLab.com.br
*/

#define CLK1 5 //wyswietlacz nr1 8segm.4-cz 
#define DIO1 6 //wyswietlacz nr1 8segm.4-cz


int WhichScreen =1;   // This variable stores the current Screen number
boolean hasChanged = true;
const int buttonPin = 37;    // the number of the pushbutton pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

TM1637Display display_1(CLK1, DIO1); // ustawienia wyjsc dla wyswietlacza na tm1637

uint8_t wysw1LED[] = { 0x00, 0x00, 0x00, 0x00 };  //Dla LEDDispl4digit

//wyswietlenie segmentow dla AL
const uint8_t disp_alarm[] = {
  SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G ,           // A
  SEG_D | SEG_E | SEG_F   // L
};

//wyswietlenie segmentow dla L
const uint8_t disp_linia[] = {
  SEG_D | SEG_E | SEG_F ,// L
   0  // O
};  


void setup()
{
 // lcd.init();// initialize the lcd 0x20 lub 0x38??
//  lcd.backlight();
  pinMode(buttonPin, INPUT_PULLUP);
  display_1.setBrightness(0x0a); //LED7Seg 
   Serial.begin(9600);
   WhichScreen = 0;  //aby przy starcie zaczynało na pierwszej opcji menu
}
void loop()
{

  if (hasChanged == true) {
    
  switch(WhichScreen) {
    case 1:
    {
      firstScreen();
    }
      break;
    
    case 2:
      {
        secondScreen();
      }
      break;
    
    case 3:
      {
        thirdScreen();
      }
      break;
    
   /* Dla wiekszej ilosci wyswietlania pozycji menu
    *  
    case 4:
      {
        fourthScreen();
      }
      break;
    
    case 5:
      {
        fifthScreen();
      }
      break;
    
    case 6:
      {
        sixthScreen();
      }
      break; 
      */
  
    case 0:  //konczacy zapis menu
      {
        
      }
      break;
    }
    
}

    //-------------------------------
    // BEGIN of the switch debouncing code
    int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        hasChanged = true;
        WhichScreen++;
        
        
      }
    } else {
      hasChanged = false;
    }
  }
  lastButtonState = reading;
  // END of the switch Debouncing code
  // --------------------------------------
  if (WhichScreen > 3){
    WhichScreen = 1;
  }
}

void firstScreen()
  {
    display_1.clear();
   Serial.println("glowny ekran");  // test w serial
   display_1.showNumberDec(99, false, 2, 2);
  }
  
void secondScreen()
  {
  display_1.clear();  //konieczne by nie nakladaly sie na siebie znaki/liczby z poprzedniego menu
 int alarmHigh = 30;
 display_1.setSegments(disp_alarm, 2, 0);
 display_1.showNumberDec(alarmHigh, false, 2, 2);
  Serial.print("alarm:");  // test w serial
  Serial.println(alarmHigh);
  }
  
void thirdScreen()
  {
   display_1.clear(); 
  int liniaNr = 7;
  display_1.showNumberDecEx(liniaNr,0, true);
  display_1.setSegments(disp_linia, 2, 0);
  
   Serial.print("linia nr:");  // test w serial
   Serial.println(liniaNr);
  }
/*

dla większej ilosci przejsc miedzy wyswietlanymi informacjami, ponizej rozpiska dla wyswietlacza LCD !!!
  
 void fourthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("This is screen 4");
    lcd.setCursor(0,1);
    lcd.print("Just press btn");
  }
void fifthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("   Fifth screen");
    lcd.setCursor(0,1);
    lcd.print("i2C LCD screen");
  }
void sixthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("THE last screen");
    lcd.setCursor(0,1);
    lcd.print("  Sixth and last");
  }
  */

Nie próbowałem jeszcze z integracją do mojego projektu.

Button podpięty z: Pinem 37 - GND

Udostępnij ten post


Link to post
Share on other sites

Aktualizacja powyższego kodu, menu inicjowane osobnym klawiszem, i na nim przełączanie pomiędzy ustawieniami a wyświetlaniem na bieżąco jakichs tam parametrów, w tym wypadku do testu wartość na wejściu analogowym.

#include <TM1637Display.h>

/* ! ! ! ! ! ! ! ! ! !  ! !!  !! ! ! ! !  !
 * UWAGA MODYFIKACJA KODU Z LCD NA LED 7 segmentowy 4-digit
 * 
 *  ! ! ! !  ! !! ! !  ! !  ! ! !!  ! 
 * 
 * This code create a MENU structure on a 16x2 LCD screen.
 * Six (6) different screens are implemented, and you can travel
 * thru them by pressing a button on Arduino PIN 4. Each press
 * of the button advances one (1) screen. 
 * 
 * Made by Clovis Fritzen in 05/06/2017
 * http://www.FritzenMaker.com
 * http://www.FritzenLab.com.br
*/

#define CLK1 5 //wyswietlacz nr1 8segm.4-cz 
#define DIO1 6 //wyswietlacz nr1 8segm.4-cz


int WhichScreen =1;   // This variable stores the current Screen number
boolean hasChanged = true;
boolean pokazMenu = 0;
const int buttonPin = 37;    // the number of the pushbutton pin
const int buttonMenu = 33; // wywolanie menu
int buttonState; // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 45;    // the debounce time; increase if the output flickers


int value; //testowe

TM1637Display display_1(CLK1, DIO1); // ustawienia wyjsc dla wyswietlacza na tm1637

uint8_t wysw1LED[] = { 0x00, 0x00, 0x00, 0x00 };  //Dla LEDDispl4digit

//wyswietlenie segmentow dla AL
const uint8_t disp_alarm[] = {
  SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G ,           // A
  SEG_D | SEG_E | SEG_F   // L
};

//wyswietlenie segmentow dla L
const uint8_t disp_linia[] = {
  SEG_D | SEG_E | SEG_F ,// L
   0  // O
};  

const uint8_t disp_set[] = {
  SEG_A | SEG_C | SEG_D | SEG_F | SEG_G ,// S
  SEG_A | SEG_C | SEG_E | SEG_F | SEG_G , // E
  SEG_D | SEG_E | SEG_F | SEG_G
};  

int test[2];

void setup()
{
 // lcd.init();// initialize the lcd 0x20 lub 0x38??
//  lcd.backlight();
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(buttonMenu, INPUT_PULLUP);
  display_1.setBrightness(0x0a); //LED7Seg 
   Serial.begin(9600);
   WhichScreen = 0;  //aby przy starcie zaczynało na pierwszej opcji menu
}
void loop()
{
  
    int value = analogRead(2);  // pomiar na analogowym wejsciu losowej
  Serial.print(F("Wejscie analogowe 2 ma wartosc: ")); // to na nic tu nie potrzebne
  Serial.println(value);
    test[1] = value; //zapis do tablicy potrzebny aby w CASE mozna bylo odczytac wartosc, po wrzuceniu do warunku na poczatku funkcji loop nie porzebne.
Serial.println(test[1]);

if (digitalRead(33) == LOW) // sprawdza czy na pinie 33 stan LOW niski, jesli tak to ..
{
  delay(250);
  pokazMenu = !pokazMenu; // ..zmienia prawde logiczna w zmiennej typu boolean na przeciwna, czyli 1 na 0 lub 0 na 1
}

  
if (pokazMenu == 0) // jesli (domyslnie na starcie) mamy 0 to wykonaj program, wlasciwy..czy tez ten ktory ma sie glownie wykonywac
{  
  display_1.showNumberDec(test[1]); //info domslna strona  a raczej wyswietlacz, z w tym przypadku do testow wartoscia napiecia na analogowym pinie 
  
  hasChanged = true; // ustawiam na true, aby po wlaczeniu na menu pojawila sie na wyswietlaczu strona ustawien, bez tego zostaje zamrozony wynik ostatniego pomiaru z wejscia analogowego
  
}

else // jesli zmienna pokazMenu ma wartosc inna niz zero.. w tym wypadku tylko moze byc to 1 wykonaj.. wyswietlenie menu

{
 
 if (hasChanged == true) 
 {   
  switch(WhichScreen) {
    case 1:
    {
      firstScreen();
    }
      break;
    
    case 2:
      {
        secondScreen();
      }
      break;
    
    case 3:
      {
        thirdScreen();
      }
      break;
    
   /* Dla wiekszej ilosci wyswietlania pozycji menu
    *  
    case 4:
      {
        fourthScreen();
      }
      break;
    
    case 5:
      {
        fifthScreen();
      }
      break;
    
    case 6:
      {
        sixthScreen();
      }
      break; 
      */
  
    case 0:  //konczacy zapis menu
      {
        
      }
      break;
    }
    
}

    //-------------------------------
    // BEGIN of the switch debouncing code
    int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        hasChanged = true;
        WhichScreen++;
        
        
      }
    } else {
      hasChanged = false;
    }
  }
  lastButtonState = reading;
  // END of the switch Debouncing code
  // --------------------------------------
  if (WhichScreen > 3){
    WhichScreen = 1;
  }
}

}

void firstScreen()  // pierwsza strona opcji
  {

    display_1.clear();
   Serial.println("glowny ekran");  // test w serial
   display_1.showNumberDec(1246);
   delete []test;
   
  
  }
  
void secondScreen() // druga str opcji itd itp
  {
  display_1.clear();  //konieczne by nie nakladaly sie na siebie znaki/liczby z poprzedniego menu
 int alarmHigh = 30;
 display_1.setSegments(disp_alarm, 2, 0);
 display_1.showNumberDec(alarmHigh, false, 2, 2);
  Serial.print("alarm:");  // test w serial
  Serial.println(alarmHigh);
  }
  
void thirdScreen()
  {
   display_1.clear(); 
  int liniaNr = 7;
  display_1.showNumberDecEx(liniaNr,0, true);
  display_1.setSegments(disp_linia, 2, 0);
  
   Serial.print("linia nr:");  // test w serial
   Serial.println(liniaNr);
  }
/*

dla większej ilosci przejsc miedzy wyswietlanymi informacjami, ponizej rozpiska dla wyswietlacza LCD !!!
  
 void fourthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("This is screen 4");
    lcd.setCursor(0,1);
    lcd.print("Just press btn");
  }
void fifthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("   Fifth screen");
    lcd.setCursor(0,1);
    lcd.print("i2C LCD screen");
  }
void sixthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("THE last screen");
    lcd.setCursor(0,1);
    lcd.print("  Sixth and last");
  }
  */

 

Udostępnij ten post


Link to post
Share on other sites

od ostatniego czasu udzielania sie w tym temacie spoooro sie zmieniło w kodzie i działaniu programu, na plus oczywiście,

@RFM przyjacielu, mówiłeś że te 43 ms na wyświetlacze to bardzo dużo, masz rację, zauważyłem to kiedy dodałem kilka warunków do programu, i menu przedewszystkim, to jak reagowały klawisze.. a raczej nie reagowały 🙂

Świetnie było widać  lagi kiedy w tle są wysyłane na serialu dane, a główna strona czy raczej pętla odpowiedzialna za wyświetlanie 2 temperatur była w użyciu (pokazMenu=0);

Serial monitor wyrzucał nieregularnie linijki , zauważalne skokowe wyświetlanie podglądu danych.

Do myślenia dało mi dlaczego po wyświetleniu menu nie ma tego efektu a dane w serial monitorze szaleją 😄

jedyny wniosek, wyświetlanie menu jest odświeżane przy zmianie naciśnięciu jakiegoś klawisza.

    Kilka postów wstecz wspomniałeś o użyciu millis() i co jakiś czas odpytywać temperaturę, zaświtało mi w głowie, a co jak by tak co jakiś czas wyrzucać komendę Display..

Wrzuciłem to w warunek z millis() i BOMBA 💥

Wszystko odżyło, klawisze lepiej reagują, i serial.write/ serial.print działają płynnie.

Przykładowa wstawka

      wysw2LED[0] = display_2.encodeDigit(airoutCalkow/1000%10); //wyswietla cyfre dziesiatek z pomiaru cz.1 na wyswietlaczu pierwszym
      wysw2LED[1] = display_2.encodeDigit(airoutCalkow/100%10); //wyswietla cyfre jednosci z pomiaru cz.1 na wyswietlaczu pierwszym
      wysw2LED[2] = (SEG_A | SEG_B | SEG_F | SEG_G); // znak stopni zamiast kropki ktore brak w wyswietlaczu ktory posiadam
      wysw2LED[3] = display_2.encodeDigit(airoutCalkow/10%10); //pierwsza cyfra czesci dziesietnych

//      display_2.setSegments(wysw2LED); // wyswietlenie  temperatury na pierwszym wyswietlaczu  TO WŁAŚNIE LAGUJE TA LINIA

/* po wrzuceniu tej linii kodu jak ponizej ,cały program pędzi jak Passaciak TDI na 4000obr/min z dwiema turbinami */

      if (millis() - time4 >=100)
    {
      display_2.setSegments(wysw2LED); // wyswietlenie  temperatury na pierwszym wyswietlaczu
      time4 = millis();
    }
    

 

Udostępnij ten post


Link to post
Share on other sites

Wyciskaj ze staruszka AVR ile możesz. Ma ograniczenia, czasem można je akceptować, czasem nie. Najczęściej nie można akceptować Arduinowych "bibliotek". Nie jestem jakimś tam supermenem w pisaniu kodu, ale jak widzę te Arduinowe twory (potwory) t myślę, że Halloween jest codziennie.

Nie to, ze jestem przeciwnikiem AVR. Mają swoją niszę (kiedyś były super, bo ARM były zarezerwowane dla nielicznych) teraz, cóż, przeważnie taniej kupisz 100 razy lepszy ARMN za 2 razy mniejszą kasę (Mega2560).

AVR jest dobry na start (jak kiedyś z uC 8051, z CPU to Z-80), ale czasy się zmieniają. Do CV AVR to chyba sobie nie wpiszesz ? Jak myślisz, AVR to "atut" gdy szukasz pracy?

Udostępnij ten post


Link to post
Share on other sites

Na obecna chwilę poprzez odczyt millis na poczatku i na końcu loop obliczyłem średnią 28ms. Powiem tak, dla mnie to spory sukces przeskoczyć z tych 1568 ms na 118 a teraz do tych 30 ms. 

Wiem że da się to jeszcze przyspieszyć ale jak na bibliotekach standardowych myślę całkiem nieźle. Wyświetlacze odwiedzane co 125ms. 

Pewnie jeszcze pogrzebie i zejdę tych kilka ms niżej.

Co do programu na obecną chwilę:

  • Przyspieszenie interfejsu 
  • Wyświetlanie 2 wartości temperatur 
  • Dwa termometry ds18b20 obsługiwane bez potrzeby wpisywania ręcznie adresów
  • Menu wyświetlane na LED 4 digits 7 segm. Tm1637
  • Menu obsługiwane 4 przyciskami, Menu(next), Up/dodaj, Down/ujmij, OK/Zapisz.
  • Podczas edycji miga kontrolka(LED) o konieczności zapisania parametru nowego (porównanie do zawartości EEPROM.
  • Przy braku aktywności w Menu po 20 sek powrót do wyświetlania temperatur, jeśli parametru zmieniono a nie zapisano -powrót do ustawień odczytanych z eeprom.
  • Jeśli nie zapiszemy parametrów i przeskoczymy całe Menu ..to jak wyżej.
  • Sprawdzenie na bierząco czy nie przekroczono max temp w przypadku przekroczenia - sygnał na przekaźnik.
  • Możliwość wybrania Alarmu dla jednego z czujników z poziomu Menu.
  • Wybranie linii /ID dla tego zestawu monitorującego.
  • Obsługa pamięci eeprom (opcje update dla oszczędzania ilości zapisów,  porósnania wyświetlanych informacji z zawartością pamięci. W przypadku wgrania na nową płytkę programu przy pierwszym uruchomieniu nadanie wartości domyślnych w pamięci.
  • Wysyłanie przez Serial1 (znaki kontrolne początek i koniec przesyłanych danych. Na 11 znakach wysłane temp1 i temp2. Stan ALarmu. Nr Linii/id)
  • Wysyłanie co około 28-30ms.
  •  

Udostępnij ten post


Link to post
Share on other sites
17 minut temu, szczepulek napisał:

Powiem tak, dla mnie to spory sukces przeskoczyć z tych 1568 ms na 118 a teraz do tych 30 ms. 

Sukces ogromny. Uczysz się, poznajesz słabe punkty AVR, niedługo zaczniesz pisać soft na ARM. Paradoksalnie, na ARM łatwiej i szybciej pisze się soft niż na AVR a przy okazji są przeważnie tańsze niż AVR, czy tego chce @niveasoft tudzież (fajne, dosyć egzotyczne w dzisiejszych czasach słowo) Mirek K. (M36 - te 36 to chyba nr ulicy, nie wiek), czy nie.

Jak chcesz zajść poniżej tych 30 ms, co pewnie jest już bardziej sztuka dla sztuki, chyba, że odbierasz dane po UART z prędkością 921600 ale nawet 115200 może być problemem. Jeden bajt przy 115200 jest przesyłany w ok 87us. Arduino ma bufor 64 bajty (ESP 128). Łatwo policzyć, że w 30ms może być przysłane prawie 350 bajtów! Można zwiększyć bufor ale...już to kiedyś pisałem. Coś za  za coś.

 

Na koniec mojej wypowiedzi chciałbym zachęcić Cię do ARM. Dlaczego?

Używam ARM bo:

- ARM przeważnie są tańsze niż AVR o podobnym wyposażeniu oferując zdecydowanie większe możliwości (DMA) i prędkość działania.
- ARM, przy tym samym zegarze jest ok 7 razy szybszy od AVR, a maksymalne częstotliwości taktowania zaczynają się od 24MHz a kończą na 650 (w przypadku rodziny STM32.
- W przeważającej większości mają więcej pamięci RAM i można robić duże bufory nadawcze dla UART, I2c, SPI, USB.
- Maja bogatsze wyposażenie (liczba USART/UART, I2C, SPI, timerów) i większe możliwości tychże peryferii. 12 UART w STM32 nie jest problemem, AVR max 4. Można dołożyć np SC16IS7xx ale 1 UART to ok 10zł, 2 ok 19zł).
- Mają DMA (AVR ATmega/tiny nigdy o czymś takim nie słyszały).
- Wiele ARM ma USB, w AVR to rzadkość a USB jest teraz pewnym standardem.

- Sprzętowe sterowanie przepływem i kierunkiem transmisji (RS485) ale nie w każdym STM32.
- Wersje z Ethernetem, AVR nie ma z ETH.
- Wszystkie timery 16-bit (można łączyć w 32-bit) a wiele wersji posiada 32-bit.
- ADC 12..16-bit, CA 12-bit.
- ADC do 80MS/s (LPC), 18MS/s (STM32).
- Mają wielopoziomowy system przerwań (15 poziomów, Xmega tylko 3, Mega/Tiny 0 ale najnowsze wersje maja już 3 poziomy).
- Zdecydowanie większe pojemności pamięci FLASH (do 2MB) i RAM (do 1MB) o czym nawet AVR Xmega mogą tylko pomarzyć.
- Sprzętowe interfejsy CAN, LCD równoległe, matryce LCD kolor 18-bit.
- Stany wyjątkowe: Bład magistrali i podobne jak w MC68k (dawne MAC, Amiga).
- Kilkadziesiąt razy tańsze narzędzia (debuger STM32 - 13zł).

- CubeMX do konfigurowania i generowania kodu (najnowszy także IDE i kompilator).
- Podczas debugowania na bieżąco widzę stan zmiennych w AVR po zatrzymaniu uC.
- Nie muszę się zastanawiać czy dana jest w ram czy flasch aby użyć stosownej funkcji (z sufiksem _P).
- Argument w sprintf, scanf itp nie jest ograniczony do 16-bit int lecz do 32-bit.
- Przesuwane bitu (w lewo) nie jest ograniczone do 16 bitów.
- W AVR nie ma typu double, ma taki sam zakres jak float. I tak dobrze, że od którejś tam wersji, typ long long ma 64-bity a nie jak wcześniej 32-bit tak samo jak long.
- Odkładanie na stos w przerwaniu rejestrów, które czasem nie są używane (R0, R1, RAMPZ, rejestr statusu) co wymusza czasem używanie wstawek ASM.

 

Z własnych doświadczeń (to nie tylko moja opinia) mogę napisać, że RPi itp często trzeba wspomagać jakimś uC. Kiedyś robiłem to na AVR, teraz na STM32 (dawno, dawno temu na CPLD Altery z serii MAX7, MAX3). Piszę o tym abyś nie był rozczarowany. Unikaj bibliotek Adafruit. Chyba najgorsze jakie widziałem zarówno na Arduino jak i RPi. W sumie to można by książkę napisać na ten temat.

 

Życzę powodzenia w walce z AVR i mam nadzieję, że szybko dołączysz do grona ARMowców 🙂 Bardzo żałuję, że przez pewien splot wydarzeń a raczej pazerność firmy, w które pracowałem, nie kontynuowałem pracy z AVR od ok 2006 roku lecz dopiero, gdy odszedłem indywidualnie zainwestowałem w ARM czego nie żałuję. To inna liga i wcale nie trudniejsza niz AVR, zwłaszcza gdy bierzemy pod uwagę Xmega.

 

Udostępnij ten post


Link to post
Share on other sites
12 godzin temu, RFM napisał:

Mirek K. (M36 - te 36 to chyba nr ulicy, nie wiek), czy nie.

Czyli to stąd taka święta wojna przeciwko AVR... Panie Sławomir S. może lepiej zabrać się do roboty zamiast zazdrościć innym?

  • Nie zgadzam się! 1

Udostępnij ten post


Link to post
Share on other sites
(edytowany)

W moim wypadku ardu tylko do wysyłania. A esp do odbioru.. nasłuchiwania po serialu. Dalej śle po wifi co 5 min wyłapane dane z pomiarami i poprzez stronę php do bazy danych. Dla moich potrzeb te czasy są wystarczające do komfortowej pracy z monitorem temperatur.

Z całym szacunkiem do wszystkich. Prosił bym aby nie toczyć tutaj wojen słownych. Tylko skupmy się na projekcie 🙂 powtarzam ..z całym szacunkiem 🤗

Edytowano przez szczepulek

Udostępnij ten post


Link to post
Share on other sites

WSTĘP: ZASTRZEGAM SOBIE PRAWO DO WŁASNOŚCI KODÓW PROGRAMÓW ZAWARTYCH W TYM TEMACIE, KOD/PROGRAM MOŻNA UŻYWAĆ DO CELÓW PRYWATNYCH, LECZ NIE ZEZWALAM ABY WYKORZYSTANY ZOSTAŁ CELACH UCZESTNICTWA PRZEZ OSOBY TRZECIE W KONKURSACH, ARTYKUŁACH, LUB INNYCH PUBLIKACJACH BEZ MOJEJ ZGODY, ZABRANIA SIĘ TAKŻE PRZYPISANIE SOBIE CAŁOŚCI KODU, LUB JEGO CZĘŚCI A DOKŁADNIE  PRZEZE MNIE OPRACOWANEGO, UNIKALNEGO OD POWSZECHNIE ZNANYCH Z KURSÓW PROGRAMOWANIA, SZKICÓW, ITP. (WŁASNOŚĆ INTELEKTUALNA)

OK, udało mi się zakończyć projekt 🙂

Podczas testów kilKa błędów wyszło, między innymi że podczas błędu ERR2 w linijce było zapytanie o adres z 2 czujnika, i jeszcze jakiś jeden błąd.. AHA! w funkcji obsługującej zmianę ustawień, po edycji i nie zapisaniu przeskoczenie do następnych stron Menu skutkowało blokadą zwiększania parametrów(+).

Niestety... ale musiałem zrezygnować z czujników DS18B20...  mają straszną wadę, są niesamowicie podatne na ładunki elektrostatyczne, niestety w miejscu zamontowania sporo produkcyjnych elementów z tworzyw sztucznych pociera o siebie wytwarzając potencjał.

Pół biedy jak by tylko zakłócało działanie, ale czujnik GRZAŁ SIĘ DO OKOŁO 80 stopni C, znalazłem w sieci info że podłączając odwrotnie + i - to czujnik działa jak grzałka i się uszkadza.

W moim wypadku ładunki jak by na - dawały większą wartość niż na plusie.. sam nie wiem, tak czy inaczej często dochodziło do problemów. Ostatecznie kod zmieniony  został pod obsługę NTC w moim przypadku 5k Ohm, tolerancja 0,5%, temp ..-50..+150 *C, nie znałem parametru Beta wiec sam policzyłem, stosując kalkulator z jakiejś strony online, dla temp 0,2*C woda z lodem, i wrzątek 100*C w czajniku, u mnie około 3490. Przekłamanie około 0.5 st C po kalibracji.

Przejdźmy do rzeczy.. Podaję 3 szkice, 2 dla układu Mega2560 będącego częścią główną ,nazwę to rejestrator, urządzenia do pomiarów, jest to także master dla komunikacji serial. Oraz jeden szkic dla układu ESP82-12E będącego "okienkiem" na świat wysyłającym dane do bazy danych, umiejscowionej w sieci LAN u mnie, Serwer powstał na komputerze  z zainstalowanym XAMPP (apache+mysql).

Dodam jeszcze że napisałem stronę w PHP która pobiera z tej bazy danych na serwerze wszystkie pomiary, Lecz mamy tam możliwość z bocznego Menu wybrać 'nr Linii'. i Wyświetlić segregowane wyniki. Na końcu prześlę kilka zdjęć i zrzutów z tabel z wynikami po kilku dniach użytkowania w warunkach produkcyjnych.

Uwaga! w kodzie może być pewien nieład.. który w moich oczach jest porządkiem 🙂 albo skróty myślowe jasne dla mnie, nie koniecznie dla was.. No ale co. Macie PRAWIE wszystko wyłożone na ławę. OFICJALNIE KODY PROGRAMÓW PONIŻEJ UWAŻAM ZA OSTATECZNE, I DZIAŁAJĄCE POPRAWNIE ..  lecz nie jest to jednoznaczne że nie posiada błędów lub lepszych rozwiązań.

💥 UWAGA!!! Zmienione są niektóre piny ich kolejność i/lub przeznaczenie!!! SPRAWDŹ połączenia przed wgraniem na płytki!!!! 💥

  • Arduino MEGA2560 wersja z cz.temp. DS18B20
#include <EEPROM.h>
#include <TM1637Display.h> //wersja 1.0 biblioteki
#include <DS18B20.h>
#include <OneWire.h>

/*     SSS                                                 L             K       (2019) v.5
      S       ZZZZ    CCC   ZZZZ    EEE    PPPP    U   U   L      EEE    K   K
       SSS      Z    C        Z    E___E   P   P   U   U   L     E___E   K K
          S    Z     C       Z     E       P   P   U   U   L     E       K  K
      SSSS    ZZZZ    CCC   ZZZZ    EEE    PPPP     UUU     LL    EEE    K   K
                                           P
    KOMUNIKACJA PO SERIALU (SOFTWARE)
    Do komunikacji wykorzystano Nadawanie TX Arduino Mega 2560, odbior na Arduino Uno R3
    Na Mega 2560 uzyto Serial1, mozna uzyc serial2, czy serial3. Na Uno piny 2-oraz 3.
    WAZNE !!! nie zapomnijcie polaczyc ze soba GND obu plytek.
    u mnie dziala to dobrze. Przy nadawaniu temperatura jest zamieniana na liczbe calkowita bez przecinka/kropki poprzez
    pomnozenie przez 100 wyniku pomiaru. By uniknac zmiany dlugosci wysylanych danych przy ujemnych temperaturach,
    do wyniku dodaje 30 stopni, ktore przy pozniejszemu dekodowaniu na odbiorniku odejmuje (te 30st.),
    Dzieki temu zabiegowi temperatura np 22.50 st.C, zamienione na calkowite ma wartosc 2250. a po dodaniu wczesniej
    do pomiaru 30 ma wartosc 5250. I do wysylania potrzebne sa 4 bajty.
    Bez tego wartosc -23.00 st.C po pomnozeniu ma wartosc -2300 czyli ze znakiem minusa mamy 5 bajtow.
    Po dodaniu do pomiaru 30 st mamy 13 st (-23+30= 13) podsumowujac, minimalna temp przesylana bez bledu dekodowania/
    odczytu/ to temperatura  -29.50, natomiast maksymalna to 69.50 (bo 70.00+ 30 = 100, po pomnozeniu przekracza 4 bajty)
    Może i to  rozwiązanie mocno AMATORSKIE, ale działa :) teraz można ulepszac kod i przeksztalcac..

    ! ! ! !  ! !! ! !  ! !  ! ! !!  !
    // kod dla ARDUINO MEGA 2560 (4 x Serial) w trybie nadawania na Serial1

    MODYFIKACJA KODU Z LCD NA LED 7 segmentowy 4-digit /adaptacja

   czesciowo dzieki Clovis Fritzen in 05/06/2017

*/

#define ONE_WIRE_temp_in 2 //pin dla 1 czujnika ds18b20
#define ONE_WIRE_temp_out 3 //pin dla drugiego czujnika
#define CLK1 5 //wyswietlacz nr1 8segm.4-cz dla wejscia powietrza - temp
#define DIO1 6 //wyswietlacz nr1 8segm.4-cz
#define CLK2 7 //wyswietlacz nr2 8segm.4-cz dla wyjscia powietrza - temp
#define DIO2 8 //wyswietlacz nr2 8segm.4-cz


int WhichScreen = 1;  // This variable stores the current Screen number
boolean hasChanged = true; //czy nastapila zmiana w menu/ odswierza wyswietlane dane pobierajac wartosci z tablic po modyfikacjach.
boolean pokazMenu = 0; // 0 = glowna funkcja, czy tez domyslnie wyswietlane dane, przy 1 wiadomo co sie poawia jak nazwa zmiennej wskazuje

const int resetPin = 9 ; //reset Mega2560
const int automatSwPin = 11 ; // PIN 11 ,podlaczony przez przekaznik w skrzynce kontrolnej
const int ALtempLED = 50 ; // podlaczony przez przekaznik w skrzynce kontrolnej
const int ALprzekaznik = 51; // Przekaznik sygn ALarmu
const int LEDzapisz = 12;  //alarmuje o braku zapisu ustawien
const int buttonMenu = 33; // wywolanie Menu
const int buttonOk = 32; // zatwierdz/zapisz key OK
const int buttonUp = 31; // edycja key UP
const int buttonDn = 30; // edycja key DOWN
int stanAutoSwPin = 0;

int buttonState; // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 120;    // the debounce time; increase if the output flickers


TM1637Display display_1(CLK1, DIO1);
TM1637Display display_2(CLK2, DIO2);
OneWire oneWire_in(ONE_WIRE_temp_in);
OneWire oneWire_out(ONE_WIRE_temp_out);

DS18B20 sensor_airin(&oneWire_in);
DS18B20 sensor_airout(&oneWire_out);

byte address1[8]; //dla ds18b20 czujnik 1 / in
byte address2[8]; //dla czujnik 2 / out

unsigned long time0 = 0; //zliczanie czasu pracy w automacie
unsigned long time0blink = 0; // czasowka dla migajacej lampy sygnalizacyjnej
word zwlokaPrzekazAL = 30000; //300000ms = 5 minut,  zwloka nim wlaczy sie sygnalizator zewn alarmu

unsigned long time1 = 0; //migajaca dioda powiadomien o zapisie
unsigned long time2 = 0; // czasowka dla wyswietlacza LED Display 1 /  odswiezanie

unsigned long timeReset; // czasowka do momentu resetowania
int actErr1 = 0;
int actErr2 = 0;
int zwlokaReset = 30000;

//unsigned long time3 = 0; // testowe pocz loop  ORAZ czas po zapisie 'buzki'/LED 'zapisz!'
//unsigned long time4 = 0; // testowe koniec loop - pocz
//unsigned long time5 = 0; // testowe str 1 - pocz
//unsigned long time6 = 0; // testowe
//unsigned long timeSrednia=0;
//unsigned long przebieg = 1;
//unsigned long timeSredniaSuma = 0;
//unsigned long timeSredniaWynik = 0;
//unsigned long dodawanie [1];

unsigned long autoExitMenu = 0; //wyjscie z menu automat (odczyt dla funkcji z millis)
word autoExitCzas = 20000; // czas zwloi przed AUTOMATYCZNYM WYJSCIEM z menu, maksymalnie '65534' ms dla zmiennej typu 'word'

boolean d1 = 0; // do migajacej diody zapis
boolean d2 = 0; // do migajacej lampy sygnalizacyjnej

uint8_t wysw1LED[] = { 0x00, 0x00, 0x00, 0x00 };  //Dla LEDDispl4digit
uint8_t wysw2LED[] = { 0x00, 0x00, 0x00, 0x00 };

String wyspom1 [11]; // [znSpecPoczatku][c1p1][c2p1][c3p1][AL0/1][c1p2][c2p2][c3p2][liniaC1][liniaC2][znSpecKonca]

/* tabStrMenu  - przechowywanie poszczegolnych ustawien dla kolejnych stron, 0 - niewykozystane, 1 - nr czujnika powiazany z alarmem, 2 - dla 1 strony czyli ALARM, 3 - przechowywany numer LINII;
  mozna tez przypisac do stron przez 's-1' w linii funkci menu  */
int tabStrMenu[4];  //  dane ze stron/menu LED  // ilosc deklarowana = ilosc stron + 1; srtona 0 (case 0) nie przechowuje zadnej wartosci potrzebnej dla dzialaniaprogramu
int eepromOdczyt[4]; // i tak wartosci w tabeli [0] - braka odpowiednika dla pamieci EEPROM/miejsca 0 nie ma poprostu w EEPROM, [1] w tabeli odpowiada miejsce (1) w pamieci eeprom itd...
int i;
char AL;
char KOD; // zakodowane wartosci do wyslania Serial
byte first3loopForTX; //pierwsze 3 petle programu-odliczanie

//wyswietlanie segmentow dla ALc
const uint8_t disp_cznr[] = { // dalej w kodzie czujnik nr 1=in 2=out
  SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G ,           // A
  SEG_D | SEG_E | SEG_F,                                    // L
  SEG_D | SEG_E | SEG_G                                     // c
};

//wyswietlenie segmentow dla AL
const uint8_t disp_alarm[] = {
  SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G ,           // A
  SEG_D | SEG_E | SEG_F                                     // L
};

//wyswietlenie segmentow dla L
const uint8_t disp_linia[] = {
  SEG_D | SEG_E | SEG_F ,                                   // L
  SEG_C | SEG_E | SEG_G                                     // n
};

const uint8_t disp_done[] = {
  SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,           // d
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,   // O
  SEG_C | SEG_E | SEG_G,                           // n
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G            // E
};

const uint8_t disp_buzka[] = {
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,            // 8  8-]
  SEG_G,                                                            // -
  SEG_A | SEG_B | SEG_C | SEG_D,                                    // ]  
  0
};

const uint8_t disp_confirm[] = {
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,           // e
  SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,           // d
  SEG_E | SEG_D,                                   // i
  SEG_D | SEG_E | SEG_F | SEG_G                    // t
};

/* P
  const uint8_t disp_confirm[] = {
  SEG_A | SEG_B | SEG_E | SEG_F | SEG_G,           // c
  0,                                               // o
  0,                                               // n
  0                                                // f
  };
*/

void setup()
{
  digitalWrite(resetPin, HIGH);
  delay(200);
  pinMode(buttonOk, INPUT_PULLUP);
  pinMode(buttonMenu, INPUT_PULLUP);
  pinMode(buttonUp, INPUT_PULLUP);
  pinMode(buttonDn, INPUT_PULLUP);
  pinMode(automatSwPin, INPUT_PULLUP);
  pinMode(LEDzapisz, OUTPUT);
  digitalWrite(LEDzapisz, LOW);
  pinMode(ALprzekaznik, OUTPUT);
  digitalWrite(ALprzekaznik, LOW);
  pinMode(ALtempLED, OUTPUT);
  digitalWrite(ALtempLED, LOW);
  pinMode(resetPin, OUTPUT);



  display_1.setBrightness(0x0c); //LED7Seg jasnosc wys 1, ponizej 2
  display_2.setBrightness(0x0c);

  Serial.begin(9600);
  Serial1.begin(9600);  // inic. serial 1 do wysylania danych na esp8266

  sensor_airin.begin(9); // inicjacja, wartosc w nawiasach to rozdzielczosc czujnika od 9 do 12
  sensor_airout.begin(9);

  oneWire_in.reset_search();
  while (oneWire_in.search(address1))
  {
    if (address1[0] != 0x28)
      continue;

    if (OneWire::crc8(address1, 7) != address1[7])
    {
      Serial.println(F("1-Wire IN bus connection error!"));
      break;
    }
  }

  oneWire_out.reset_search();
  while (oneWire_out.search(address2))
  {
    if (address2[0] != 0x28)
      continue;

    if (OneWire::crc8(address2, 7) != address2[7])
    {
      Serial.println(F("1-Wire OUT bus connection error!"));

      break;
    }
  }

  // PINy diagnostyczne
  //pinMode(40, OUTPUT); // czas trwania dla DS18b20
  //pinMode(44, OUTPUT); //czas trwania dla LED-wysw


  sensor_airin.request();
  sensor_airout.request();

  if (EEPROM.read(1) > 2)  //warunek, jesli nr czujnika odczytany w EEPROM jest wiekszy niz 2 --zapisz wartosc domyslna 1
  {
    Serial.println("Zapisano domyslny numer czujnika dla alarmu");
    EEPROM.write(1, 1);
  }


  for (i = 1; i <= 3; i++) // ilosc stron = 3 w tym przypadku, to i komorek pamieci 3
  {
    tabStrMenu[i] = EEPROM.read(i); // i=1 alarm (sygnalizacja) przypisany dla czujnika 1 lub 2 (1= in, 2= out)
    // i=2 do testow domyslna wartosc dla alarmu, domyslnie pobierane z EEPROM do tabeli
    // i=3 domyslnie z eeprom - pobranie numeru linii do tabeli
    WhichScreen = 0; // aby menu startowalo od 1 str.
  }

  AL = '0'; // znacznik alarmu na znak 0

  first3loopForTX = 1; //pierwsze wysylanie danych po Serial'u od uruchomienie programu

  time0 = millis(); // rozpoczecie zliczania (dla trybu Nara praca automat)
  timeReset = millis();
}


void loop()
{
  //    time3 = millis();
  int airinCalkow;
  int airoutCalkow;
  int comTempIN;
  int comTempOut;

  stanAutoSwPin = digitalRead(automatSwPin); // odczytaj stan na pine - przekaznik w Narze
  if (stanAutoSwPin == !LOW)  // jesli wyl. automat..
    time0 = millis(); // nadpisuj zliczanie (zerowanie)

  // digitalWrite(40, HIGH); //do pomiaru na oscyloskopie czasu trwania "start pomiaru odczytu DS18B20"

  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  for (i = 1 ; i <= 3; i++)
  {
    eepromOdczyt[i] = EEPROM.read(i); //aktualnie zapisane w eeprom
    //   Serial.println("wartosci zapisane w komorkak EEPROM:");
    //   Serial.println(eepromOdczyt[i]);
  }


  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  if ( sensor_airin.available() )
  {

    float  tempIn = sensor_airin.readTemperature(address1); // odczyt temp
    float  tempOut = sensor_airout.readTemperature(address2);
    /*     Serial.println(tempOut); //wyswietla w serial monitor, ostatecznie bedzie usuniete
    */

    // digitalWrite(40, LOW); //koniec pomiaru odczytu i przeliczenia na calkowita liczbe

    airinCalkow = tempIn * 100; //pozbycie sie kropki w wyniku pomiaru xx.xx
    airoutCalkow = tempOut * 100; //podobnie dla drugiego pomiaru
    comTempIN = (tempIn + 30) * 100; //pozbycie sie kropki w wyniku pomiaru xx.xx
    comTempOut = (tempOut + 30) * 100; //podobnie dla drugiego pomiaru


    sensor_airin.request();
    sensor_airout.request();

  }


  Serial.println("sens.dost?; adres sen1; adres sen2:");
  Serial.println(sensor_airin.available());    // informacje do testow dzialania wysw w serial monitor, nie potzrebne potem.
  Serial.println(address1[0]);
  Serial.println(address2[0]);


  //obsluga wyswietlania pierwszego wyswietlacza dla czujnika 1 ,szczegulna uwage nalezy zwrocic na prawidlowe odwolanie sie do uint, i display

  // digitalWrite(44, HIGH);      //start wyswietlanie wartosci na led_tm1637

  // uwaga.. zamiana ulamka na calkowite i przez dodanie do wyniku +29 pozbycie sie ewentualnego znaku MINUS

  char ti1 = comTempIN / 1000 % 10 + 48; //dodanie 48 by uzyskac znak typu char
  char ti2 = comTempIN / 100 % 10 + 48;
  char ti3 = comTempIN / 10 % 10 + 48;
  char to1 = comTempOut / 1000 % 10 + 48; // L_._ dziesiatki
  char to2 = comTempOut / 100 % 10 + 48; // _L._ jednosci
  char to3 = comTempOut / 10 % 10 + 48; // __.L cz.dziesietne



  //jesli  odczyt EEPROM nr czuj=1 i temp wej >= odczyt EEPROM dla temp alarmu  'lub'
  if (eepromOdczyt[1] == 1 && airinCalkow >= eepromOdczyt[2] * 100 || eepromOdczyt[1] == 2 && airoutCalkow >= eepromOdczyt[2] * 100)
  {
    AL = '1';
    digitalWrite(ALtempLED, HIGH); //aktywacja diody sygnalizujacej o przekroczeniu temp max , takze  praca maszyny w Automacie
    if (millis() - time0 > zwlokaPrzekazAL)
    {
      if (millis() - time0blink > 1250)
      {
        d2 = !d2;
        time0blink = millis();
      }

      if (d2)  {
        digitalWrite(ALprzekaznik, HIGH); //aktywacja przekaznika sygnalizacji alarmu po 5 min od wykrycia pracy w automacie
      }
      else
      {
        digitalWrite(ALprzekaznik, LOW);
      }

    }
    else
    {
      digitalWrite(ALprzekaznik, LOW);
    }
  }
  else
  {
    AL = '0';
    digitalWrite(ALprzekaznik, LOW); // brak alarmu - wylacz przekaznik, diode sygn.
    digitalWrite(ALtempLED, LOW);
  }


  char Ln1 = eepromOdczyt[3] / 10 % 10 + 48; // 1 cyfra nr linii --dodanie 48 by uzyskac znak typu char
  char Ln2 = eepromOdczyt[3] % 10 + 48; //2 cyfra nr linii

  /*
    Serial.println("pierwsze uruch petli loop?"); //test
    Serial.println(firstSerialTX); //test
    Serial.println("ln1 ln2");
    Serial.println(Ln1);
    Serial.println(Ln2);
  */

  //  digitalWrite(44, LOW); //koniec pomiaru czasu funkcji wyswietlania na 2 szt modulu LED wyswietlacz tm1637 //pomiar na oscyloskopie

  /*kodowanie Alarmu i pracy nary w Auto/Recznym

     wyspom1[4] = KOD  jesli kod pryjmuje wartosc 0 - tryb autom. | brak alarmu
                                                  1 - tryb autom. | alarm!
                                                  2 - tryb reczny/wyl | brak alarmu
                                                  3 - tryb reczny/wyl | alarm!
                                                  na kod sklada sie AL i stanAutoSwPin (LOW = tryb autom)
  */
  if (AL == '0' && stanAutoSwPin == LOW)
  {
    KOD = '0'; // brak alarmu, praca automat
  }

  if (AL == '1' && stanAutoSwPin == LOW)
  {
    KOD = '1';
  }

  if (AL == '0' && stanAutoSwPin == HIGH)
  {
    KOD = '2';
  }

  if (AL == '1' && stanAutoSwPin == HIGH)
  {
    KOD = '3';
  }

  char wyspom1 [11]; // [znspec][c1p1][c2p1][c3p1][AL0/1][c1p2][c2p2][c3p2][liniaC1][liniaC2][znSpecKonca]
  //char wyspom2 [5];

  wyspom1[0] = 0x7B; //zn specj nadawania
  wyspom1[1] = ti1; //odpowiada za dziesiatki 1 pomiaru
  wyspom1[2] = ti2; //odpowiada za jednosci 1 pomiaru
  wyspom1[3] = ti3; //odpowiada za czasci dziesietne 1 pomiaru, czyli po kropce
  wyspom1[4] = KOD;  //czy aktywny alarm?? temperatury: 0 nie,  1 tak
  wyspom1[5] = to1; //odpowiada za dziesiatki 2 pomiaru
  wyspom1[6] = to2; //odpowiada za jednosci 2 pomiaru
  wyspom1[7] = to3; //odpowiada za czasci dziesietne 2 pomiaru, czyli po kropce
  wyspom1[8] = Ln1; // 1. cyfra nr linii
  wyspom1[9] = Ln2; // 2. cyfta nr linii
  wyspom1[10] = 0x7D; // znak specj zakonczenia nadawania

  /* konfiguraca przycisku Menu */
  if (digitalRead(buttonMenu) == LOW && pokazMenu == 0) // sprawdza czy na pinie 33 stan LOW niski, jesli tak to ..
  {
    pokazMenu = 1; //uruchamia Menu
    delay(15);
  }


  // komunikacja

  if (wyspom1[1] != '0' && wyspom1[2] != '0' && wyspom1[3] != '0' || first3loopForTX >= 3)
    // podczas startu programu na plytce  wartosci sa rowne 0 0 0 , jesli wartosci sa inne to wysyla na SERIAL dane
  {
    Serial1.write(wyspom1, 11); // wysyla paczke do drugiego urzadzenia na Serial nr (serial1)

    Serial.println("na com");
    for (int j = 0; j < 11; j++)
    {
      Serial.print(wyspom1[j]);
    }
    Serial.println(" ");
  }
  else
  {
    Serial.println("! blad wartosci do wyslania lub wykonanie petli 'loop' mniej niz 3 razy od starcie!"); // zdazalo sie ze pierwsze 3 pomiary po uruchomieniu byly losowe zafalszowane dlatego pierwsze trzy pomijam
    if (first3loopForTX < 3) //dodaje 1 do czasu wykonania 3co najmniej 3 petli
    {
      first3loopForTX++;

      //przebieg = 1; //testy czasowe obiegu petli

    }
  }

  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


  // kontrolka o nie zapisaniu do pamieci parametrow z menu.
  if (eepromOdczyt[1] != tabStrMenu[1] || eepromOdczyt[2] != tabStrMenu[2] || eepromOdczyt[3] != tabStrMenu[3]) // kontrolka miga dla braku zapisu nr czujnika
  {
    if (millis() - time1 > 250)
    {
      d1 = !d1;
      time1 = millis();
    }
  }

  if (d1)  
  {
    digitalWrite(LEDzapisz, HIGH);
  }
  else
  {
    digitalWrite(LEDzapisz, LOW);
  }


  if (eepromOdczyt[1] == tabStrMenu[1] && eepromOdczyt[2] == tabStrMenu[2] &&  eepromOdczyt[3] == tabStrMenu[3]) // " && AL != '1' " do testu przekaznika podczas alarmu , sygnalizacja na LED pin 13
  {
    digitalWrite(LEDzapisz, LOW);
  }


  // jesli (domyslnie na starcie) mamy 0 to wykonaj program, wlasciwy..czy tez ten ktory ma sie glownie wykonywac

  if (pokazMenu == 0) {    //GLOWNY PROGRAM

    //poczatek gl prog

    if ( airinCalkow < -9900  || airinCalkow == 0)
    {
      wysw1LED[0] = (SEG_A | SEG_D | SEG_E | SEG_F | SEG_G); // E
      wysw1LED[1] = (SEG_E | SEG_G); // r
      wysw1LED[2] = (SEG_E | SEG_G); // r
      wysw1LED[3] = display_1.encodeDigit(1); // 1
      display_1.setSegments(wysw1LED); // Err1

      actErr1 = 1;

      //ponowne wyszukanie czujnika i przypisanie pod address
      oneWire_in.reset_search();
      while (oneWire_in.search(address1))
      {
        if (address1[0] != 0x28)
          continue;

        if (OneWire::crc8(address1, 7) != address1[7])
        {
          Serial.println(F("1-Wire IN bus connection error!"));
          break;
        }
      }
    }
    else
    {
      wysw1LED[0] = display_1.encodeDigit(airinCalkow / 1000 % 10); //wyswietla cyfre dziesiatek z pomiaru cz.1 na wyswietlaczu pierwszym
      wysw1LED[1] = display_1.encodeDigit(airinCalkow / 100 % 10); //wyswietla cyfre jednosci z pomiaru cz.1 na wyswietlaczu pierwszym
      wysw1LED[2] = (SEG_A | SEG_B | SEG_F | SEG_G); // znak stopni zamiast kropki ktore brak w wyswietlaczu ktory posiadam
      wysw1LED[3] = display_1.encodeDigit(airinCalkow / 10 % 10); //pierwsza cyfra czesci dziesietnych

      actErr1 = 0;
    }

    //obsluga wyswietlania drugiego wyswietlacza dla czujnika 2
    if (airoutCalkow < -9999 || airoutCalkow == 0)
    {
      wysw2LED[0] = (SEG_A | SEG_D | SEG_E | SEG_F | SEG_G); // E
      wysw2LED[1] = (SEG_E | SEG_G); // r
      wysw2LED[2] = (SEG_E | SEG_G); // r
      wysw2LED[3] = display_2.encodeDigit(2); // 2
      display_2.setSegments(wysw2LED); // Err2

      actErr2 = 1;
      //ponowne wyszukanie czujnika i przypisanie pod addres
      oneWire_out.reset_search();
      while (oneWire_out.search(address2))
      {
        if (address2[0] != 0x28)  //// pooprawa błedu address1 na adress2 /sprawdzic podczas dzialania(!)
          continue;

        if (OneWire::crc8(address2, 7) != address2[7])
        {
          Serial.println(F("1-Wire OUT bus connection error!"));
          break;
        }
      }
    }
    else
    {
      wysw2LED[0] = display_2.encodeDigit(airoutCalkow / 1000 % 10); //wyswietla cyfre dziesiatek z pomiaru cz.1 na wyswietlaczu pierwszym
      wysw2LED[1] = display_2.encodeDigit(airoutCalkow / 100 % 10); //wyswietla cyfre jednosci z pomiaru cz.1 na wyswietlaczu pierwszym
      wysw2LED[2] = (SEG_A | SEG_B | SEG_F | SEG_G); // znak stopni zamiast kropki ktore brak w wyswietlaczu ktory posiadam
      wysw2LED[3] = display_2.encodeDigit(airoutCalkow / 10 % 10); //pierwsza cyfra czesci dziesietnych
      //      display_2.setSegments(wysw2LED); // wyswietlenie  temperatury na pierwszym wyswietlaczu

      actErr2 = 0;
    }

    if (millis() - time2 >= 125) // co 125ms odswierzenie wyswietlaczy
    {
      display_1.setSegments(wysw1LED); // wyswietlenie  temperatury na pierwszym wyswietlaczu
      display_2.setSegments(wysw2LED);
      time2 = millis();
    }

    // koniec gl prog

    hasChanged = true; // ustawiam na true, aby po wlaczeniu na menu pojawila sie na wyswietlaczu strona ustawien, bez tego zostaje zamrozony wynik ostatniego pomiaru z wejscia analogowego

    if (actErr1 == 1 || actErr2 == 1)
    {
      if (millis() - timeReset > zwlokaReset)
        digitalWrite(resetPin, LOW);
    }
    else
    {
      timeReset = millis();
      digitalWrite(resetPin, HIGH);
    }

  }

  else // jesli zmienna pokazMenu ma wartosc inna niz zero.. w tym wypadku tylko moze byc to 1 wykonaj.. wyswietlenie menu

  {


    int s = WhichScreen;  // UWAGA! nalezy zadeklarowac tablice o liczbie elementow nie mniejszej niz ilosc stron.

    /* konfiguraca przycisku Up/gora */
    if (digitalRead(buttonUp) == LOW && WhichScreen == s) // zmiana parametrow UP/dodaj
    {
      //Serial.print("UP dla strona nr :");
      //Serial.println(WhichScreen);
      if (WhichScreen == s)
      {

        if (tabStrMenu[s] < 99 &&  s != 1) // gorna granica wyboru 99, oprocz  strony dla nr czujnika gdzie max to 2.
        {
          tabStrMenu[s]++; //dodaj o jeden wiecej
        }

        if (s == 1 && tabStrMenu[s] < 2) // gorna granica wyboru 99, oprocz  strony dla nr czujnika gdzie max to 2.
        {
          tabStrMenu[s]++; //dodaj o jeden wiecej
        }


        autoExitMenu = millis(); // zerowanie braku aktywnosci w menu
        hasChanged = true; //odswierza wyswietlacz LED
        delay (20);
      }
    }

    /* konfiguraca przycisku dol/minus */
    if (digitalRead(buttonDn) == LOW && WhichScreen == s) // zmiana parametrow DOWN/odejmij
    {
      if (WhichScreen == s)
      {
        if (tabStrMenu[s] > 1) //
        {
          tabStrMenu[s]--;
        }
        autoExitMenu = millis(); // zerowanie braku aktywnosci w menu
        hasChanged = true;
        delay(20);
      }
    }

    /* konfiguracja przycisku Ok/Zapisz */
    if (digitalRead(buttonOk) == LOW && WhichScreen == s && WhichScreen > 0) // od strony 1 zapis do komorki 's' = stronie
    {
      if (WhichScreen == s)
      {
        if (eepromOdczyt[s] == 255) //warunek gdy wartosc domyslna wynosi 255 (nowa plytka nie nadpisywana pamiec) uzyj polecenia zapisz WRITE
        {
          EEPROM.write(s, 35); // zapisyj na wartosc domyslna alarmu / linii produ. na: 35
          tabStrMenu[s] = eepromOdczyt[s]; // uaktualnienie wpisanej wartosci z pamieci do tablicy wyswietlajacej
          display_1.setSegments(disp_done);
          Serial.println("\n nadpisano po raz PIERWSZY \n strona i komorka nr:");
          Serial.println(s);
          hasChanged = true;
          digitalWrite(LEDzapisz, LOW);
          digitalWrite(LEDzapisz, HIGH);
          delay(75);
          digitalWrite(LEDzapisz, LOW);
          delay(50);
          digitalWrite(LEDzapisz, HIGH);
          delay(75);

        }
        else
        {
          if (eepromOdczyt[s] != tabStrMenu[s])
          {
            EEPROM.update(s, tabStrMenu[s]);
            Serial.println("uaktualniono wartosc w pamieci...");
            display_1.setSegments(disp_done);
            digitalWrite(LEDzapisz, HIGH);
            display_2.setSegments(disp_buzka);
            hasChanged = true;
            delay(1300);
            digitalWrite(LEDzapisz, LOW); //wygasza diode zapisu
            display_2.clear();
            hasChanged = true;


          }
        }
        autoExitMenu = millis(); // zerowanie braku aktywnosci w menu
        hasChanged = true;
        delay (25);
      }
    }

    if (millis() - autoExitMenu > autoExitCzas) //warunek wyprowadza z menu, jesli brak aktywnosci podana ilosc czasu (ms)
    {
      for (int k = 1; k <= 3; k++) //dla stron 1-3 (LNr, czNr, alTemp) przywrocenie ustawien domyslnych jesli roznia sie od nastawionych i zapisanych w eeprom, oraz wyl diody sygnalizacyjnej 'zapisz'
        if (eepromOdczyt[k] != tabStrMenu[k])
          tabStrMenu[k] = eepromOdczyt[k];
      pokazMenu = 0;
      digitalWrite(LEDzapisz, LOW);
      autoExitMenu = millis();
    }


    if (hasChanged == true)
    {

      switch (WhichScreen) {
        case 1:
          {

            firstScreen();
          }
          break;

        case 2:
          {
            secondScreen();
          }
          break;


        case 3:
          {
            thirdScreen();
          }
          break;




        case 4:
          {

            /* Dzieki temu warunkowi, bedac na OSTATNIEJ wyswietlanej stronie,
              jesli wprowadzimy modyfikacje parametrow na ktorejs ze stron, i nie zapiszemy ich
              przy wychodzeniu z menu zostana przywrocone domyslne wartosci zapisane w eeprom.
              kontrolka od zapisu gasnie.
            */
            for (i = 1 ; i <= 3; i++)
              if (eepromOdczyt[i] != tabStrMenu[i])
              {
                tabStrMenu[i] = eepromOdczyt[i];
              }
            autoExitMenu = millis(); // zerowanie braku aktywnosci w menu
            pokazMenu = 0; //wracamy do wyswietlania z glownej pętli funkcji
          }
          break;

        /* Dla wiekszej ilosci wyswietlania pozycji menu


          case 5:
          {
          fifthScreen();
          }
          break;

          case 6:
          {
          sixthScreen();
          }
          break;
        */

        case 0:  //konczacy zapis menu
          {

          }
          break;
      }

    }

    //-------------------------------
    // BEGIN of the switch debouncing code
    int reading = digitalRead(buttonMenu);
    if (reading != lastButtonState) {
      // reset the debouncing timer
      lastDebounceTime = millis();
    }

    if ((millis() - lastDebounceTime) > debounceDelay) {
      // whatever the reading is at, it's been there for longer
      // than the debounce delay, so take it as the actual current state:

      // if the button state has changed:
      if (reading != buttonState) {
        buttonState = reading;

        // only toggle the LED if the new button state is HIGH
        if (buttonState == HIGH) {
          hasChanged = true;
          WhichScreen++;


        }
      }
      else
      {
        hasChanged = false;
      }
    }
    lastButtonState = reading;
    // END of the switch Debouncing code
    // --------------------------------------
    if (WhichScreen > 4) { //ilosc wszystkich stron  ..doliczamy tez ta wracajaca do pierwotnej funkcji wykonywania
      WhichScreen = 1;
    }

  }

  /*
     wylicza czas petli programu
    time4= millis()-time3;

    timeSrednia=dodawanie[0];
    dodawanie[0]=timeSrednia+time4;
    timeSredniaWynik=dodawanie[0]/przebieg;

    Serial.println("ŚrEdNiA:");
        Serial.println(timeSredniaWynik);
                Serial.println(" ");

    przebieg++;
  */


}  // KONIEC void loop() !!;  #################################################




void firstScreen()  // pierwsza strona opcji // nr czujnika dla alarmu
{

  display_1.setSegments(disp_cznr, 3, 0); // wyswietla wartosc cz1 lub czujnik 2, w zaleznosci ile ich podlaczymy
  display_1.showNumberDec(tabStrMenu[1], false, 1, 3);  //wyswietla graniczna temp. alarmu
  if (tabStrMenu[1] != eepromOdczyt[1])
  {
    display_2.setSegments(disp_confirm); // wyswietlenie  Edit na drugim wyswietlaczu w menu
  }
  else
  {
    if (millis() - time2 > 100)
    {
      //        display_1.clear();
      display_2.clear();
      time2 = millis();
    }
  }


}

void secondScreen() // druga str opcji itd itp
{

  // display_1.clear();  //konieczne by nie nakladaly sie na siebie znaki/liczby z poprzedniego menu
  display_1.setSegments(disp_alarm, 2, 0);
  display_1.showNumberDec(tabStrMenu[2], false, 2, 2);  //wyswietla graniczna temp. alarmu

  if (tabStrMenu[2] != eepromOdczyt[2])
  {
    display_2.setSegments(disp_confirm);
  }// wyswietlenie  Edit na drugim wyswietlaczu w menu
  else
  {
    if (millis() - time2 > 100)
    {
      //        display_1.clear();
      display_2.clear();
      time2 = millis();
    }
  }

  //    time5=millis()-time3;
  //    Serial.println("Str2");
  //   Serial.println(time5);
  // Serial.print("STRONA 2 Alarm od:");  // test w serial
  //  Serial.println(tabStrMenu[2]);
}

void thirdScreen() // trzecia  str opcji itd itp
{

  display_1.showNumberDec(tabStrMenu[3], false, 2, 2); // wartosc przechowywana dla Nr Linii
  // display_1.showNumberDecEx(tabStrMenu[3],0, true); // wartosc przechowywana dla Nr Linii
  display_1.setSegments(disp_linia, 2, 0);
  if (tabStrMenu[3] != eepromOdczyt[3])
  {
    display_2.setSegments(disp_confirm); // wyswietlenie  Edit na drugim wyswietlaczu w menu
  }
  else
  {
    if (millis() - time2 > 100)
    {
      //        display_1.clear();
      display_2.clear();
      time2 = millis();
    }
  }


  // Serial.print("STRONA 3 linia nr:");  // test w serial
  //  Serial.println(tabStrMenu[3]);
}
/*

  dla większej ilosci przejsc miedzy wyswietlanymi informacjami, ponizej rozpiska dla wyswietlacza LCD !!!

  void fourthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("This is screen 4");
    lcd.setCursor(0,1);
    lcd.print("Just press btn");
  }
  void fifthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("   Fifth screen");
    lcd.setCursor(0,1);
    lcd.print("i2C LCD screen");
  }
  void sixthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("THE last screen");
    lcd.setCursor(0,1);
    lcd.print("  Sixth and last");
  }
*/
  • Arduino MEGA2560 wersja z cz. temp. NTC 5K
#include <EEPROM.h>
#include <TM1637Display.h> //wersja 1.0 biblioteki

//  WERSJA DLA  NTC 5k  ohm; toler 0,5%; Beta wyliczona 3490

/*     SSS                                                 L             K       (2019) v.6
      S       ZZZZ    CCC   ZZZZ    EEE    PPPP    U   U   L      EEE    K   K
       SSS      Z    C        Z    E___E   P   P   U   U   L     E___E   K K
          S    Z     C       Z     E       P   P   U   U   L     E       K  K
      SSSS    ZZZZ    CCC   ZZZZ    EEE    PPPP     UUU     LL    EEE    K   K
                                           P
    KOMUNIKACJA PO SERIALU (SOFTWARE)
    Do komunikacji wykorzystano Nadawanie TX Arduino Mega 2560, odbior na Arduino Uno R3
    Na Mega 2560 uzyto Serial1, mozna uzyc serial2, czy serial3. Na Uno piny 2-oraz 3.
    WAZNE !!! nie zapomnijcie polaczyc ze soba GND obu plytek.
    u mnie dziala to dobrze. Przy nadawaniu temperatura jest zamieniana na liczbe calkowita bez przecinka/kropki poprzez
    pomnozenie przez 100 wyniku pomiaru. By uniknac zmiany dlugosci wysylanych danych przy ujemnych temperaturach,
    do wyniku dodaje 30 stopni, ktore przy pozniejszemu dekodowaniu na odbiorniku odejmuje (te 30st.),
    Dzieki temu zabiegowi temperatura np 22.50 st.C, zamienione na calkowite ma wartosc 2250. a po dodaniu wczesniej
    do pomiaru 30 ma wartosc 5250. I do wysylania potrzebne sa 4 bajty.
    Bez tego wartosc -23.00 st.C po pomnozeniu ma wartosc -2300 czyli ze znakiem minusa mamy 5 bajtow.
    Po dodaniu do pomiaru 30 st mamy 13 st (-23+30= 13) podsumowujac, minimalna temp przesylana bez bledu dekodowania/
    odczytu/ to temperatura  -29.50, natomiast maksymalna to 69.50 (bo 70.00+ 30 = 100, po pomnozeniu przekracza 4 bajty)
    Może i to  rozwiązanie mocno AMATORSKIE, ale działa :) teraz można ulepszac kod i przeksztalcac..

    ! ! ! !  ! !! ! !  ! !  ! ! !!  !
    // kod dla ARDUINO MEGA 2560 (4 x Serial) w trybie nadawania na Serial1

    MODYFIKACJA KODU Z LCD NA LED 7 segmentowy 4-digit /adaptacja

   czesciowo dzieki Clovis Fritzen in 05/06/2017

*/

// Czujniki temp analogowe NCT 5k (0.3stC =14280 Ohm; 100stC =482 Ohm, beta 3485-3490)

// which analog pin to connect
//czujnik 1 IN na pinie analogowym A0
#define THERMISTORPIN_1 A0
// resistance at 25 degrees C
#define THERMISTORNOMINAL_1 5000
// temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL_1 25
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES_1 5 // do usredniania wynikow tutaj 5-ciu
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT_1 3485
// the value of the 'other' resistor / rezystor ma dokładność 5% powinno się uzyć 1% toleranci, tutj wpisuje wartosc z pomiaru multimetrem
#define SERIESRESISTOR_1 5020


//czujnik 2 out na pinie analogowym A2
#define THERMISTORPIN_2 A2
// resistance at 25 degrees C  wartosc rezystancji dla...
#define THERMISTORNOMINAL_2 5000
// temp. for nominal resistance (almost always 25 C) ...temperatury 25*C
#define TEMPERATURENOMINAL_2 25
// how many samples to take and average, more takes longer
// but is more 'smooth'
#define NUMSAMPLES_2 5
// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT_2 3485  //3485
// the value of the 'other' resistor
#define SERIESRESISTOR_2 4990


#define CLK1 5 //wyswietlacz nr1 8segm.4-cz dla wejscia powietrza - temp
#define DIO1 6 //wyswietlacz nr1 8segm.4-cz
#define CLK2 7 //wyswietlacz nr2 8segm.4-cz dla wyjscia powietrza - temp
#define DIO2 8 //wyswietlacz nr2 8segm.4-cz

//bufor wynikow pomiarow temp czujniki 1 i 2
int samples_1[NUMSAMPLES_1];
int samples_2[NUMSAMPLES_2];
//do pomiarow temp , sredniej, i konwersji z czujnikow temp NTC5
uint8_t m;
float average_1;
uint8_t n;
float average_2;

int comTempIN;
int comTempOut;


int WhichScreen = 1;  // This variable stores the current Screen number
boolean hasChanged = true; //czy nastapila zmiana w menu/ odswierza wyswietlane dane pobierajac wartosci z tablic po modyfikacjach.
boolean pokazMenu = 0; // 0 = glowna funkcja, czy tez domyslnie wyswietlane dane, przy 1 wiadomo co sie poawia jak nazwa zmiennej wskazuje

const int resetPin = 9 ; //reset Mega2560
const int automatSwPin = 11 ; // PIN 11 ,podlaczony przez przekaznik w skrzynce kontrolnej
const int ALtempLED = 50 ; // podlaczony przez przekaznik w skrzynce kontrolnej
const int ALprzekaznik = 51; // Przekaznik sygn ALarmu
const int LEDzapisz = 12;  //alarmuje o braku zapisu ustawien
const int buttonMenu = 33; // wywolanie Menu
const int buttonOk = 32; // zatwierdz/zapisz key OK
const int buttonUp = 31; // edycja key UP
const int buttonDn = 30; // edycja key DOWN
int stanAutoSwPin = 0;

int buttonState; // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 120;    // the debounce time; increase if the output flickers


TM1637Display display_1(CLK1, DIO1);
TM1637Display display_2(CLK2, DIO2);

unsigned long time0 = 0; //zliczanie czasu pracy w automacie
unsigned long time0blink = 0; // czasowka dla migajacej lampy sygnalizacyjnej
word zwlokaPrzekazAL = 30000; //300000ms = 5 minut,  zwloka nim wlaczy sie sygnalizator zewn alarmu

unsigned long time1 = 0; //migajaca dioda powiadomien o zapisie
unsigned long time2 = 0; // czasowka dla wyswietlacza LED Display 1 /  odswiezanie

unsigned long timeReset; // czasowka do momentu resetowania
int actErr1 = 0;
int actErr2 = 0;
float zwlokaReset = 660000; // czas zwloki do resetu, RESET wykonywany podajac niski stan LOW z PINu  nr 9 na PIN Reset

unsigned long autoExitMenu = 0; //wyjscie z menu automat (odczyt dla funkcji z millis)
word autoExitCzas = 20000; // czas zwloi przed AUTOMATYCZNYM WYJSCIEM z menu, maksymalnie '65534' ms dla zmiennej typu 'word'

boolean d1 = 0; // do migajacej diody zapis
boolean d2 = 0; // do migajacej lampy sygnalizacyjnej

uint8_t wysw1LED[] = { 0x00, 0x00, 0x00, 0x00 };  //Dla LEDDispl4digit
uint8_t wysw2LED[] = { 0x00, 0x00, 0x00, 0x00 };

String wyspom1 [11]; // [znSpecPoczatku][c1p1][c2p1][c3p1][AL0/1][c1p2][c2p2][c3p2][liniaC1][liniaC2][znSpecKonca]

/* tabStrMenu  - przechowywanie poszczegolnych ustawien dla kolejnych stron, 0 - niewykozystane, 1 - nr czujnika powiazany z alarmem, 2 - dla 1 strony czyli ALARM, 3 - przechowywany numer LINII;
  mozna tez przypisac do stron przez 's-1' w linii funkci menu  */
int tabStrMenu[4];  //  dane ze stron/menu LED  // ilosc deklarowana = ilosc stron + 1; srtona 0 (case 0) nie przechowuje zadnej wartosci potrzebnej dla dzialaniaprogramu
int eepromOdczyt[4]; // i tak wartosci w tabeli [0] - braka odpowiednika dla pamieci EEPROM/miejsca 0 nie ma poprostu w EEPROM, [1] w tabeli odpowiada miejsce (1) w pamieci eeprom itd...
int i;

char AL;
char KOD; // zakodowane wartosci do wyslania Serial
byte first3loopForTX; //pierwsze 3 petle programu-odliczanie

//wyswietlanie segmentow dla ALc
const uint8_t disp_cznr[] = { // dalej w kodzie czujnik nr 1=in 2=out
  SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G ,            // A
  SEG_D | SEG_E | SEG_F,                                     // L
  SEG_D | SEG_E | SEG_G                                      // c
};

//wyswietlenie segmentow dla AL
const uint8_t disp_alarm[] = {
  SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G ,           // A
  SEG_D | SEG_E | SEG_F                                      // L
};

//wyswietlenie segmentow dla L
const uint8_t disp_linia[] = {
  SEG_D | SEG_E | SEG_F ,         // L
  SEG_C | SEG_E | SEG_G           // n
};

const uint8_t disp_done[] = {
  SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,           // d
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,   // O
  SEG_C | SEG_E | SEG_G,                           // n
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G            // E
};

const uint8_t disp_buzka[] = {
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G,           // 8  8-]
  SEG_G,                                                           // -
  SEG_A | SEG_B | SEG_C | SEG_D,                                   // ]
  0
};

const uint8_t disp_confirm[] = {
  SEG_A | SEG_D | SEG_E | SEG_F | SEG_G,   // e
  SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,   // d
  SEG_E | SEG_D,                           // i
  SEG_D | SEG_E | SEG_F | SEG_G            // t
};

void setup()
{
  digitalWrite(resetPin, HIGH);
  delay(200);
  pinMode(buttonOk, INPUT_PULLUP);
  pinMode(buttonMenu, INPUT_PULLUP);
  pinMode(buttonUp, INPUT_PULLUP);
  pinMode(buttonDn, INPUT_PULLUP);
  pinMode(automatSwPin, INPUT_PULLUP);
  pinMode(LEDzapisz, OUTPUT);
  digitalWrite(LEDzapisz, LOW);
  pinMode(ALprzekaznik, OUTPUT);
  digitalWrite(ALprzekaznik, LOW);
  pinMode(ALtempLED, OUTPUT);
  digitalWrite(ALtempLED, LOW);
  pinMode(resetPin, OUTPUT);



  display_1.setBrightness(0x0c); //LED7Seg jasnosc wys 1, ponizej 2
  display_2.setBrightness(0x0c);

  Serial.begin(9600);
  Serial1.begin(9600);  // inic. serial 1 do wysylania danych na esp8266

  
  if (EEPROM.read(1) > 2)  //warunek, jesli nr czujnika odczytany w EEPROM jest wiekszy niz 2 --zapisz wartosc domyslna 1
  {
    Serial.println("Zapisano domyslny numer czujnika dla alarmu");
    EEPROM.write(1, 1);
  }


  for (i = 1; i <= 3; i++) // ilosc stron = 3 w tym przypadku, to i komorek pamieci 3
  {
    tabStrMenu[i] = EEPROM.read(i); // i=1 alarm (sygnalizacja) przypisany dla czujnika 1 lub 2 (1= in, 2= out)
    // i=2 do testow domyslna wartosc dla alarmu, domyslnie pobierane z EEPROM do tabeli
    // i=3 domyslnie z eeprom - pobranie numeru linii do tabeli
    WhichScreen = 0; // aby menu startowalo od 1 str.
  }

  AL = '0'; // znacznik alarmu na znak 0

  first3loopForTX = 1; //pierwsze wysylanie danych po Serial'u od uruchomienie programu

  time0 = millis(); // rozpoczecie zliczania (dla trybu Nara praca automat)
  timeReset = millis(); // dla automatycznego restartu gdy jest blad Err

}


void loop()
{
  
  int airinCalkow;
  int airoutCalkow;


  stanAutoSwPin = digitalRead(automatSwPin); // odczytaj stan na pine - przekaznik w Narze
  if (stanAutoSwPin == !LOW)  // jesli wyl. automat..
    time0 = millis(); // nadpisuj zliczanie (zerowanie)

  // digitalWrite(40, HIGH); //do pomiaru na oscyloskopie czasu trwania "start pomiaru odczytu DS18B20"

  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  for (i = 1 ; i <= 3; i++)
  {
    eepromOdczyt[i] = EEPROM.read(i); //aktualnie zapisane w eeprom
    //   Serial.println("wartosci zapisane w komorkak EEPROM:");
    //   Serial.println(eepromOdczyt[i]);
  }


  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 
  // digitalWrite(40, LOW); //koniec pomiaru odczytu i przeliczenia na calkowita liczbe

  // CZ nr 1 odczyt konwersja

  // take N samples in a row, with a slight delay
  for (m = 0; m < NUMSAMPLES_1; m++) {
    samples_1[m] = analogRead(THERMISTORPIN_1);
    delay(10);
  }

  // average all the samples out
  average_1 = 0;
  for (m = 0; m < NUMSAMPLES_1; m++) {
    average_1 += samples_1[m];
  }
  average_1 /= NUMSAMPLES_1;

 // Serial.print("Average analog reading 1 (A0)");  //testy odczytu ntc
 // Serial.println(average_1);
  // convert the value to resistance
  average_1 = 1023 / average_1 - 1;
  average_1 = SERIESRESISTOR_1 / average_1;

 // Serial.print("Thermistor resistance 1");
 // Serial.println(average_1);

  float tempIn;
  tempIn = average_1 / THERMISTORNOMINAL_1;     // (R/Ro)
  tempIn = log(tempIn);                  // ln(R/Ro)
  tempIn /= BCOEFFICIENT_1;                   // 1/B * ln(R/Ro)
  tempIn += 1.0 / (TEMPERATURENOMINAL_1 + 273.15); // + (1/To)
  tempIn = 1.0 / tempIn;                 // Invert
  tempIn -= 273.15;                         // convert to C

 // Serial.print("Temperature 1  ");
 // Serial.print(tempIn);
 // Serial.println(" *C");

  // CZ nr 2 odczyt konwersja

  // take N samples in a row, with a slight delay
  for (n = 0; n < NUMSAMPLES_2; n++) {
    samples_2[n] = analogRead(THERMISTORPIN_2);
    delay(10);
  }

  // average all the samples out
  average_2 = 0;
  for (n = 0; n < NUMSAMPLES_2; n++) {
    average_2 += samples_2[n];
  }
  average_2 /= NUMSAMPLES_2;

 // Serial.print("Average analog reading 2 (A2)");
 // Serial.println(average_2);
  // convert the value to resistance
  average_2 = 1023 / average_2 - 1;
  average_2 = SERIESRESISTOR_2 / average_2;

 // Serial.print("Thermistor resistance 2 ");
 // Serial.println(average_2);

  float tempOut;
  tempOut = average_2 / THERMISTORNOMINAL_2;     // (R/Ro)
  tempOut = log(tempOut);                  // ln(R/Ro)
  tempOut /= BCOEFFICIENT_2;                   // 1/B * ln(R/Ro)
  tempOut += 1.0 / (TEMPERATURENOMINAL_2 + 273.15); // + (1/To)
  tempOut = 1.0 / tempOut;                 // Invert
  tempOut -= 273.15;                         // convert to C

 // Serial.print("Temperatura 2 ");
 // Serial.print(tempOut);
 // Serial.println(" *C");

  airinCalkow = tempIn * 100; //pozbycie sie kropki w wyniku pomiaru xx.xx
  airoutCalkow = tempOut * 100; //podobnie dla drugiego pomiaru
  comTempIN = (tempIn + 30) * 100; //pozbycie sie kropki w wyniku pomiaru xx.xx
  comTempOut = (tempOut + 30) * 100; //podobnie dla drugiego pomiaru

//obsluga wyswietlania pierwszego wyswietlacza dla czujnika 1 ,szczegulna uwage nalezy zwrocic na prawidlowe odwolanie sie do uint, i display

// digitalWrite(44, HIGH);      //start wyswietlanie wartosci na led_tm1637 - testy oscyloskop

// uwaga.. zamiana ulamka na calkowite i przez dodanie do wyniku +30 pozbycie sie ewentualnego znaku MINUS ; dodanie +48 dla znaku ASCI

char ti1 = comTempIN / 1000 % 10 + 48; //dodanie 48 by uzyskac znak typu char
char ti2 = comTempIN / 100 % 10 + 48;
char ti3 = comTempIN / 10 % 10 + 48;
char to1 = comTempOut / 1000 % 10 + 48; // L_._ dziesiatki
char to2 = comTempOut / 100 % 10 + 48; // _L._ jednosci
char to3 = comTempOut / 10 % 10 + 48; // __.L cz.dziesietne



//jesli  odczyt EEPROM nr czuj=1 i temp wej >= odczyt EEPROM dla temp alarmu  'lub'
if (eepromOdczyt[1] == 1 && airinCalkow >= eepromOdczyt[2] * 100 || eepromOdczyt[1] == 2 && airoutCalkow >= eepromOdczyt[2] * 100)
{
  AL = '1';
  digitalWrite(ALtempLED, HIGH); //aktywacja diody sygnalizujacej o przekroczeniu temp max , takze  praca maszyny w Automacie
  if (millis() - time0 > zwlokaPrzekazAL)
  {
    if (millis() - time0blink > 1250)
    {
      d2 = !d2;
      time0blink = millis();
    }

    if (d2)  {
      digitalWrite(ALprzekaznik, HIGH); //aktywacja przekaznika sygnalizacji alarmu po 5 min od wykrycia pracy w automacie
    }
    else
    {
      digitalWrite(ALprzekaznik, LOW);
    }

  }
  else
  {
    digitalWrite(ALprzekaznik, LOW);
  }
}
else
{
  AL = '0';
  digitalWrite(ALprzekaznik, LOW); // brak alarmu - wylacz przekaznik, diode sygn.
  digitalWrite(ALtempLED, LOW);
}


char Ln1 = eepromOdczyt[3] / 10 % 10 + 48; // 1 cyfra nr linii --dodanie 48 by uzyskac znak typu char
char Ln2 = eepromOdczyt[3] % 10 + 48; //2 cyfra nr linii


//  digitalWrite(44, LOW); //koniec pomiaru czasu funkcji wyswietlania na 2 szt modulu LED wyswietlacz tm1637 //pomiar na oscyloskopie

/*kodowanie Alarmu i pracy nary w Auto/Recznym

   wyspom1[4] = KOD  jesli kod pryjmuje wartosc 0 - tryb autom. | brak alarmu
                                                1 - tryb autom. | alarm!
                                                2 - tryb reczny/wyl | brak alarmu
                                                3 - tryb reczny/wyl | alarm!
                                                na kod sklada sie AL i stanAutoSwPin (LOW = tryb autom)
*/
if (AL == '0' && stanAutoSwPin == LOW)
{
  KOD = '0'; // brak alarmu, praca automat
}

if (AL == '1' && stanAutoSwPin == LOW)
{
  KOD = '1';
}

if (AL == '0' && stanAutoSwPin == HIGH)
{
  KOD = '2';
}

if (AL == '1' && stanAutoSwPin == HIGH)
{
  KOD = '3';
}

char wyspom1 [11]; // [znspec][c1p1][c2p1][c3p1][AL0/1][c1p2][c2p2][c3p2][liniaC1][liniaC2][znSpecKonca]
//char wyspom2 [5];

wyspom1[0] = 0x7B; //zn specj nadawania
wyspom1[1] = ti1; //odpowiada za dziesiatki 1 pomiaru
wyspom1[2] = ti2; //odpowiada za jednosci 1 pomiaru
wyspom1[3] = ti3; //odpowiada za czasci dziesietne 1 pomiaru, czyli po kropce
wyspom1[4] = KOD;  //czy aktywny alarm?? temperatury: 0 nie,  1 tak
wyspom1[5] = to1; //odpowiada za dziesiatki 2 pomiaru
wyspom1[6] = to2; //odpowiada za jednosci 2 pomiaru
wyspom1[7] = to3; //odpowiada za czasci dziesietne 2 pomiaru, czyli po kropce
wyspom1[8] = Ln1; // 1. cyfra nr linii
wyspom1[9] = Ln2; // 2. cyfta nr linii
wyspom1[10] = 0x7D; // znak specj zakonczenia nadawania

/* konfiguraca przycisku Menu */
if (digitalRead(buttonMenu) == LOW && pokazMenu == 0) // sprawdza czy na pinie 33 stan LOW niski, jesli tak to ..
{
  pokazMenu = 1; //uruchamia Menu
  delay(15);
}


// komunikacja

if (wyspom1[1] != '0' && wyspom1[2] != '0' && wyspom1[3] != '0' || first3loopForTX >= 3)
  // podczas startu programu na plytce  wartosci sa rowne 0 0 0 , jesli wartosci sa inne to wysyla na SERIAL dane
{
  Serial1.write(wyspom1, 11); // wysyla paczke do drugiego urzadzenia na Serial nr (serial1)

  Serial.println("na com");
  for (int j = 0; j < 11; j++)
  {
    Serial.print(wyspom1[j]);
  }
  Serial.println(" ");
}
else
{
  Serial.println("! blad wartosci do wyslania lub wykonanie petli 'loop' mniej niz 3 razy od starcie!");
  if (first3loopForTX < 3) //dodaje 1 do czasu wykonania 3co najmniej 3 petli
  {
    first3loopForTX++;
  }
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


// kontrolka o nie zapisaniu do pamieci parametrow z menu.
if (eepromOdczyt[1] != tabStrMenu[1] || eepromOdczyt[2] != tabStrMenu[2] || eepromOdczyt[3] != tabStrMenu[3]) // kontrolka miga dla braku zapisu nr czujnika
{
  if (millis() - time1 > 250)
  {
    d1 = !d1;
    time1 = millis();
  }
}

if (d1)  
{
  digitalWrite(LEDzapisz, HIGH);
}
else
{
  digitalWrite(LEDzapisz, LOW);
}


if (eepromOdczyt[1] == tabStrMenu[1] && eepromOdczyt[2] == tabStrMenu[2] &&  eepromOdczyt[3] == tabStrMenu[3]) // " && AL != '1' " do testu przekaznika podczas alarmu , sygnalizacja na LED pin 13
{
  digitalWrite(LEDzapisz, LOW);
}


// jesli (domyslnie na starcie) mamy 0 to wykonaj program, wlasciwy..czy tez ten ktory ma sie glownie wykonywac

if (pokazMenu == 0) {    //GLOWNY PROGRAM

  //poczatek gl prog

  if ( airinCalkow < -9900  || airinCalkow == 0)
  {
    wysw1LED[0] = (SEG_A | SEG_D | SEG_E | SEG_F | SEG_G); // E
    wysw1LED[1] = (SEG_E | SEG_G); // r
    wysw1LED[2] = (SEG_E | SEG_G); // r
    wysw1LED[3] = display_1.encodeDigit(1); // 1
    display_1.setSegments(wysw1LED); // Err1

    actErr1 = 1;
  }
  else
  {
    wysw1LED[0] = display_1.encodeDigit(airinCalkow / 1000 % 10); //wyswietla cyfre dziesiatek z pomiaru cz.1 na wyswietlaczu pierwszym
    wysw1LED[1] = display_1.encodeDigit(airinCalkow / 100 % 10); //wyswietla cyfre jednosci z pomiaru cz.1 na wyswietlaczu pierwszym
    wysw1LED[2] = (SEG_A | SEG_B | SEG_F | SEG_G); // znak stopni zamiast kropki ktore brak w wyswietlaczu ktory posiadam
    wysw1LED[3] = display_1.encodeDigit(airinCalkow / 10 % 10); //pierwsza cyfra czesci dziesietnych

    actErr1 = 0;
  }

  //obsluga wyswietlania drugiego wyswietlacza dla czujnika 2
  if (airoutCalkow < -9999 || airoutCalkow == 0)
  {
    wysw2LED[0] = (SEG_A | SEG_D | SEG_E | SEG_F | SEG_G); // E
    wysw2LED[1] = (SEG_E | SEG_G); // r
    wysw2LED[2] = (SEG_E | SEG_G); // r
    wysw2LED[3] = display_2.encodeDigit(2); // 2
    display_2.setSegments(wysw2LED); // Err2

    actErr2 = 1;
  }
  else
  {
    wysw2LED[0] = display_2.encodeDigit(airoutCalkow / 1000 % 10); //wyswietla cyfre dziesiatek z pomiaru cz.1 na wyswietlaczu pierwszym
    wysw2LED[1] = display_2.encodeDigit(airoutCalkow / 100 % 10); //wyswietla cyfre jednosci z pomiaru cz.1 na wyswietlaczu pierwszym
    wysw2LED[2] = (SEG_A | SEG_B | SEG_F | SEG_G); // znak stopni zamiast kropki ktore brak w wyswietlaczu ktory posiadam
    wysw2LED[3] = display_2.encodeDigit(airoutCalkow / 10 % 10); //pierwsza cyfra czesci dziesietnych
    //      display_2.setSegments(wysw2LED); // wyswietlenie  temperatury na pierwszym wyswietlaczu

    actErr2 = 0;
  }


  if (millis() - time2 >= 125) // co 125ms odswierzenie wyswietlaczy
  {
    display_1.setSegments(wysw1LED); // wyswietlenie  temperatury na pierwszym wyswietlaczu
    display_2.setSegments(wysw2LED);
    time2 = millis();
  }

  // koniec glownej czesci programu ***************************

  
  hasChanged = true; // ustawiam na true, aby po wlaczeniu na menu pojawila sie na wyswietlaczu strona ustawien, bez tego zostaje zamrozony wynik ostatniego pomiaru z wejscia analogowego

  if (actErr1 == 1 || actErr2 == 1)
  {
    if (millis() - timeReset > zwlokaReset)
      digitalWrite(resetPin, LOW);
  }
  else
  {
    timeReset = millis();
    digitalWrite(resetPin, HIGH);
  }
}
else // jesli zmienna pokazMenu ma wartosc inna niz zero.. w tym wypadku tylko moze byc to 1 wykonaj.. wyswietlenie menu
{
  int s = WhichScreen;  // UWAGA! nalezy zadeklarowac tablice o liczbie elementow nie mniejszej niz ilosc stron.

  /* konfiguraca przycisku Up/gora */
  if (digitalRead(buttonUp) == LOW && WhichScreen == s) // zmiana parametrow UP/dodaj
  {
    //Serial.print("UP dla strona nr :");
    //Serial.println(WhichScreen);
    if (WhichScreen == s)
    {

      if (tabStrMenu[s] < 99 &&  s != 1) // gorna granica wyboru 99, oprocz  strony dla nr czujnika gdzie max to 2.
      {
        tabStrMenu[s]++; //dodaj o jeden wiecej
      }

      if (s == 1 && tabStrMenu[s] < 2) // gorna granica wyboru 99, oprocz  strony dla nr czujnika gdzie max to 2.
      {
        tabStrMenu[s]++; //dodaj o jeden wiecej
      }

      autoExitMenu = millis(); // zerowanie braku aktywnosci w menu
      hasChanged = true; //odswierza wyswietlacz LED
      delay (20);
    }
  }

  /* konfiguraca przycisku dol/minus */
  if (digitalRead(buttonDn) == LOW && WhichScreen == s) // zmiana parametrow DOWN/odejmij
  {
    if (WhichScreen == s)
    {
      if (tabStrMenu[s] > 1) //
      {
        tabStrMenu[s]--;
      }
      autoExitMenu = millis(); // zerowanie braku aktywnosci w menu
      hasChanged = true;
      delay(20);
    }
  }

  /* konfiguracja przycisku Ok/Zapisz */
  if (digitalRead(buttonOk) == LOW && WhichScreen == s && WhichScreen > 0) // od strony 1 zapis do komorki 's' = stronie
  {
    if (WhichScreen == s)
    {
      if (eepromOdczyt[s] == 255) //warunek gdy wartosc domyslna wynosi 255 (nowa plytka nie nadpisywana pamiec) uzyj polecenia zapisz WRITE
      {
        EEPROM.write(s, 35); // zapisyj na wartosc domyslna alarmu / linii produ. na: 35
        tabStrMenu[s] = eepromOdczyt[s]; // uaktualnienie wpisanej wartosci z pamieci do tablicy wyswietlajacej
        display_1.setSegments(disp_done);
        Serial.println("\n nadpisano po raz PIERWSZY \n strona i komorka nr:");
        Serial.println(s);
        hasChanged = true;
        digitalWrite(LEDzapisz, LOW);
        digitalWrite(LEDzapisz, HIGH);
        delay(75);
        digitalWrite(LEDzapisz, LOW);
        delay(50);
        digitalWrite(LEDzapisz, HIGH);
        delay(75);

      }
      else
      {
        if (eepromOdczyt[s] != tabStrMenu[s])
        {
          EEPROM.update(s, tabStrMenu[s]);
          Serial.println("uaktualniono wartosc w pamieci...");
          display_1.setSegments(disp_done);
          digitalWrite(LEDzapisz, HIGH);
          display_2.setSegments(disp_buzka);
          hasChanged = true;
          delay(1300);
          digitalWrite(LEDzapisz, LOW); //wygasza diode zapisu
          display_2.clear();
          hasChanged = true;
        }
      }
      autoExitMenu = millis(); // zerowanie braku aktywnosci w menu
      hasChanged = true;
      delay (25);
    }
  }

  if (millis() - autoExitMenu > autoExitCzas) //warunek wyprowadza z menu, jesli brak aktywnosci podana ilosc czasu (ms)
  {
    for (int k = 1; k <= 3; k++) //dla stron 1-3 (LNr, czNr, alTemp) przywrocenie ustawien domyslnych jesli roznia sie od nastawionych i zapisanych w eeprom, oraz wyl diody sygnalizacyjnej 'zapisz'
      if (eepromOdczyt[k] != tabStrMenu[k])
        tabStrMenu[k] = eepromOdczyt[k];
    pokazMenu = 0;
    digitalWrite(LEDzapisz, LOW);
    autoExitMenu = millis();
  }

  if (hasChanged == true)
  {
    switch (WhichScreen) {
      case 1:
        {
          firstScreen();
        }
        break;

      case 2:
        {
          secondScreen();
        }
        break;


      case 3:
        {
          thirdScreen();
        }
        break;




      case 4:
        {

          /* Dzieki temu warunkowi, bedac na OSTATNIEJ wyswietlanej stronie,
            jesli wprowadzimy modyfikacje parametrow na ktorejs ze stron, i nie zapiszemy ich
            przy wychodzeniu z menu zostana przywrocone domyslne wartosci zapisane w eeprom.
            kontrolka od zapisu gasnie.
          */
          for (i = 1 ; i <= 3; i++)
            if (eepromOdczyt[i] != tabStrMenu[i])
            {
              tabStrMenu[i] = eepromOdczyt[i];
            }
          autoExitMenu = millis(); // zerowanie braku aktywnosci w menu
          pokazMenu = 0; //wracamy do wyswietlania z glownej pętli funkcji
        }
        break;

      /* Dla wiekszej ilosci wyswietlania pozycji menu


        case 5:
        {
        fifthScreen();
        }
        break;

        case 6:
        {
        sixthScreen();
        }
        break;
      */

      case 0:  //konczacy zapis menu
        {

        }
        break;
    }

  }

  //-------------------------------
  // BEGIN of the switch debouncing code
  int reading = digitalRead(buttonMenu);
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        hasChanged = true;
        WhichScreen++;


      }
    }
    else
    {
      hasChanged = false;
    }
  }
  lastButtonState = reading;
  // END of the switch Debouncing code
  // --------------------------------------
  if (WhichScreen > 4) { //ilosc wszystkich stron  ..doliczamy tez ta wracajaca do pierwotnej funkcji wykonywania
    WhichScreen = 1;
  }
 }
}  // KONIEC void loop() !!;  #################################################




void firstScreen()  // pierwsza strona opcji // nr czujnika dla alarmu
{

  display_1.setSegments(disp_cznr, 3, 0); // wyswietla wartosc cz1 lub czujnik 2, w zaleznosci ile ich podlaczymy
  display_1.showNumberDec(tabStrMenu[1], false, 1, 3);  //wyswietla graniczna temp. alarmu
  if (tabStrMenu[1] != eepromOdczyt[1])
  {
    display_2.setSegments(disp_confirm); // wyswietlenie  Edit na drugim wyswietlaczu w menu
  }
  else
  {
    if (millis() - time2 > 100)
    {
      //        display_1.clear();
      display_2.clear();
      time2 = millis();
    }
  }


}

void secondScreen() // druga str opcji itd itp
{

  // display_1.clear();  //konieczne by nie nakladaly sie na siebie znaki/liczby z poprzedniego menu
  display_1.setSegments(disp_alarm, 2, 0);
  display_1.showNumberDec(tabStrMenu[2], false, 2, 2);  //wyswietla graniczna temp. alarmu

  if (tabStrMenu[2] != eepromOdczyt[2])
  {
    display_2.setSegments(disp_confirm);
  }// wyswietlenie  Edit na drugim wyswietlaczu w menu
  else
  {
    if (millis() - time2 > 100)
    {
      //        display_1.clear();
      display_2.clear();
      time2 = millis();
    }
  }
}

void thirdScreen() // trzecia  str opcji itd itp
{

  display_1.showNumberDec(tabStrMenu[3], false, 2, 2); // wartosc przechowywana dla Nr Linii
  // display_1.showNumberDecEx(tabStrMenu[3],0, true); // wartosc przechowywana dla Nr Linii
  display_1.setSegments(disp_linia, 2, 0);
  if (tabStrMenu[3] != eepromOdczyt[3])
  {
    display_2.setSegments(disp_confirm); // wyswietlenie  Edit na drugim wyswietlaczu w menu
  }
  else
  {
    if (millis() - time2 > 100)
    {
      //        display_1.clear();
      display_2.clear();
      time2 = millis();
    }
  }
}
/*

  dla większej ilosci przejsc miedzy wyswietlanymi informacjami, ponizej rozpiska dla wyswietlacza LCD !!!

  void fourthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("This is screen 4");
    lcd.setCursor(0,1);
    lcd.print("Just press btn");
  }
  void fifthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("   Fifth screen");
    lcd.setCursor(0,1);
    lcd.print("i2C LCD screen");
  }
  void sixthScreen()
  {
    lcd.clear();
    lcd.setCursor(0,0); // Column, line
    lcd.print("THE last screen");
    lcd.setCursor(0,1);
    lcd.print("  Sixth and last");
  }
*/

 

Odbiór danych z MEGA2560 i przesłanie do serwera danych.

ESP8266-12E

#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>


/*     SSS                                                L            K       (2019)
      S       ZZZZ    CCC   ZZZZ    EEE   PPPP    U   U   L      EEE   K   K
       SSS      Z    C        Z    E___   P   P   U   U   L     E___   K K
          S    Z     C       Z     E      P   P   U   U   L     E      K  K
      SSSS    ZZZZ    CCC   ZZZZ    EEE   PPPP     UUU     LL    EEE   K   K
                                          P
    KOMUNIKACJA PO SERIALU (SOFTWARE) //ESP8266
    Do komunikacji wykorzystano Nadawanie TX Arduino Mega 2560, odbior na ESP8266-12E
    Na Mega 2560 uzyto Serial1, mozna uzyc serial2, czy serial3. Na ESP piny 2-oraz 3.
    WAZNE !!! nie zapomnijcie polaczyc ze soba GND obu plytek.
    u mnie dziala to dobrze. Przy nadawaniu temperatura jest zamieniana na liczbe calkowita bez przecinka/kropki poprzez
    pomnozenie przez 100 wyniku pomiaru. By uniknac zmiany dlugosci wysylanych danych przy ujemnych temperaturach,
    do wyniku dodaje 30 stopni, ktore przy pozniejszemu dekodowaniu na odbiorniku odejmuje (te 30st.),
    Dzieki temu zabiegowi temperatura np 22.50 st.C, zamienione na calkowite ma wartosc 2250. a po dodaniu wczesniej
    do pomiaru 30 ma wartosc 5250. I do wysylania potrzebne sa 4 bajty.
    Bez tego wartosc -23.00 st.C po pomnozeniu ma wartosc -2300 czyli ze znakiem minusa mamy 5 bajtow.
    Po dodaniu do pomiaru 30 st mamy 13 st (-23+30= 13) podsumowujac, minimalna temp przesylana bez bledu dekodowania/
    odczytu/ to temperatura  -29.50, natomiast maksymalna to 69.50 (bo 70.00+ 30 = 100, po pomnozeniu przekracza 4 bajty)
    Może i to  rozwiązanie mocno AMATORSKIE, ale działa :) teraz można ulepszac kod i przeksztalcac..
*/
#define D7 (13) //LED wysylam
#define D8 (15) // Led_Error
#define D5 (14) //rx odbior danych

/*
  SoftwareSerial mySerial; //rx pin 2,  tx pin 3
*/

// WIFI ##################################################
const char* ssid     = "ssidTwojejSieciWiFi";
const char* password = "hasloDoSieci";
const char* host = "192.168.1.111"; // Host , adres bazy danych

int automatPraca; // stan nary, pobierana informacja z SERIAL (Mega 2560) //sprawdzanie czy maszyna w trybie automatycznym (zwarty PIN16 do maszy)


//unsigned long timeTrybAuto = 0;
unsigned long timeAddDB = 0; //wysylaj po okreslonym czasie dane pobrane z SoftwareSerial do bazy danych
unsigned long czasAutomatPraca;
unsigned long timeErr;

SoftwareSerial mySerial(14, SW_SERIAL_UNUSED_PIN);

char buff[11]; //Initialized variable to store recieved data // bufor na odbierane dane, w moim przypadku 11 znaków do odbioru
byte count;
float tempOdczyt1;
float tempOdczyt2;
unsigned long czasDoWyslania; //ilosc czasu ( ms) po jaki wysylane sa pomiary temp do bazy danych
int ALOdczyt;
char KOD;
int PracaAutoOdczyt;
int LnOdczyt;
char ALmysql;

void setup ()
{
  czasDoWyslania = 300000;
  czasAutomatPraca = 0;
  timeAddDB = millis();
  PracaAutoOdczyt = 1;
  pinMode(D8, OUTPUT); // LED zolta - error
  pinMode(D7, OUTPUT); //  LED niebieska panelu - wysyłanie

  delay(1000);
  // Open serial communications and wait for port to open:
  Serial.begin(9600);

  Serial.println("Start");
  mySerial.begin(9600);

  // Start laczenia sie do wifi
  Serial.println();
  Serial.println();
  Serial.print("polacz z siecia ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi polaczone");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());


}

void loop()
{
  buff[0] = 0; //proba


  if (mySerial.available() > 0)
  {
    buff[0] = mySerial.read(); //
    if (buff[0] == 0x7B) //sprawdza czy pierwszy bajt jest poprawny i jest to znak 0x7B (HEX) czyli "{"
      count = 1;

    while (count < 11)
      if (mySerial.available() > 0) // jesli transmisja na serial software aktywna przechodzi dalej.
      {
        buff[count] = mySerial.read(); //odczyt z serial software
        count++;
      }

    // 0x7D znak specjalny konczacy, 0x65 ('A') znak konczacy podczas pracy w AUTOMACIE
    if (count == 12 && buff[10] == 0x7D ) // kontrola ostatniego bajtu/znaku (9 znak), w przypadku prawidłowego znaku kontynuacja
    {
      for (byte i = 0; i < 11; i++) //zapisujemy do tabeli buff kolejne znaki odebrane
      {
        Serial.print(buff[i]);
        Serial.print(",");
      }
    }
  }

  if (buff[0] == 0x7B && buff[10] == 0x7D)
  {


    // [0] zn spec 0x7b, [1]- ti1,  ti2,  AL,  to1,  to2,  to3,  Ln1,  Ln2,  zn spec 0x7d
    Serial.println();
    Serial.println("T1:");
    //float
    tempOdczyt1 = (((buff[1] - 48) * 100) + ((buff[2] - 48) * 10) + ((buff[3] - 48) + 0.001)) / 10 - 30;
    Serial.println(tempOdczyt1);

    KOD = buff[4];

    Serial.println("kod to:");
    Serial.println(KOD);
    // KOD (ALOdczyt) - rozszyfrowanie
    if (KOD == '0')
    {
      ALOdczyt = 0;
      PracaAutoOdczyt = 1;
    }
    if (KOD == '1')
    {
      ALOdczyt = 1;
      PracaAutoOdczyt = 1;
    }
    if (KOD == '2')
    {
      ALOdczyt = 0;
      PracaAutoOdczyt = 0;
    }
    if (KOD == '3')
    {
      ALOdczyt = 1;
      PracaAutoOdczyt = 0;
    }

    Serial.println("AL:");
    //int
    Serial.println(ALOdczyt);

    Serial.println("Nara w tr.Auto:");

    Serial.println(PracaAutoOdczyt);


    Serial.println("T2:");
    //float
    tempOdczyt2 = (((buff[5] - 48) * 100) + ((buff[6] - 48) * 10) + ((buff[7] - 48) + 0.001)) / 10 - 30;
    Serial.println(tempOdczyt2);

    Serial.println("LiniaNR:");
    //int
    LnOdczyt = (((buff[8] - 48) * 10) + (buff[9] - 48));
    Serial.println(LnOdczyt);

    Serial.println("dane gotowe do wysłania..");


    czasAutomatPraca = millis() - timeAddDB; // czas pracy w automatycznym trybie
    Serial.println(czasAutomatPraca);


   if (czasAutomatPraca > czasDoWyslania && PracaAutoOdczyt == 1) //  wysylanie po okreslonym czasie pod warunkiem ze w automacie maszyna
    {
      if (-50 < tempOdczyt1 < 90 && -50 < tempOdczyt2 < 90 && LnOdczyt < 100)  // pomin esli wykracza poza zakres
        {  
          // Dane na serwer !
          Serial.print("connecting to ");
          Serial.println(host);
     digitalWrite(D8, LOW);
          // Use WiFiClient class to create TCP connections
          WiFiClient client;
          const int httpPort = 80;
          if (!client.connect(host, httpPort)) {
             digitalWrite(D8, HIGH);
            Serial.println("connection failed");
            
          if (czasAutomatPraca > 1.25*czasDoWyslania)
            timeAddDB = millis();
            
            return;
          }
          digitalWrite(D7, HIGH); //LED kontrolny na panelu, informacja  poczatek transmisji
    
          // tworzenie zapytania do URL
          String url = "/wyslijpomiar.php?"; //jest to strona na serwerze sluzaca do wysylania poprzez GET parametrow temp itp do bazy danych poprzez INSERT zagniezdzony w kodzie zrodlowym pliku wyslijpomiar.php
    
    
          // Send request
          Serial.print("Requesting URL: ");
          Serial.println(url);
          if (ALOdczyt == 0) // wysylanie odczytanych z seriala wartosci na serwer, jesli bra alarmu nie podajemy zadnych parametrow dla &alarm=  wtedy bedzie umieszczony bit 0 w bazie.
          {
            client.print(String("GET ") + url + "linia_nr=" + LnOdczyt + "&temperatura1=" + tempOdczyt1 + "&temperatura2=" + tempOdczyt2 + "&alarm=" + " HTTP/1.1\r\n" +
                         "Host: " + host + "\r\n" +
                         "Connection: close\r\n\r\n");
          }
          else
          {
            client.print(String("GET ") + url + "linia_nr=" + LnOdczyt + "&temperatura1=" + tempOdczyt1 + "&temperatura2=" + tempOdczyt2 + "&alarm=1" + " HTTP/1.1\r\n" +
                         "Host: " + host + "\r\n" +
                         "Connection: close\r\n\r\n");
          }
    
          unsigned long timeout = millis();
          while (client.available() == 0) {
            if (millis() - timeout > 5000) {
               digitalWrite(D8, HIGH);
              Serial.println(">>> Client Timeout !");
              client.stop();
              return;
            }
          }
    
          // Read all the lines from the answer
          while (client.available())
          {
            String line = client.readStringUntil('\r');
            Serial.print(line);
          }
    
          // Close connecting
          Serial.println();
          Serial.println("zamyanie polaczenia");
    
          timeAddDB = millis(); // zapis obecnego czasu  pracy procesora, ponowne zliczanie czasu dla wyslania danych do bazy
        }

    }

    digitalWrite(D7, LOW); //led koniec transmisji

  }


  for (int j = 0 ; j > 11; j++)
  {
    buff[j] = 0;
  }

  Serial.println("czekam..");

 if (PracaAutoOdczyt == 0)
  timeAddDB = millis();
}

 

Teraz zapis poprzez PHP do serwera:

plik w katalogu serwera WWW o nazwie  wyslijpomiar.php  a w nim,

<?php
session_start();
$host = "localhost";
//$id_user=$_SESSION['pomiary'];
$username="pomiary";
$password="hasloTwoje";
$database="naratemperatury";
$polaczenie = @new mysqli($host,$username,$password,$database);
if($polaczenie->connect_errno!=0) //sprawdza czy nawiazano polaczenie
{
echo "Error ".$polaczenie->connect_errno; //blad gdy polaczenie nie nawiazane
}
else
{
  //wstawiamy przez GET który mamy skonf też w kodzie dla ESP8266 parametry wartości pomiarów
if($polaczenie->query("INSERT INTO pomiary (id, data, linia_nr, temperatura1, temperatura2, temperatura3, alarm) VALUES (NULL, NULL, '$_GET[linia_nr]','$_GET[temperatura1]','$_GET[temperatura2]',NULL,'$_GET[alarm]')"))

		{
			echo "udalo sie";
		}
		else
		{
			echo "nie udalo sie";
			
		}


$polaczenie->close(); //konczy polaczenie
}
?>

Wynik wyświetlanych danych z bazy danych przez PHP i w programie .exe (Delphi), struktura tabeli w MySQL; w załącznikach

 

struktura mysql.png

tabela.png

wykres i tabela.jpg

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...