Skocz do zawartości

Menu 6 czujników DS18B20 na LCD 2x16 na Arduino


Tom5e

Pomocna odpowiedź

Witajcie,

Jest to mój pierwszy pogram (tak naprawdę posiłkowałem się gotowymi przykładami) na Arduino. Wcześniej nie miałem styczności z programowaniem więc jest to dla mnie dość skomplikowane. Udało mi się stworzyć poniższy program który pokazuje 6 pomiarów temperatury (na razie podłączone są fizycznie dwa czujniki), każdy na innym ekranie przełączanymi dwoma przyciskami. Działa to całkiem nieźle ale zauważyłem, że podczas przełączania w określonym momencie program jakby się zawiesza i nie można zmienić ekranu na następny. Na początku filmiku słychać,że wciskam przycisk,a ekran się nie zmienia. Dzieje się tak po około sekundzie po zmianie ekranu (taki jest czas między pomiarami temperatury). Tak jakby w momencie pomiaru temperatury Arduino blokowało się. Pod koniec filmiku przełączam ekrany bardzo szybko i tu nie ma problemu z przełączaniem.

  1. Czy ktoś może wie co jest przyczyną tego blokowanie się Arduino? Czy to możliwe aby odczyt pomiaru z DS18B20 tak obciążał procesor mimo, że pomiar ma trwać tyko jedną milisekundę. A może to błędny kod? 
  2. Standardowy problem z odczytem temperatury. Czasami pokazuje temperaturę -127 lub +85 stopni. Nie znalazłem konkretnej odpowiedzi dlaczego tak się dzieje i jak to rozwiązać. Może ktoś już do tego dotarł? 
  3. Czy według was ten kod jest prawidłowy? Czy można uprościć ten kod i pozbyć się tych if przy przyciskach i zmianie ekranów? Jak zrobić aby pomiar temperatury był wykonywany raz na sekundę? 

Z góry dziękuje za odpowiedzi. 

#include <Wire.h>   // standardowa biblioteka Arduino
#include <LiquidCrystal_I2C.h> // dolaczenie pobranej biblioteki I2C dla LCD
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 2
#define TEMPERATURE_PRECISION 11 //Rozdzielczosc czujnika

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensor(&oneWire);
LiquidCrystal_I2C lcd(0x27, 16, 2); //LiquidCrystal_I2C lcd(0x3f, 16, 2);

int upButton = 11;
int downButton = 12;
int menu =2;

unsigned long aktualnyCzas = 0; 
unsigned long zapamietanyCzasWyswietlacz1 = 0;
unsigned long zapamietanyCzasWyswietlacz2 = 0;
unsigned long zapamietanyCzasWyswietlacz3 = 0;
unsigned long zapamietanyCzasWyswietlacz4 = 0;
unsigned long zapamietanyCzasWyswietlacz5 = 0;
unsigned long zapamietanyCzasWyswietlacz6 = 0;

void setup()
{
  lcd.init();
  lcd.backlight();
  lcd.setBacklight(HIGH);
  pinMode(upButton, INPUT_PULLUP);
  pinMode(downButton, INPUT_PULLUP);
  sensor.begin();      
}  
void loop()
{   
 if (digitalRead(upButton)==LOW){
    lcd.clear();
    menu=menu+1;
 while (digitalRead(upButton)==LOW);
  }
 if (digitalRead(downButton)==LOW){  
    lcd.clear();
    menu=menu-1;
    while (digitalRead(downButton)==LOW);
} 
  if (menu==2)
  {    
    Temp1(); 
  } 
 if (menu==1)
  {
    (menu=7);
  }
  if (menu==3)
  {
    Temp2();   
  }
  if (menu==4)
  {
    Temp3();    
  }
  if (menu==5)
  {
    Temp4();   
  }
  if (menu==6)
  {
    Temp5();    
  }
  if (menu==7)
  {
    Temp6();   
  }
  if (menu==8)
  {
    menu=2;   
  }
}
void Temp1()
{
    aktualnyCzas = millis();
  if(aktualnyCzas - zapamietanyCzasWyswietlacz1 >= 1000)
   {
    zapamietanyCzasWyswietlacz1 = aktualnyCzas;
    sensor.requestTemperatures();
    lcd.setCursor(4,0);
    lcd.print("Pomiar 1");
    lcd.setCursor(3,1);
    lcd.print(sensor.getTempCByIndex(0));
    lcd.setCursor(9,1);
    lcd.print("st.C"); 
   }
  else if (aktualnyCzas - zapamietanyCzasWyswietlacz1 >= 1) 
   {
    lcd.setCursor(4,0);
    lcd.print("Pomiar 1"); 
   }  
}
void Temp2()
{
    aktualnyCzas = millis();
  if(aktualnyCzas - zapamietanyCzasWyswietlacz2 >= 1000)
   {
    zapamietanyCzasWyswietlacz2 = aktualnyCzas;
    sensor.requestTemperatures();
    lcd.setCursor(4,0);
    lcd.print("Pomiar 2");
    lcd.setCursor(3,1);
    lcd.print(sensor.getTempCByIndex(1));
    lcd.setCursor(9,1);
    lcd.print("st.C"); 
   }
  else if (aktualnyCzas - zapamietanyCzasWyswietlacz2 >= 1) 
   {
    lcd.setCursor(4,0);
    lcd.print("Pomiar 2"); 
   }  
}
void Temp3()
{
    aktualnyCzas = millis();
  if(aktualnyCzas - zapamietanyCzasWyswietlacz3 >= 1000)
   {
    zapamietanyCzasWyswietlacz3 = aktualnyCzas;
    sensor.requestTemperatures();
    lcd.setCursor(4,0);
    lcd.print("Pomiar 3");
    lcd.setCursor(3,1);
    lcd.print(sensor.getTempCByIndex(0));
    lcd.setCursor(9,1);
    lcd.print("st.C"); 
   }
  else if (aktualnyCzas - zapamietanyCzasWyswietlacz3 >= 1) 
   {
    lcd.setCursor(4,0);
    lcd.print("Pomiar 3"); 
   }  
}
void Temp4()
{
    aktualnyCzas = millis();
  if(aktualnyCzas - zapamietanyCzasWyswietlacz4 >= 1000)
   {
    zapamietanyCzasWyswietlacz4 = aktualnyCzas;
    sensor.requestTemperatures();
    lcd.setCursor(4,0);
    lcd.print("Pomiar 4");
    lcd.setCursor(3,1);
    lcd.print(sensor.getTempCByIndex(1));
    lcd.setCursor(9,1);
    lcd.print("st.C"); 
   }
  else if (aktualnyCzas - zapamietanyCzasWyswietlacz4 >= 1) 
   {
    lcd.setCursor(4,0);
    lcd.print("Pomiar 4"); 
   }  
}
void Temp5()
{
    aktualnyCzas = millis();
  if(aktualnyCzas - zapamietanyCzasWyswietlacz5 >= 1000)
   {
    zapamietanyCzasWyswietlacz5 = aktualnyCzas;
    sensor.requestTemperatures();
    lcd.setCursor(4,0);
    lcd.print("Pomiar 5");
    lcd.setCursor(3,1);
    lcd.print(sensor.getTempCByIndex(0));
    lcd.setCursor(9,1);
    lcd.print("st.C"); 
   }
  else if (aktualnyCzas - zapamietanyCzasWyswietlacz5 >= 1) 
   {
    lcd.setCursor(4,0);
    lcd.print("Pomiar 5"); 
   }  
}
void Temp6()
{
    aktualnyCzas = millis();
  if(aktualnyCzas - zapamietanyCzasWyswietlacz6 >= 1000)
   {
    zapamietanyCzasWyswietlacz6 = aktualnyCzas;
    sensor.requestTemperatures();
    lcd.setCursor(4,0);
    lcd.print("Pomiar 6");
    lcd.setCursor(3,1);
    lcd.print(sensor.getTempCByIndex(0));
    lcd.setCursor(9,1);
    lcd.print("st.C"); 
   }
  else if (aktualnyCzas - zapamietanyCzasWyswietlacz6 >= 1) 
   {
    lcd.setCursor(4,0);
    lcd.print("Pomiar 6"); 
   }  
}
  • Lubię! 1
Link do komentarza
Share on other sites

1 godzinę temu, Tom5e napisał:

Czy to możliwe aby odczyt pomiaru z DS18B20 tak obciążał procesor

Niemożliwe.

Trzeba jednak odróżnić czas odczytu wyniku z czujnika (ten trwa moment), od czasu wykonywania pomiaru przez czujnik (a ten dla rozdzielczości 11 bit wynosi ok. 0,3sek). Dlatego najlepiej po odczycie getTempCByIndex() od razu poprosić o nowy pomiar: requestTemperatures().

1 godzinę temu, Tom5e napisał:

Czasami pokazuje temperaturę -127 lub +85 stopni

Czy masz opornik podciągający na linii danych od czujników?

1 godzinę temu, Tom5e napisał:

Czy można uprościć ten kod

Oczywiście.

Na początek spróbuj napisać procedurę odczytu czujnika, zamiast powtarzać to samo 6 razy.

I jak napisał @Santiago zajmij się debounce'm przycisku.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

85 stopni oznacza "jestem gotowy do pracy, teraz możesz odczytać temperaturę". Jeśli dostaniesz taki wynik musisz powtórzyć pomiar.

Podłączone trzema przewodami czy dwoma na pasożytniczym?

Link do komentarza
Share on other sites

(edytowany)
47 minut temu, Santiago napisał:

Naciskasz raz a przełącznik drga wiele razy stąd te przypadkowe wartości.

Oglądałem filmik w którym ktoś tłumaczył to o czym piszesz. Rozwiązaniem miało być dołożenie delay'a i tak też zrobiłem. Testowałem z różnymi wartościami. Przykład poniżej. Ale nic to nie wniosło.

Dodatkowo mogę klikać szybko przez godzinę i zawsze się ekran przełączy. A jak zaczekam około sekundy po przełączeniu to się "zawiesza".

void loop()
{   
 if (digitalRead(upButton)==LOW){
    delay(50);
    lcd.clear();
    menu=menu+1;
 while (digitalRead(upButton)==LOW)
    delay(50);
  }
 if (digitalRead(downButton)==LOW){  
    delay(50);
    lcd.clear();
    menu=menu-1;
    while (digitalRead(downButton)==LOW)
    delay(50);

 

Edytowano przez Tom5e
Link do komentarza
Share on other sites

Opornik mam podpięty i całość jest na pasożytniczym. Zmienię rozdzielczość czujników na najmniejszą i zobaczę co się stanie.

12 minut temu, jand napisał:

Na początek spróbuj napisać procedurę odczytu czujnika, zamiast powtarzać to samo 6 razy.

Mógłbyś napisać coś więcej? Bo nie za bardzo wiem jak się za to zabrać.

  • Lubię! 1
Link do komentarza
Share on other sites

6 minut temu, Tom5e napisał:

całość jest na pasożytniczym

Na początek spróbuj zasilić normalnie.

 

7 minut temu, Tom5e napisał:

Bo nie za bardzo wiem jak się za to zabrać.

Masz szereg funkcji Temp1(), Temp2() itd., które są niemal identyczne.

Spróbuj napisać jedną, wspólną funkcję Temp(int czujnik) która będzie odczytywać dane z czujnika o podanym numerze.

Link do komentarza
Share on other sites

45 minut temu, Tom5e napisał:

Opornik mam podpięty i całość jest na pasożytniczym

Jaki opornik (wartość)? Teoretycznie biblioteka powinna sama wykryć że to pasożytnicze, ale wtedy sprawa się komplikuje - trzeba naładować kondensator, a to na pewno nie trwa milisekundę. Stąd się pewnie bierze te -127 stopni (czyli "urządzenie niepodłączone"). - z jakichś przyczyn kondensator w DS nie zdążył się naładować. Tak jak pisał @jand - odpuść sobie na razie pasożytnicze.

 

Link do komentarza
Share on other sites

Opornik 4,7kΩ.

Potestowałem rozdzielczość czujnika i na 8 bit śmiga aż miło, nie wywala błędów. Ekran przełącza się za każdym razem błyskawicznie. Natomiast po zmianie na 12 bit często wywala błąd -127/+85. A przełączanie ekranów jest mega irytujące bo za 3/5 wciśnięciu przycisku dopiero reaguje i zmienia ekran, ogólnie mega "muli".

Czy to oznacza, że Arduino nie radzi sobie z tym czujnikiem na wysokiej rozdzielczości? Czy czegoś brakuje?  

Link do komentarza
Share on other sites

28 minut temu, Tom5e napisał:

Opornik 4,7kΩ.

 

Do pasożytniczego raczej koło kilooma...

Poza tym to nie Arduino muli, tylko funkcja requestTemperature ma wmontowanego delaya (w przypadku 12 bitów to 750 msec). Można to wyłączyć - poszukaj co robią waitForConversion, setWaitForConversion i tym podobne.

Ogólnie - używając jakiejś biblioteki warto zapoznać się z tym, co ona robi...

 

Link do komentarza
Share on other sites

Przykład z wyłączeniem czekania na koniec pomiaru:

// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);


uint32_t czasTeraz,czasPoprzedni,tik=10, czas1,czas2,czas3,czas4,roznica,maximum,srednia;
uint8_t n10,fn10,sekundy,minuty,godziny,dni,nic;
 
bool fsekundy,fminuty,fgodziny,fdni;
void setup() {
//  sysClock(INT_OSC32);
  // put your setup code here, to run once:
Serial.begin(115200);
  sensors.begin();
sensors.requestTemperatures(); 
sensors.setWaitForConversion(0);
}

void loop() {
  czas(); 
  // put your main code here, to run repeatedly:
 if(fsekundy)
 {
  if(sekundy%2==0)
  {
     sensors.requestTemperatures(); // Send the command to get temperatures
     float odczyt=sensors.getTempCByIndex(0);
     Serial.print("Odczyt temperatury zaraz po zleceniu konwersji: "); 
     Serial.println(odczyt); 
  }
  else
  {
     float odczyt=sensors.getTempCByIndex(0);
     Serial.print("Odczyt temperatury w innej sekundzie: "); 
     Serial.println(odczyt); 
  }
 }
 

}


void czas()
{
  czasTeraz=millis();
 fn10=fsekundy=fminuty=fgodziny=fdni=0;
if((uint32_t)(czasTeraz-czasPoprzedni)>=tik)
{
  czasPoprzedni=czasTeraz;
  fn10=1;
  n10++;
  if(n10>=100)
  {
    n10=0;
    sekundy++;
    fsekundy=1;
     if (sekundy>=60)
    {
      sekundy=0;
      minuty++;
      fminuty=1;
      if (minuty>=60)
      {
        minuty=0;
        godziny++;
        fgodziny=1;
        if (godziny>=24)
        {
          godziny=0;
          fdni=1;
          dni++;
    
        }
      }
    }
  }
}
}

Timer programowy - funkcja czas() oznacza mi czy dany przebieg loop jest w pełnej sekundzie działania programu, jeśli tak, to w parzyste zleca pomiar, a w nieparzyste odczytuje temperaturę, dzięki temu z każdej sekundy tylko 20ms jest wykorzystywane, raz na milion pętli loop. Pozostaje dużo czasu na inne czynności, np. miganie ledem. 20ms trwa mniej więcej jedna transmisja do/z DS.

Można też tak zrobić, by co sekundę odczytać (czy tam co 750ms dla 12bitów, ale ciężko się na palcach to liczy), a potem zlecić kolejny pomiar, tylko wtedy to trwa już 40ms. Jak odczytasz po kolei 10 czujników to też to zajmie wielokrotność odczytu jednego. No ale i tak jest dużo szybciej niż czekać 750ms na każdy.

Jak chcesz mieć odczyt wszystkich co 1s to po prostu można to sobie dalej podzielić, zamiast 1s podzielić zadania na interwały co 50ms, można w kolejnych wywołaniach odczytać po 1 czujniku, a w ostatnim zlecić pomiar, przez kolejne odliczać tylko czas do zakończenia pomiaru w wybranej rozdzielczości.

A tu taki przykład, tylko z wykorzystaniem gotowej biblioteki:

#include <DallasTemperature.h>
#include <OneWire.h>
#include <TickTwo.h>
 
#define ONE_WIRE_BUS 4
 
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

float tempDS;

void temp();
void serial1000();
void serial500();
void ledBlink();

TickTwo timer1(temp, 100);
TickTwo timer2(serial500, 500);
TickTwo timer3(serial1000, 1000);
TickTwo timer4(ledBlink, 50);

void setup() {
  Serial.begin(115200);

  timer1.start();
  timer2.start();
  timer3.start();
  timer4.start();
  
  sensors.setWaitForConversion(0);
  sensors.setResolution(12);
  sensors.begin();
  }

void loop() {
  timer1.update();
  timer2.update();
  timer3.update();
  timer4.update();
 
}

 

void temp() {
static uint8_t ktoraSetkaSekundy=0;

switch (ktoraSetkaSekundy)
{
  case 0:
sensors.requestTemperatures();  
  break;
  case 3:
Serial.println("Kuku z trojki");
  break;
  case 8:
tempDS = sensors.getTempCByIndex(0);
  break;
  default:
// gdy 1,2,3,4,5,6,7 i 9 nic ta funkcja nie robi poza ktoraSetkaSekundy++
  break; 
}
ktoraSetkaSekundy++; 
if( ktoraSetkaSekundy>9) ktoraSetkaSekundy=0;
}
 

void serial500()
{
Serial.println("test 500 ms");

}

void serial1000()
{
Serial.print("Temperatura: ");
Serial.println(tempDS);
}

void ledBlink()
{
static bool startujemy=0;  
if(! startujemy) 
{
  pinMode(LED_BUILTIN,OUTPUT);
  startujemy=1;
}  
digitalWrite(LED_BUILTIN, ! digitalRead (LED_BUILTIN));

} 

 

Link do komentarza
Share on other sites

Po dodaniu

sensors.setWaitForConversion(false);

i podłączeniu jednego czujnika w trybie niepasożytniczym wszystko działa bardzo fajnie. Natomiast po podłączeniu czujników w tryb pasożytniczy kod nie działa. Wyświetlają się temperatury +85 stopni. Myślałem że może jak dodam adresy czujników to zaskoczy, natomiast nic to nie wniosło.

Poniżej kod który działa bez włączonej konwersji, a z włączoną wyświetla się +85 stopni. Może ktoś ktoś ma pomysł jak to poprawić?

 

#include <Wire.h>   // standardowa biblioteka Arduino
#include <LiquidCrystal_I2C.h> // dolaczenie pobranej biblioteki I2C dla LCD
#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 2

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
LiquidCrystal_I2C lcd(0x27, 16, 2); //LiquidCrystal_I2C lcd(0x3f, 16, 2);

uint8_t T1[8] = { 0x28, 0x1A, 0x48, 0x89, 0x0F, 0x00, 0x00, 0x48 };
uint8_t T2[8] = { 0x28, 0x41, 0x93, 0x88, 0x0F, 0x00, 0x00, 0x3F };

int resolution = 11;

unsigned long aktualnyCzas = 0; 
unsigned long zapamietanyCzasWyswietlacz1 = 0;
unsigned long zapamietanyCzasWyswietlacz2 = 0;

void setup()
{
  lcd.init();
  lcd.backlight();
  lcd.setBacklight(HIGH);
  sensors.begin(); 
  sensors.setResolution(resolution); 
  //sensors.setWaitForConversion(false);  //jeśli aktywne, nie działa
  sensors.requestTemperatures();
}  
void loop(){
    aktualnyCzas = millis();
  if(aktualnyCzas - zapamietanyCzasWyswietlacz1 >= 1000)
   {
    zapamietanyCzasWyswietlacz1 = aktualnyCzas;
    sensors.requestTemperatures();
    lcd.setCursor(0,0);
    lcd.print("T1");
    lcd.setCursor(4,0);
    lcd.print(sensors.getTempC(T1));
    lcd.setCursor(11,0);
    lcd.print("st.C"); 
   }
  else if (aktualnyCzas - zapamietanyCzasWyswietlacz1 >= 1) 
   {
     lcd.setCursor(0,0);
}
   aktualnyCzas = millis();
  if(aktualnyCzas - zapamietanyCzasWyswietlacz2 >= 1000)
   {
    zapamietanyCzasWyswietlacz2 = aktualnyCzas;
    sensors.requestTemperatures();
    lcd.setCursor(0,1);
    lcd.print("T2");
    lcd.setCursor(4,1);
    lcd.print(sensors.getTempC(T2));
    lcd.setCursor(11,1);
    lcd.print("st.C"); 
   }
  else if (aktualnyCzas - zapamietanyCzasWyswietlacz2 >= 1) 
   {
    lcd.setCursor(0,1);
   }  
}

 

Link do komentarza
Share on other sites

(edytowany)

Zgodnie opisem zasilania czujnika, podanym na stronie 7 karty katalogowej (rysunek 6) w trybie pasożytniczym zaleca się stosowanie dodatkowego tranzystora MOSFET do zasilania czujników. Specjalnie, jeśli czujników jest więcej.

Osobiście nie stosował bym trybu pasożytniczego, no chyba że jest to naprawdę konieczne.

Edytowano przez jand
Link do komentarza
Share on other sites

18 godzin temu, jand napisał:

Osobiście nie stosował bym trybu pasożytniczego, no chyba że jest to naprawdę konieczne.

Chciałem zastosować ten tryb bo z tych informacji do których dotarłem w internecie wszyscy zachwalali jak to świetnie działa (zanim tu trafiłem). Ktoś robił testy na 100 czujnikach i nie było żadnych problemów (tak twierdził). Ale widzę, że nie działa to tak fajnie jak niektórzy zachwalają.

W przyszłości będę chciał zrobić projekt na większej liczbie czujników i przekaźników. Czy zwiększenie liczby pinów (Arduino UNO) przez ekspander wyprowadzeń PCF8574 -  zda egzamin przy tych czujnikach lub przekaźnikach? Pytam bo jak to działa tak samo słabo jak tryb pasożytniczy to wolę kupić od razu Arduino Mega. 

Link do komentarza
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!

Anonim
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...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.