Skocz do zawartości

Zakłócenia odczytu z LM35 i fotorezystora


dawis96

Pomocna odpowiedź

Cześć. Znów mam problem z termometrem LM35. Program ma za zadanie jednocześnie sterować wiatrakiem w zależności od odczytów z termometru oraz  światłem w zależności od odczytów z fotorezystora(światło ma się świecić tylko kiedy w pokoju jest słabe światło, przy jasnym świetle oraz w nocy ma być wyłączone). Zastosowałem uśrednianie pomiarów, które odbywa się w osobnych funkcjach poniżej. Zamiast delay wykorzystuje funkcję millis() aby nie "zamrażać" Arduino miedzy kolejnymi pomiarami. Problem polega na tym, że podczas słabego lub zgaszonego światła pomiary wydają się sensowne, lecz kiedy zapale mocne światło odczyt z fotorezystora skacze go góry (tak jak powinno się stać) natomiast termometr zaczyna podawać różne wartości). Próbowałem rozdzielić czujniki, stosując osobne uziemienia dla obu czujników lecz nic to nie dawało. W czym może być problem? Przeczytałem ze pomiary nie odczyty się odbywać w tym samym czasie, tylko po kolei za sobą, ale nie wiem jak to zrobić przy użyciu funkcji millis() i czy to przez to program źle działa. Proszę o pomoc.

#define relay_fan 2
#define thermometer A5
#define relay_bulb 4
#define photoresistor A4

//zmienne do pomiaru sredniej temperatury
float temperature;
int iT=0;
float sumT=0;
float meanT=0;
unsigned long keptTimeTemp=0;
//zmienne do sterowania wentylatorem
float FanOnTemp=23.0;
float FanOffTemp=22.5;

//zmienne do pomiaru srednigo poziomu oswietlania
int light_level;
int iL=0;
float sumL=0;
float meanL=0;
unsigned long keptTimeLight=0;
//zmienne do sterowania swiatlem
int lightMin=5;
int lightMax=40;

unsigned long keptTimePrint=0;//zmienna czasowa do wypisywania informacji 

unsigned long actualTime=0;//zmienna czasowa do zapisywania aktualnczego czasu funkcja millis()



void setup() {
  Serial.begin(9600);
  pinMode(relay_fan, OUTPUT) ; 
  digitalWrite(relay_fan, HIGH);
  pinMode(relay_bulb, OUTPUT) ; 
  digitalWrite(relay_bulb, HIGH);
  

}

void loop() {
 
  actualTime=millis();

  
  meanT= average_temperature();
  meanL= average_light_level();

  //Sterowanie wentylatorem
  if (meanT>=FanOnTemp) {
    digitalWrite(relay_fan, LOW);  
  }
  else if(meanT<=FanOffTemp) {
    digitalWrite(relay_fan, HIGH);
  }

  //Sterowanie swiatlem
  if ((meanL<lightMin)||(meanL>lightMax)){
    digitalWrite(relay_bulb, HIGH);
  }
  else {
    digitalWrite(relay_bulb, LOW);
  }


  //Wypisywanie danych
  if (actualTime - keptTimePrint >= 11000UL){

    Serial.print("t:");
    Serial.print(meanT);
    Serial.print(",F:");
    if (digitalRead(relay_fan)==LOW) {
      Serial.print("1");
    }
    else {
      Serial.print("0");
    }
    Serial.print(",L:");
    Serial.print(meanL);
    Serial.print(",B:");
    if (digitalRead(relay_bulb)==LOW) {
      Serial.println("1");
    }
    else {
      Serial.println("0");
    }
    
    keptTimePrint= actualTime;
  }
}

float average_temperature(){
   if (actualTime - keptTimeTemp >= 1000UL){  //odmierzanie czasu
      if (iT<10){ //robienie 10 pomiarow
      keptTimeTemp= actualTime;
      temperature = ((analogRead(thermometer) * 5.0) / 1024.0) * 100; //zamiana napiecia na stopnie celcjusza
      sumT=sumT+temperature;
      iT++;
      Serial.print("actual temperature: ");
      Serial.println(temperature);
     }
     else if(iT>=10){
      meanT=sumT/iT; //Obliczanie sredniej i zerowanie zmiennych
      Serial.print("average temperature: ");
      Serial.println(meanT);
      iT=0;
      sumT=0;
     }
  }
  return meanT;
}
float average_light_level(){
   actualTime=millis();
   if (actualTime - keptTimeLight >= 1000UL){  //odmierzanie czasu
      if (iL<10){ //robienie 10 pomiarow
      keptTimeLight= actualTime;
      light_level= map(analogRead(photoresistor), 0, 1023, 0, 99);
      sumL=sumL+light_level;
      iL++;
      Serial.print("actual light level: ");
      Serial.println(light_level);
     }
     else if(iL>=10){
      meanL=sumL/iL; //Obliczanie sredniej i zerowanie zmiennych
      Serial.print("average light level: ");
      Serial.println(meanL);
      iL=0;
      sumL=0;
     }
  }
  return meanL;
}

image.thumb.png.82f839a826c8e765eaea3bdcbda2c5be.pngimage.thumb.png.4f864a102484bc6ad1e502de957bb69a.pngimage.thumb.png.d4aee7476d30e8f5159fb9c9550d2e18.png

Link do komentarza
Share on other sites

if (actualTime - keptTimeLight >= 1000UL) w tej linijce jedynie zwiększaj zmienną, np. sekund i ustawiaj flagę, że jest nowa na 1.  A już poza tym warunkiem gdy sekunda jest parzysta i flaga nowa==1 to mierz jedno, a nieparzysta to coś innego. Można mierzyć np. tylko wtedy gdy jest podzielna przez 5 (sekunda%5==0).

Pomiary ADC  lepiej wykonywać w odniesieniu do napięcia wewnętrznego mikroprocka analogReference() - ustaw na internal, dzielnikami rezystorowymi dopasuj do 1.1V bo tyle mniej więcej ono jest zamiast typowych 5V. Jak mierzysz w odniesieniu do VCC=5V to gdy silniki nie pracują napięcie może być idealnie =5V, odczyt z czujnika 3V pokaże 3V/5V*1024=615. Jak obciążysz Arduino silnikiem to czujnik dalej podaje napięcie 3V ale VCC może być już wtedy 4,5V, czyli ADC pokaże 3/4.5*1024=682, będzie kłamał, że temperatura jest wyższa gdy silnik pracuje. To oczywiście nie musi być aż tak dramatyczny skok napięcia, ale przekłamania mogą być. Swoją drogą lepiej zasilić silnik z zupełnie innego źródła.

Link do komentarza
Share on other sites

A ja bym radził - zamiast tak drastycznych zmian typu dzielniki napięcia na każdym wejściu poszukać jednak w kodzie. Spróbuj okrajać swój program do coraz prostszej postaci albo wycinać pewne fragmenty. Możesz zacząć np. włączenia na stałe wiatraczka, bez żadnych if-ów. Potem możesz włączyć do drugie coś (żarówkę?) bez wiatraczka, potem oba na raz. Niech warunki wszystkiego będa stabilne i wtedy rób pomiary. W ten sposób znajdziesz to coś, po usunięciu czego pomiar zacznie być poprawny. To nie musi być problem ze sprzętem, ale tak czy tak musisz podrążyć temat. Sprawdź oczywiście Vcc woltomierzem w różnych sytuacjach, choć nie widzę przyczyny dla której miałoby pływać. Może np. zacznij od całkiem nowego programu w którym w pętli tylko mierzysz jedno wejście? Jak jest wtedy? A gdy dodasz pomiary drugiego? A gdy dopiszesz uśrednianie? A gdy jeszcze pozałączasz wyjścia? Niedziałanie programów to ich stan naturalny 🙂 a Ty jako programista/konstruktor musisz wypracować sobie własne metody weryfikacji każdego fragmentu po kolei. Pisz jakiś test i jeśli jest dobrze, dopisuj kolejny kawałek bazując na tym co już działa. Totalne (modne słowo) zmiany nie są wskazane, bo w ten sposób może i coś przypadkowo się poprawi, ale nie dojdziesz co było źle - to i nauka z tego żadna. A może się też okazać, że włożysz kawał roboty w błoto.. Pzrecież każdy z nas pisze programy i każdy robi błędy. Podejdź do tego systematycznie: od zera budując kod lub od góry, usuwając kolejne fragmenty z już istniejącego. Ciekaw jestem wniosków.

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

(edytowany)

Rozebrałem wszystko, aby sprawdzić działanie samych odczytów i problem  występuje już przy tej czynności. Po podłączeniu samego termometru i fotorezystora termometr dalej wariuje.  W układzie gdzie jest sam termometr odczyty z niego są prawidłowe. Chyba poddam się i użyje termometru cyfrowego ale martwi mnie to ponieważ muszę do tego układu dodać jeszcze czujnik wilgotności gleby, który jest analogowy .

 

Edit.

Przetestowałem czujnik wilgotnosci gleby i  pokazuje takie same odczyty w układzie gdzie pracuje sam, jak i z fotorezystorem oraz termometrem. 

#define thermometer A5
#define photoresistor A4
int light_level;
float temperature;

void setup() {
    Serial.begin(9600);
}

void loop() {
  light_level= map(analogRead(photoresistor), 0, 1023, 0, 99);
  delay(1000);
  temperature = ((analogRead(thermometer) * 5.0) / 1024.0) * 100; //zamiana napiecia na stopnie celcjusza

  Serial.print("T: ");
  Serial.println(temperature);
  Serial.print("L: ");
  Serial.println(light_level);
  delay(1000);

}

 

image.thumb.png.f5849c0acd521c66398dd72dc8db7c78.png

Edytowano przez dawis96
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

Teraz gdy podłączone są tylko czujniki, arduino zasilane jest przez usb. W pełnym programie do arduino podłączony jest zasilacz 12v, ponieważ wiatrak jest na 12v, a żarówka ma osobne zasilanie z gniazdka. Odczyty pokazują ze temperatura skacze gdy odczyty z rezystora lub czujnika wilgotności gleby się zmieniają. 

#define thermometer A5
#define photoresistor A4
#define soil_moisture_sensor A3
int light_level;
float temperature;
float soil_moisture;

void setup() {
    Serial.begin(9600);
}

void loop() {
  light_level= map(analogRead(photoresistor), 0, 1023, 0, 99);
  temperature = ((analogRead(thermometer) * 5.0) / 1024.0) * 100; //zamiana napiecia na stopnie celcjusza
  soil_moisture= map(analogRead(soil_moisture_sensor), 0, 1023, 0, 99);
  

  Serial.print("T: ");
  Serial.println(temperature);
  Serial.print("L: ");
  Serial.println(light_level);
  Serial.print("S: ");
  Serial.println(soil_moisture);
  Serial.println(" ");
  delay(1000);
 

}

 

image.thumb.png.fd09b9020ae4c8bac72b256fc96ac1c3.pngimage.thumb.png.b0ea4eb9b9406ac203a32402b64b953d.png

Link do komentarza
Share on other sites

Nie pisałeś wcześniej o USB - to zupełnie inny sposób, bo wtedy 5V które ADC używa jako napięcia odniesienia jest podawane wprost z kabla, z zasyfionego komputera. Odpal to samo z 12V, niech Arduino samo sobie zrobi 5V - to musi być czyste.

Link do komentarza
Share on other sites

Jeśli to UNO, to na linii zasilania z USB jest switch (tranzystor) wyłączany gdy płytka widzi VIN. Więc z podpiętym zasilaczem powinno chodzić z 12V. Dziwne to. A jak daleko masz ten czujnik? Spróbuj wywalić te zmiennoprzecinkowe obliczenia temperatury i wypisać same wyniki oddawane przez analogRead() albo zmapuj je tą samą metodą czyli

map(0,1023, 0, 500)

ale to bardziej tak z ciekawości.. Czy układ jest teraz tak podłączony jak na rysunku z płytką stykową? A może akurat to wejście analogowe jest jakieś ułomne? Spróbuj zamienić wejścia albo podpiąć temperaturę na inny, jeszcze nieużywany pin. Możesz też spróbować robić kilka odczytów tej samej wielkości i brać pod uwagę ostatni:

analogRead(thermometer);
analogRead(thermometer);
temperature = ((analogRead(thermometer) * 5.0) / 1024.0) * 100;

Napisz jak wyglądają wyniki tych prób.

  • Lubię! 1
  • Pomogłeś! 1
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.