• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Czujnik kierunku wiatru - nieznany protokół
#11
ciekawe czy nie będzie to 1Wire
Arduino zostało wymyślone po to, by robić dobrze jedną prostą rzecz – migać diodą. 
 
Odpowiedź
#12
@Jarewa0606 niestety to nie 1Wire
@kaczakat a możesz mnie nakierować jak odczytać te piki i obliczyć czas trwania? Próbowałem z pulseIn ale cały czas dostaje "1"
 
Odpowiedź
#13
Wskazówki już masz, jeśli ich nie rozumiesz, to po prostu za mało wiedzy - kurs i uzupełnienie podstaw. A co do ogólnych danych to oczywiście logika musi być w obu urządzeniach 0-5V, musisz wiedzieć jaki jest minimalny poziom sygnału i maksymalny (za niskich sygnałów UNO nie zauważy, poniżej 0V i powyżej 5.5V mogą go uszkodzić). Druga sprawa to wspólna masa. pulseln powinno działać, krótkie impulsy można mierzyć też używając ręcznie micros(), odczytujesz licznik kiedy startujesz, kiedy kończysz i zapisujesz sobie różnicę. No albo normalnie jak w AVR C timerami sprzętowymi, ale to co daje Arduino spokojnie wystarczy.
 
Odpowiedź
#14
Udało mi się odczytać kierunki, tylko nie wiem jak teraz zoptymalizować kod hmmm.
Kod:
// Ustaw pin do odczytu
const int kierunekWiatruPin = 2;

// deklaracja zmiennych:
int PWM[15];
int compass[3];
const char* kierunek;

void setup() {
 Serial.begin(115200);
 pinMode(kierunekWiatruPin, INPUT);    
 attachInterrupt(digitalPinToInterrupt(kierunekWiatruPin), kierunekWiatru, RISING);
}

void loop(){
 
 
 
}

void kierunekWiatru(){
 if(pulseIn(kierunekWiatruPin, HIGH) > 1000){
 for (byte k=0; k<15; k++) {
     PWM[k] = pulseIn(kierunekWiatruPin, HIGH);
   }
     if(PWM[3] > 400 and PWM[3] < 600) compass[0] = 1; else compass[0] = 0;
     if(PWM[4] > 400 and PWM[4] < 600) compass[1] = 1; else compass[1] = 0;
     if(PWM[5] > 400 and PWM[5] < 600) compass[2] = 1; else compass[2] = 0;
     if(PWM[6] > 400 and PWM[6] < 600) compass[3] = 1; else compass[3] = 0;
   
       if(compass[0] == 1 and compass[1] == 1 and compass[2] == 1 and compass[3] == 1) kierunek = "N";
       if(compass[0] == 1 and compass[1] == 1 and compass[2] == 1 and compass[3] == 0) kierunek = "NNE";
       if(compass[0] == 1 and compass[1] == 1 and compass[2] == 0 and compass[3] == 0) kierunek = "NE";
       if(compass[0] == 1 and compass[1] == 1 and compass[2] == 0 and compass[3] == 1) kierunek = "ENE";
       if(compass[0] == 1 and compass[1] == 0 and compass[2] == 1 and compass[3] == 1) kierunek = "E";
       if(compass[0] == 1 and compass[1] == 0 and compass[2] == 1 and compass[3] == 0) kierunek = "ESE";
       if(compass[0] == 1 and compass[1] == 0 and compass[2] == 0 and compass[3] == 1) kierunek = "SE";
       if(compass[0] == 1 and compass[1] == 0 and compass[2] == 0 and compass[3] == 0) kierunek = "SSE";
       if(compass[0] == 0 and compass[1] == 1 and compass[2] == 1 and compass[3] == 1) kierunek = "S";
       if(compass[0] == 0 and compass[1] == 1 and compass[2] == 1 and compass[3] == 0) kierunek = "SSW";
       if(compass[0] == 0 and compass[1] == 1 and compass[2] == 0 and compass[3] == 1) kierunek = "SW";
       if(compass[0] == 0 and compass[1] == 1 and compass[2] == 0 and compass[3] == 0) kierunek = "WSW";
       if(compass[0] == 0 and compass[1] == 0 and compass[2] == 1 and compass[3] == 1) kierunek = "W";
       if(compass[0] == 0 and compass[1] == 0 and compass[2] == 1 and compass[3] == 0) kierunek = "WNW";
       if(compass[0] == 0 and compass[1] == 0 and compass[2] == 0 and compass[3] == 1) kierunek = "NW";
       if(compass[0] == 0 and compass[1] == 0 and compass[2] == 0 and compass[3] == 0) kierunek = "NNW";      
   
      Serial.println(kierunek);
 }
}
 
Odpowiedź
#15
To chyba była długa noc. Na pewno wartości w tablicy kompas to 0 lub NIE 0, więc nie są potrzebne porównania typu "compass[2] == 0 and compass[3] == 1", kompilator może to wie i sam coś zrobi z tym sam, ale można to zapisać po prostu "! compass[2] and compass[3] " - nie jest 0 i jest 1.
Po wejściu w przerwanie powinno się je wyłączyć - detachInterrupt(), bo w trakcie jego trwania będą kolejne impulsy, po zakończeniu funkcji od razu zostanie wywołana ponownie. Gdybyś println umieścił poza przerwaniem to pewnie nigdy by się nie wykonało, bo program trwa w przerwaniu. Jeśli to jego jedyne zadanie to w sumie nie ma znaczenia. Jeśli byś używał zmiennych jeszcze poza przerwaniem to dodaj do ich deklaracji volatile.
Używanie w przerwaniu innych funkcji i to tak długich nie jest najlepszym pomysłem, także można sobie tylko tu wskoczyć, przełączyć się na zbocze opadające, zapisać stan licznika us z funkcji micros() ( i tak z 15us straty), po całej sekwencji zablokować przerwanie lub przełączyć się na inną funkcję, która tylko sprawdza ile czasu minęło od poprzedniej transmisji (tak by złapać jej początek), wrócić do loop i na spokojnie obliczyć dane w inne funkcji poza przerwaniem.
Taki program zmieściłby się w attiny13 i po prostu softserialem możesz do jakiegoś "dużego" procesora po prostu wysłać gotowe dane. Soft serial jest oparty o przerwania timera i nie zadziała w innym przerwaniu. Ale i tak nie robi się funkcji typu pulseIn i println w przerwaniach. Po zablokowaniu przerwania i odczytaniu kierunku, wracasz do loop, drukujesz dane, za określony czas znowu aktywujesz przerwanie i blokujesz procesor (jeśli to jego jedyne zadanie).
Ja bym sprawdzał w pętli głównej (po prostu inną funkcją przerwania z krótką zmienną) czy stan bezczynności jest dłuższy niż przerwa między nadawaniem pików, wtedy należy się przygotować do odebrania pierwszego, ustawić przerwanie by wychwycić ten moment. Jak nastąpi to ustawić tylko zmienną flagę (volatile), zablokować to przerwanie i oddać program do loop. można odczekać zwykłym delay w us 750us i odczytać stan pinu, potem w sekwencji 1500us wybrać sobie te cztery 0 i 1, operacjami bitowymi (przesunięcie i suma gdy 1 lub przesunięcie) napełnić zmienną byte, będzie miała wartość 0-15. Z udelayami procesor zostanie zablokowany na czas tylko 8 pików. Jeśli sprawdzasz kierunek wiatru raz na kilka s to nie będzie miało dużego znaczenia. No ale to też zależy co masz w pętli głównej, jak są tu polecenia, które długo trwają to zanim dojdzie do funkcji kierunku, chwila może uciec. Można też w jednej funkcji przerwania sprawdzać czy od ostatniego nadawania była przerwa, jeśli tak to aktywować taką 10ms funkcję w kolejnej aktywacji przerwania. Interesują Cię tylko 4 bity, można więc też zignorować niepotrzebne. Można też użyć timera sprzętowego i jego przerwań, gdy wybije pierwszy impuls wyłączyć przerwanie od INT, ustawić timer na określony czas by odczytać pierwszy bit, potem zmienić czas timera na 1500us i odczytać trzy pozostałe.
No, i wszystkie te rzeczy mogą się teraz gryźć z tym co planujesz robić poza odczytem kierunku wiatru, inne biblioteki mogą Ci wyłączać przerwania, mieć swoje długie funkcje, mieć swoje przerwania, które będą zakłócały Twoje pomiary. Więc jakbyś zlecił komuś ten program to nic sam nie zrobisz, mogłoby się okazać, że po byle jakiej modyfikacji nic nie działa. No a poukładanie teraz wielozadaniowego programu w loop, to będzie zabawa Big Grin.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości