Skocz do zawartości

IR break beam - attiny + arduino


Puchaczov

Pomocna odpowiedź

Hej, potrzebuję sobie stworzyć urządzonko które określi mi czy coś przerwało linię. Z mikrokontrolerami nie miałem nigdy specjalnego stąd moje pytanie.

napisałem taki o oto kod do generowania ciągłego impulsu 38khz:

#include <util/delay.h>
#define TOGGLE_DELAY 26
#define REFRESH_DELAY 600
int main(void)
{
   int i;
   DDRB |= (1 << PB3);
   PORTB |= (1 << PB3);
   while(1)
   {
       for(i = 0; i < 23; ++i)
       {
           PORTB ^= (1 << PB3);
           _delay_us(TOGGLE_DELAY);
       }
       PORTB =(0 << PB3);
       _delay_us(REFRESH_DELAY);
   }
   return 0;
}

kod ten według założeń powienien generować sygnał 38khz przez 600us, przez następne 600us 'odpoczywać' i tak w kółko. Coś chyba zepsułem bo odbiornik (arduino + IRReceiver)

nie chce wystawiać 0 na przypisany pin mimo, że dioda świeci ( nie wiem z jaką f ale świeci ). Gdy natomiast zamrugam pilotem od telewizora, odbiornik w arduino poprawnie rozpoznaje sekwencje i odmruguje mi dioda led.

kod arduino:

int lastCheck;
void setup(void) {
 Serial.begin(9600);
 Serial.println("Ready to decode IR!");
 pinMode(3, INPUT);
 pinMode(2, OUTPUT);
 lastCheck = micros();
}
volatile bool value = 0;
volatile bool i = 0;
void loop(void) {
 int now = micros();
 int pin = digitalRead(3);
 if(pin == 0)
 {
   digitalWrite(2, !value);
 }
 else //brak impulsow
 {
   if(now - lastCheck > 3) //impuls trwa wiecej niz 3us
   {
     value = 0;
     digitalWrite(2,value);
   }
 }
 lastCheck = now;
 i++;
}

Attiny odpowiedzialny za generowanie czestotliwosci 38khz ma podpiety do diody opornik 50 Ohm.

Moje pytanie brzmi: Mając diodę TSAL6400, jak mogę odczytać przez jaki czas mogę nią świecić z daną częstotliwością i na ile powinienem ją gasić. Prawdopodobnie uszkodziłem ją przez świecenie z nadmierną częstotliwością (przez pewien czas miałem błąd w kodzie który nie gasił diody po 'odegraniu' sekwencji)

Link do komentarza
Share on other sites

1. Prąd przewodzenia tej diody to 100mA, attiny nie powinien jej uszkodzić, bo wyjścia attiny mają dużo mniejszy prąd.

2. Większość prostych kamerek (np. z tel. kom.) nie ma filtru IR, więc widać w nich światło IR. W ten sposób możesz sprawdzić czy dioda rzeczywiście świeci (będziesz wiedział czy dioda działa czy raczej coś z 38kHz jest nie tak)

Link do komentarza
Share on other sites

Jeśli dobrze rozumiem, to stała TOGGLE_DELAY wyraża długość połowy okresu przebiegu jaki generujesz dla diody. 26us daje częstotliwość 19kHz która leży daleko poza pasmem pracy odbiornika IR. To na pewno jest do poprawy.

Nie możesz spalić diody nadawczej "nadmierną częstotliwością". Natomiast zbyt dużym prądem na pewno. Mając jednak opornik 50R szeregowo jesteś daleki od przekroczenia.

Pomijam fakt, że do generacji takich rzeczy jak modulowany przebieg 36kHz o wiele lepiej nadają się sprzętowe timery procesora. Opóźnienia programowe są proste pojęciowo, ale gdy zbliżasz się do szybkości samego procesora zaczynają być mocno niedokładne no i obciążają go w 100%. Korzystając z timera wystarczy, że podepniesz diodę nadawczą pod odpowiedni pin i zaprogramujesz timer na generację przebiegu o zadanej częstotliwości i wypełnieniu. Reszta robi się sama 🙂 Jeśli pozwolisz drugiemu timerowi odliczać czas 600us to nagle okazuje się, że procesor robi wszystko co sobie zaplanowałeś a dysponujesz jeszcze 90% jego mocy obliczeniowej. Chyba warto.

Link do komentarza
Share on other sites

coś jest nie tak bo widać co jakiś czas iskierke i nic poza tym

widzę, że diody pulsują ale ich moc jest tak niewielka, że ledwo je widać. Czy może mieć to związek z zasilaniem z programatora USB?

Zmieniłem toggle_delay na 13. W późniejszym etapie chcę wykorzystać sprzętowe generowanie 38khz ale póki co chciałbym uruchomić to aby w miare działało 🙂

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

Mnie się wydaje, że łatwiej włączyć timer w trybie CTC niż kombinować z odmierzaniem czasu delay'ami. Noty katalogowe i rejestry nie gryzą 😉 Jak już tak bardzo nie chcesz z nich korzystać, to ci pomogę, ale lepiej jak to zrobisz sam 😋

Link do komentarza
Share on other sites

bardzo chętnie podzielę się również takim:

napięcie na diodzie IR wynosi 1.15V co sprawdziłem woltomierzem, natężenie 6.6 mA co sprawdziłem amperomierzem 🙂

wiem, że moja poprzednia wiadomość nie była 'so specific' 🙂

EDITKA:

zmieniłem opornik z 30Ohm na 9Ohm, natężenie podskoczyło do 66mA i teraz dioda mam dość sporą moc, teraz pobawię się z tym timerem chociaż troche się tego boje, zawsze uważałem, że timery to najlepsze wyjście ale w ich stosowaniu mam małe doświadczenie, muszę poczytać co i jak poustawiać i spróbuję. Podziele się kodem później dla potomnych a i pewnie pytań będę miał sporo.

Link do komentarza
Share on other sites

Czy dotarła uwaga o złej wartości stałej odpowiedzialnej w programie za długość okresu modulacji IR?

Kombinujesz bez sensu z opornikami a przy prawidłowym przebiegu z diody nadawczej typowy odbiornik będzie ją widział z odległości nawet kilkunastu metrów.

EDIT:

"..natężenie podskoczyło do 66mA.."

To pewnie i ciśnienie Ci podskoczy gdy wreszcie przeczytasz, że porty procesora mają obciążalność 3 razy niższą. Masz więcej tych procków? Czy to jest prąd mierzony w stanie statycznym czy uśredniony miernikiem podczas modulacji 50%?

Link do komentarza
Share on other sites

Podmieniłem ten rezystor na ograniczający prąd do 0.20 mA, z tego co wyczytałem w datashecie, aby w przerwaniu przełączać pin z odpowiednią częstotliwościa wymodziłem coś takiego:

int main(void)

{

DDRB |= (1 << PB0); // Ustawienie PB0 jako wyjscie

TCCR0A |= (1 << COM0A0); // Ustawienie COM0A1 na ToggleOC0A

TCCR0A |= (1 << WGM01);

TIMSK0 |= (1 << 2); // Ustawienie OCIE0A czyli Timer/Counter0 Output Compare Match A Int Enable

OCR0A = 125; // Zmiana stanu pinu z f = 38KHz

TCCR0B |= (1 << CS00);

sei();

for (;😉

{

TCCR0B ^= (1 << CS00);

_delay_ms(500);

}

return 0;

}

z tego co mi się wydaje, nie będę potrzebował funkcji obsługi przerwania bo ta jest niejako zagwarantowana sprzętowo (przełączanie pinu)?

125 ponieważ: f_proc: 9.6MHz (bez preskalera) <- z tego co wyczytalem preskaler ATTiny dotyczy wszystkich f tego procka, N = 1, OCRnx = 125

wiec 9600KHz / (2 * 1 * (1 + 125))

Link do komentarza
Share on other sites

Powinieneś zacząć odróżniać sprzęt procesora od jego oprogramowania. Timer jest zasobem sprzętowym. Samodzielnie potrafi liczyć, sterować pinami (np. set, reset, toggle lub PWM) a także zgłaszać przerwania. Te ostatnie są łącznikiem między tym co dzieje się w sprzęcie a tym co robi program. Przerwanie jest sygnałem sprzętowym generowanym przez jakiś zasób (np. timer czy UART) w celu zwrócenia uwagi programu na zajście jakiegoś zdarzenia. Jeżeli - jak piszesz - nie potrzebujesz przerwań bo całość rzeczy jaką chcesz robić załatwi samodzielnie timer to po co:

- grzebiesz w rejestrze TIMSK

- odpalasz globalne zezwolenie na przyjmowanie przerwań?

Przerwanie - jak sama nazwa wskazuje, służy do przerywania pracy aktualnie wykonywanego kawałka programu i zmusza procesor do wykonania specjalnej funkcji, nazywanej obsługą przerwania. Kompilator musi zostać poinformowany która funkcja jest "przypięta" do którego przerwania za pomocą specjalnego słowa "ISR" umieszczonego w jej (tej funkcji) nagłówku. Ty ich nie używasz, nie napisałeś takiej funkcji więc niepotrzebnie przerwaniami zaprzątasz sobie głowę i zaciemniasz kod. Skoro timer sam sobie radzi z odwracaniem stanu pinu - niech to robi, daj mu spokój.

Zdarzeniem sprzętowym potencjalnie mogącym wygenerować przerwanie jest tutaj właśnie odwrócenie stanu pinu i procesor może, ale nie musi zostać o tym poinformowany. Gdybyś np. chciał dokładnie wiedzieć ile razy pin został odwrócony wtedy musiałbyś napisać odpowiednią funkcję obsługi tego przerwania i w niej zliczać liczbę wystąpień. Zamiast tego zrobiłeś główną pętlę odliczającą po prostu pewien czas i blokującą zegar timera. To jest proste, choć ma jedną wadę: zatrzymując timerowi zegar w przypadkowym momencie jego pracy i nigdy nie wiesz w jakim stanie jest akurat pin sterujący diodą. Średnio w połowie przypadków będziesz zatrzymywał generację fali IR z włączoną diodą - to chyba niedobrze. Gdybyś po zablokowaniu zegara dodatkowo zabronił timerowi sterowania pinem (TCCR0A = 0) to pokazałby się tam wtedy stan odpowiedniego bitu rejestru PORTB, który możesz sobie ustawić gdzieś na początku programu raz na zawsze tak, by dioda była wyłączona. Musiałbyś też za każdym razem ponownie zezwalać timerowi na starowanie pinem przed każdym puszczeniem zegara.

Prąd 0.20mA jest chyba jednak zbyt mały. Może jednak 20mA? To całkiem dobra wartość i wystarcza do kilkumetrowych zasięgów.

Link do komentarza
Share on other sites

Oczywiście chodziło mi o 20mA.

Bardzo dziękuję Ci za pomoc, Twoje wytłumaczenie wiele mi uświadomiło (tak mi się wydaje 🙂)

#define WAVEFORM_LENGTH 1
#define REFRESH_DELAY 500
int main(void)
{
   DDRB |= (1 << PB0); // Ustawienie PB0 jako wyjscie
   PORTB |= (0 << PB0);
   TCCR0A |= (1 << COM0A0) | (1 << WGM01); // Ustawienie COM0A1 na ToggleOC0A
   OCR0A = 126; // Zmiana stanu pinu z f = 38KHz
   TCCR0B |= (1 << CS00);
   for (;;)
   {
       TCCR0B = (0 << CS00);
       TCCR0A = 0;
       _delay_ms(REFRESH_DELAY);
       TCNT0 = 0;
       TCCR0A = ((1 << COM0A0) | (1 << WGM01));
       OCR0A = 126;
       TCCR0B = (1 << CS00);
       _delay_ms(WAVEFORM_LENGTH);
   }
   return 0;
}

Wydaje mi się, że aktualny układ wpisywania do rejestrów wartości nie jest optymalny (być może psuje nawet całą wiązkę a przynajmniej takie mam wrażenie czasem).

Mam troche dziwny problem żeby utrzymać to działające stabilnie. Wygląda to trochę jakby nadajnik działał dość losowo. Czasem udaje się go dość długo stabilnie utrzymać i odbiornik poprawnie widzi wiązkę, innym razem wysyła cholera wie co i odbiornik głupieje. Tu pojawiają się też pierwsze pytania o to jak radzić sobie z przypadkami false detection. Myślałem, żeby może zamiast prostego 0101010101 wysyłać jakiś wzór?

Link do komentarza
Share on other sites

dobra, poradziłem sobie z większością problemów i bariera działa całkiem fajnie. Nurtuje mnie jednak pewna kwestia do której nie wiem jak podejść. Otóż wymaganiem które muszę spełnić jest logowanie przecięcia wiązki do bazy danych. I tu pojawia się problem ponieważ w jaki sposób mam zagwarantować 1 wywołanie funkcji na 1 przecięcie wiązki. Wiemy dobrze, że warunki nie są idealne i obiekt może poruszać się zbyt wolno (odbiornik otrzyma rzadziej sygnał IR ale otrzyma) albo sygnał zostanie odbity i dotrze do czujnika. Mój Tssp4038 jest bardzo wrażliwy, nawet na sygnał odbity

drgania styków odbiornika wyeliminowałem oraz ogólny przypadek 1 wywołania funkcji na 1 przecięcie wiązki już mam.

Link do komentarza
Share on other sites

drgania styków odbiornika wyeliminowałem oraz ogólny przypadek 1 wywołania funkcji na 1 przecięcie wiązki już mam.

Jak w TSOPie mogą ci drgać styki ?

Rozwiązaniem twojego problemu jest kodowanie wiązki. wtedy dokładnie wiesz co odebrałeś, swój sygnał, czy jakieś zakłócenie z zewnątrz. Od biedy możesz wykożystać jakiś system kodowania pilotów RTV, ale odradzam, chyba że zastosujesz jaki przestarzały kod jak RECS80, ostatecznie zerżnąć kodowanie z kostek MC145027 lub HT12.

Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • 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.