Jak Arduino może wyprowadzać określoną (tj. 56 kHz) częstotliwość nośną?

9

Pracuję nad projektem optyki kosmicznej, aby bezprzewodowo przesyłać dane między dwoma punktami. Aby to osiągnąć, używam diody podczerwieni podłączonej do Arduino Uno, która pulsuje częstotliwością nośną 56 kHz dla nadajnika i drugiego Arduino z modułem detektora IR 56 kHz dla odbiornika.

Próbowałem użyć delayMicroseconds () między poleceniami pin high i pin low, aby utworzyć częstotliwość nośną. Ten rodzaj działa, ale częstotliwość nie zawsze jest taka sama, a wszelkie dodatkowe opóźnienia pulsowania sygnału (tj. Czas wymagany do wywołania funkcji i zmniejszenia) mogą go zmienić.

Po przeczytaniu arkusza danych ATmega328 wydaje się, że istnieje sposób na ustawienie dokładniejszego impulsu za pomocą timerów układu. Czy to możliwe, a jeśli tak, to w jaki sposób wytworzyć impuls 56 kHz za pomocą timerów?

jlbnjmn
źródło
Jakiej dokładności potrzebujesz dla częstotliwości 56 kHz? Czyli jaki zakres częstotliwości jest akceptowalny w twoim projekcie? Pytam, ponieważ używając samych zegarów Arduino precyzja ma ograniczenia.
jfpoilpret
Od 55,5 kHz do 56,5 kHz byłoby idealne, aby utrzymać wysoki poziom reaktywności detektora.
jlbnjmn

Odpowiedzi:

10

Rzeczywiście jest możliwe wygenerowanie sygnału 56 kHz za pomocą timera Arduino .

W rzeczywistości zegar może być postrzegany jako specjalny rejestr w MCU, który przechowuje wartość (zaczynającą się od 0), która jest zwiększana o częstotliwość, która jest częstotliwością zegara MCU (16 MHz w Arduino Uno), możliwość podzielona przez współczynnik zwany prescaler . Kiedy ta wartość osiągnie limit, o nazwie Porównaj dopasowanie , który określisz, wtedy zdarzają się dwie rzeczy:

  • Wartość rejestru timera jest resetowana do 0.
  • Wywoływana jest jedna funkcja wywołania zwrotnego ISR (procedura obsługi przerwań) (można ją zdefiniować tak, aby wskazywała własny kod).

Chodzi o to, aby użyć tego ISR do zmiany wyjścia logicznego pinu za każdym razem, gdy jest on wywoływany ( HIGHa LOWnastępnie HIGH...).

Teraz, aby wygenerować falę kwadratową o częstotliwości 56 kHz, będziesz potrzebować swojego ISR, aby nazywać go 56000 * 2razy na sekundę ( * 2ponieważ musisz zmienić wartość wyjściową dwa razy na okres).

Możesz wybrać wartość preskalera dla timera z poniższej listy:

  • 1 (częstotliwość zegara nie jest podzielona, ​​stąd 16 MHz)
  • 8 (częstotliwość zegara jest podzielona przez 8, stąd 2 MHz)
  • 64
  • 256
  • 1024

Istnieją dwa rozmiary timerów / liczników na Arduino Uno (tak naprawdę nazywane są timerem / licznikiem ): 8 bitów i 16 bitów.

W Arduino Uno (ATmega328P) masz ogólnie trzy timery, ale niektóre z nich mogą być używane przez podstawową bibliotekę Arduino lub inne biblioteki używane w swoich szkicach (musisz to sprawdzić samodzielnie):

  • timer0 (8-bit)
  • timer1 (16-bitowy)
  • timer2 (8-bit): ten ma więcej opcji wstępnego skalowania (1, 8, 32, 64, 128, 256 i 1024)

Teraz musisz wygenerować falę 56 kHz z 16 MHz, dlatego bez wstępnego przeskalowania musisz liczyć na:

16000000 / (56000 * 2) - 1 = 141.857( - 1ponieważ licznik liczy od 0 do tej wartości i resetuje się dopiero po jej osiągnięciu)

Na podstawie tych obliczeń możemy wyciągnąć dwie obserwacje:

  1. 141.857 nie jest liczbą całkowitą i dlatego nie będziesz w stanie wygenerować fali dokładnie 56 kHz.
  2. Bez wstępnego skalowania potrzebny jest 16-bitowy zegar, ponieważ 285 nie jest reprezentowane jako 8-bitowa liczba całkowita bez znaku.

Od teraz masz dwie opcje:

  1. Użyj 16-bitowego timera ( timer1 ), użyj prescaler = 1 i wybierz 142jako porównanie dopasowania; który da ci następującą częstotliwość:16000000 / (2 * (142 + 1)) = 55944 Hz
  2. Użyj 8-bitowego timera ( timer0 ), użyj prescaler = 8 i wybierz 17jako porównanie dopasowania; która da mniejszą precyzję przy następującej częstotliwości: 16000000 / (8 * 2 * (17 + 1)) = 55555 Hzktóra wciąż mieści się w wymaganym zakresie.

Jeśli chodzi o sposób napisania szkicu, radzę zapoznać się z instrukcją, która jest bardzo kompletna i bardzo interesująca do przeczytania.

Oczywiście kompletny arkusz danych ATmega328P jest również ważny, jeśli chcesz zrozumieć, w najdrobniejszych szczegółach, co robisz.

Kilka ważnych uwag:

  • ISR jest wykonywany z wyłączonymi przerwaniami i dlatego musi być jak najkrótszy. W szczególności istnieje kilka funkcji z biblioteki Arduino, które nie będą wywoływane z ISR.
  • Zegar Arduino Uno nie jest bardzo dokładny (używa rezonatora ceramicznego zamiast kwarcu, co byłoby znacznie dokładniejsze), więc oznacza to, że częstotliwość wyjściowa będzie się dalej przesuwać.
jfpoilpret
źródło
2
Również po osiągnięciu określonego limitu sprzęt może przełączyć pin. Dlatego w ogóle nie ma potrzeby korzystania z ISR. Zawsze będzie jitter z ISR bo instrukcja nie może być przerwany po jego uruchomieniu. Jednak sprzęt zawsze przełącza pin z żądaną szybkością.
Nick Gammon
Nieco zaskakujące jest to, że Arduino Uno używa ceramicznego rezonatora, ale jego źródłem jest Arduino UNO FAQ (w pobliżu „Czy Uno używa rezonatora lub kryształu do zegara procesora?” ).
Peter Mortensen
3

Przydało mi się tone()generowanie impulsów o wysokiej częstotliwości na dowolnym pinie. Powinien być w stanie obsłużyć 56 KHz. (Edycja: Jak zauważył jfpoilpret, najbliższe, jakie można uzyskać na Arduino 16 MHz, to około 55,944 KHz)

Trudność będzie oczywiście polegała na połączeniu go z sygnałem danych. Nie sądzę, że można to zrobić w oprogramowaniu bez uciekania się do kodu niskiego poziomu. Sprzęt powinien być dość łatwy, ponieważ jest cyfrowy.

Wszystko, co musisz zrobić, to wysłać sygnał danych na inny pin, a następnie połączyć go z nośną za pomocą bramki AND. Połączony sygnał może trafić bezpośrednio do nadajnika podczerwieni.

Jeśli nie masz pod ręką bramki AND, to dość łatwo jest stworzyć własną za pomocą pary tranzystorów. Wystarczy wyszukać online „tranzystor i bramka”.

Peter Bloomfield
źródło
Odbiorniki często mają ogólnie aktywne niskie wartości wyjściowe. Jeśli podłączysz górną część diody LED do 56kHz, a dolną do pinu danych, kiedy pin danych spadnie, otrzymasz wyjście IR, które powinno sprawić, że odbiornik będzie niski. Nie potrzebna jest brama, tylko led i rezystor. Jedyny problem jest ograniczony do tego, co może prowadzić obecny pin IO.
EternityForest,
2

Przyjęta odpowiedź jfpoilpret jest bardzo dobrze napisana, doskonale poprawna iw 99% przypadków zrobię dokładnie to, co on wyjaśni. Jego rozwiązania mieszczą się w określonych parametrach, więc powinny działać bardzo dobrze. Ale co jest lepszego niż „ bardzo dobrze ”? Doskonałość! W końcu chodzi o wygenerowanie dokładnej wartości. Jak powiedziano, wystarczająco blisko jest dobre w większości przypadków (prawdopodobnie wszystkie), a nawet mając do czynienia z zegarem, gdy 1 sekunda musi wynosić 1 sekundę, nadal musisz cierpieć z powodu niedoskonałości odziedziczonych części.

To, co zasugeruję, nie zawsze jest możliwe. W niektórych przypadkach jest to możliwe, ale przy znacznie większym wysiłku i wysiłku niż w tym przypadku. Czy warto, zależnie od przypadku. Moim celem jest przede wszystkim pokazanie alternatywy dla przyszłych referencji, która jest lepsza w nieco marginalnych przypadkach. Jest to napisane z myślą o początkujących użytkownikach Arduino, którzy nie mają dużego doświadczenia w elektronice.

Dla bardziej zaawansowanych ludzi prawdopodobnie będzie to wyglądać zbyt rozwlekle i głupio. Ale wierzę, że ci sami ludzie prawdopodobnie już to wiedzą i nie potrzebują tej odpowiedzi. Dotyczy to również każdego mikrokontrolera oraz każdego producenta i architektury. Jednak w przypadku innych mikrokontrolerów należy zapoznać się z właściwym arkuszem danych, aby znaleźć odpowiednie rejestry oraz wstępnie skalować nazwy i wartości.

W twoim przypadku potrzebujesz konkretnej częstotliwości, a miłą rzeczą jest to, że dokładnie 56 kHz można osiągnąć bardzo łatwo (nie licząc praktycznych niedoskonałości części). Jest to więc również doskonały przykład.

Generowanie sygnału zależy od timerów i źródła zegara mikrokontrolera, co dobrze wyjaśniono w jfpoilpret. Jego odpowiedź dotyczy problemu tylko jednego punktu widzenia i bawi się licznikami czasu. Ale możesz także bawić się ze źródłem zegara, a nawet lepiej, zarówno w celu uzyskania synergii, jak i niesamowitych wyników. Zmieniając parametry środowiska, w tym przypadku włamując się do systemu i zastępując źródło zegara, możemy poradzić sobie z konkretnym problemem o wiele, wiele łatwiej i łatwiej.

Najpierw przypomnijmy, ze względu na przełączanie stanu pinów, musisz wykonać ISR dwa razy więcej niż częstotliwość sygnału. To 112 000 razy na sekundę. 56 000 i 16 000 000 nie sumuje się tak ładnie, jak już wspomniano. Musimy zmienić częstotliwość sygnału lub częstotliwość taktu. Zajmijmy się na razie niezmienną częstotliwością sygnału i znajdźmy lepszą częstotliwość zegara.

Najłatwiej byłoby wybrać zegar o pewnym rzędzie wielkości większym niż 56 kHz (lub 112 kHz, ale jest praktycznie taki sam), ponieważ dodajesz tylko zera, a matematyka jest najprostsza dla większości ludzi. Niestety wszystko na tym świecie jest z czymś kompromisem. Nie każda wartość będzie działać.

Pierwszy przykład dotyczy zbyt niskiej prędkości generatora taktu.

Jeśli wybierzesz zegar o częstotliwości 56 000 Hz, nie będziesz w stanie nic zrobić, ponieważ będziesz musiał wywoływać ISR w każdym cyklu i nie będziesz mógł zrobić nic innego. Jest to całkowicie bezużyteczne. Jeśli wybierzesz 10-krotnie większą prędkość (560 kHz), będziesz mieć 9 (10 cykli, aby zegar osiągnął maksymalną wartość - jeden cykl, aby wywołać funkcję ISR) cykli mikrokontrolera, aby wykonać twoją pracę i to całkiem możliwe, może to nie wystarczyć. Po prostu często potrzebujesz większej mocy obliczeniowej.

Jeśli z drugiej strony wybierzesz wartość zbyt wielką, ponieważ 56 MHz mikrokontroler po prostu nie może z nią pracować. To jest zbyt szybkie. Tak więc samo wybranie największej wartości w sklepie też jej nie zmniejszy.

Oryginalny Arduino Uno R3 ma zapasowy zegar 16 MHz, więc wszystko wolniejsze, co gwarantuje działanie. Kolejna wartość, która jest o rząd wielkości większa niż 56 i mniejsza niż 16 MHz, wynosi 5,6 MHz. Doprowadzi to do możliwości wywoływania ISR co 50 cykli i stworzy idealną częstotliwość zegara wynoszącą 112 000 Hz. Twój sygnał wyniesie dokładnie 56 kHz. Będziesz miał 49 cykli MCU, aby wykonać swój program między wywołaniami ISR, ale nadal jest to około 1/3 prędkości oryginalnego zegara. Można użyć numeru 112 jako podstawy i użyć zegara 11,2 MHz, co da około 2/3 podstawowego rezonatora 16 MHz. Funkcja ISR będzie wywoływana co 100 cykli i nadal generuje doskonały sygnał 56 kHz.

Istnieją jednak dwa główne problemy z tymi wartościami.

  • Pierwszy problem poważnie zależy od twoich potrzeb: poświęcasz około 1/3 (przy 11,2 MHz) maksymalnej mocy obliczeniowej, aby uzyskać dokładną częstotliwość sygnału, która wykorzystuje łatwą do znalezienia wartość rejestru (OCR iirc ). Możesz sobie z tym poradzić lub nie.

  • Drugi problem to trudny showstopper : bardzo łatwo jest znaleźć wartości, ale bardzo często po prostu nie istnieją one jako wyprodukowane źródło zegara. To strona rezonatora Farnella, której po prostu brakuje zarówno 5,6 MHz, jak i 11,2 MHz.

Aby tego uniknąć, możemy przyjrzeć się dostępnym wartościom rezonatora i dowiedzieć się czegoś innego, co można wykorzystać do wygenerowania dokładnie pożądanych wartości. Jeśli podzielimy 56 przez 4, otrzymamy 14 i na szczęście powstanie rezonator 14 MHz. To zapewnia nam znacznie większą prędkość i więcej mocy oraz równie łatwą do znalezienia wartość rejestru. Aby wywołać ISR 112 000 razy na sekundę, musimy wpisać wartość dziesiętną 124 lub szesnastkową 0x7C do rejestru OCR, więc licząc 124 cykle + 1 dla wywołania ISR, otrzymujemy pożądaną idealną wartość.

NB

  1. ISR - procedura obsługi przerwań (jest to kod wykonywany tylko na wygenerowanych przerwaniach)
  2. Jak duży może być Twój program, zależy od wielkości pamięci! Nie ma to nic wspólnego z częstotliwością zegara i nie ma związku z częstotliwością wywoływania ISR.
  3. Kiedy mikrokontroler zaczyna się od polecenia programu, licznik jest zwiększany. Jeśli generowane jest przerwanie, wywoływany jest ISR i ta wartość jest przechowywana w specjalnym rejestrze. Po zakończeniu kodu ISR wartość licznika programu jest przywracana z tego specjalnego rejestru, a program kontynuuje działanie od miejsca, w którym został przerwany, jak gdyby nigdy się nie zdarzyło.

    Podam wyjątkowo głupi przykład. Jeśli jesteś purystą, ostrzegam: może wystąpić krwawienie z nosa i oka.

    Wyobraź sobie, że musisz gdzieś iść. Instrukcje trasy krok po kroku to twój główny program i jego polecenia. Szybkość marszu lub biegu zależy od „prędkości zegara”, ale nie od instrukcji na trasie (30 kroków do przodu, 1 skręt o 90 stopni w lewo, 10 kroków do przodu, 45 stopni w prawo itp.) Zawsze są takie same . Teraz wyobraź sobie, że małe dziecko lub chciwy skorumpowany lokalny polityk od czasu do czasu rozwiązuje twoje buty. To zdarzenie generuje przerwanie. Potem zatrzymujesz się po ostatnim kroku, klękasz i ponownie wiążesz but. To jest twój program ISR.

    Następnie kontynuuj od miejsca, w którym się zatrzymałeś; nie zaczynasz od początku. Kiedy idziesz bez opieki po świecie i cały czas, nie przejmujesz się, nawet jeśli musisz wiązać but co drugi krok. Jeśli jednak zrobisz to z ograniczeniami czasowymi, takimi jak bieganie w odległości 100 metrów na olimpiadzie (lub bieganie z głodnego drapieżnika, który zjada mięso), zatrzymanie i zawiązanie butów może mieć tragiczne konsekwencje. To samo dotyczy mikrokontrolerów. Nawet jeśli wykonasz tylko jedną linię kodu, twój program będzie kontynuował, choć powolny. Jeśli w ogóle nie zależy ci na prędkości, nie będzie problemu. Jeśli musisz zrobić trochę czasu, na przykład używając innych działań zależnych od timera, interferencja może być bardzo niepożądana i problematyczna.

  4. Mniej znaczy więcej! Szybszy zegar nie zawsze jest lepszy. Wolniej taktowane urządzenia zużywają znacznie mniej energii. Może to być kluczowy punkt w urządzeniu zasilanym bateryjnie.

  5. Potrzebne cykle pochodzą z tych wzorów:
    (prędkość zegara / (wartość prekalera * potrzebna częstotliwość wywoływania ISR)) - 1

zzz
źródło
TLDR: Rozlutuj ceramiczny oscylator 16 MHz i zastąp go innym, który pozwala dokładnie 56 kHz przez podział liczb całkowitych (np. 14 MHz i podział przez 250).
Peter Mortensen
0

Możesz włączyć i wyłączyć nośnik, po prostu przełączając tryb styku nośnika między wyjściem a wejściem. Użyłem tego do sterowania pompą ciepła przez port podczerwieni 37 kHz (zdalne sterowanie).

kiwiron
źródło
0

Nie ma potrzeby używania ISR do utworzenia przewoźnika. Wystarczy skonfigurować zegar, aby uzyskać 50% mocy wyjściowej PWM przy wymaganej częstotliwości nośnej. ISR odpowiada wówczas za modulowanie nośnika - zwykle w odstępach 0,5 lub 1 ms - o wiele bardziej komfortową stawkę. Z mojego doświadczenia wynika, że ​​5% błąd częstotliwości nośnej jest tolerowany przez większość odbiorników IR. Użyłem Freetronics EtherMega 2560 (który ma mnóstwo zegarów), ale jestem pewien, że inne procesory poradzą sobie równie dobrze.

kiwiron
źródło
Jak dokładnie zatem realizowana jest modulacja nośnika? Zmieniasz tryb przechwytywania wyjścia timera między wejściem (nośnik wyłączony) a wyjściem (nośnik włączony)?
Peter Mortensen