Vraag:
Hoe kan een Arduino een specifieke (d.w.z. 56 kHz) draaggolffrequentie uitvoeren?
jlbnjmn
2014-02-24 06:55:35 UTC
view on stackexchange narkive permalink

Ik werk aan een optiekproject voor vrije ruimte om gegevens draadloos tussen twee punten te verzenden. Om dit te bereiken gebruik ik een IR-led die is aangesloten op een Arduino Uno die pulseert met een 56 kHz-draaggolffrequentie voor de zender en een tweede Arduino met een 56 kHz IR-detectormodule voor de ontvanger.

Ik heb het geprobeerd door delayMicroseconds () te gebruiken tussen pin high en pin low commando's om de draaggolffrequentie te creëren. Dit werkt, maar de frequentie is niet altijd hetzelfde en eventuele extra vertragingen voor het pulsen van het signaal (dwz de tijd die nodig is om de functie aan te roepen en af ​​te nemen) kunnen het veranderen.

Het lezen van de datasheet voor de ATmega328 blijkt dat er een manier is om een ​​nauwkeurigere puls in te stellen met behulp van de timers van de chip. Is dat mogelijk, en zo ja, hoe creëer je een 56 kHz puls met behulp van de timers?

Wat is de nauwkeurigheid die u nodig heeft voor uw 56 KHz-frequentie? D.w.z. welk frequentiebereik is acceptabel in uw project? Ik vraag het omdat precisie alleen met Arduino-timers beperkt is.
55,5 khz tot 56,5 khz zou ideaal zijn om een ​​hoog reactievermogen in de detector te behouden.
Vijf antwoorden:
#1
+10
jfpoilpret
2014-02-25 02:45:44 UTC
view on stackexchange narkive permalink

Het is inderdaad mogelijk om een ​​56 kHz signaal te genereren met een Arduino timer.

Een timer kan eigenlijk gezien worden als een speciaal register, in de MCU, dat een waarde (beginnend bij 0) die wordt verhoogd met een frequentie die de MCU-klokfrequentie is (16 MHz op Arduino Uno), mogelijkheid gedeeld door een factor genaamd Prescaler . Wanneer die waarde een limiet bereikt, Compare Match genaamd, die u specificeert, gebeuren er twee dingen:

  • De waarde van het timerregister wordt gereset naar 0.
  • Een ISR (interrupt service routine) callback-functie wordt aangeroepen (u kunt deze zo definiëren dat deze naar uw eigen code verwijst).

Het idee is om die ISR om de output van een logische pin te veranderen elke keer dat deze wordt aangeroepen ( HIGH , dan LOW , dan HIGH ...). / p>

Om een ​​blokgolf van 56 kHz te genereren, moet je ISR 56000 * 2 keer per seconde worden gebeld ( * 2 omdat u de outputwaarde twee keer per periode moet wijzigen).

U kunt de voorloperwaarde die u wilt voor een timer kiezen uit de volgende lijst:

  • 1 (klokfrequentie niet gedeeld, dus 16 MHz)
  • 8 (klokfrequentie wordt gedeeld door 8, dus 2 MHz)
  • 64
  • 256
  • 1024

Er zijn twee maten timers / tellers op Arduino Uno (ze zijn e noemde eigenlijk timer / teller ): 8 bits en 16 bits.

Op Arduino Uno (ATmega328P) heb je in totaal drie timers, maar sommige kunnen worden gebruikt door de Arduino-kern bibliotheek of andere bibliotheken die in je schetsen worden gebruikt (dat moet je zelf controleren):

  • timer0 (8-bit)
  • timer1 (16-bit)
  • timer2 (8-bit): deze heeft meer opties voor voorschalen (1, 8, 32, 64, 128, 256 en 1024)

Nu moet je genereren een 56 kHz golf vanaf 16 MHz, dus zonder voorcalculatie zou u moeten tellen tot:

16000000 / (56000 * 2) - 1 = 141.857 ( - 1 omdat een timer telt van 0 tot deze waarde en alleen wordt gereset na het is bereikt)

Uit deze berekening kunnen we twee observaties trekken:

  1. 141.857 is geen geheel getal en dus heb je gewonnen ' t in staat zijn om een ​​golf van precies 56 kHz te genereren.
  2. Zonder voorcalculatie heb je een 16-bits timer nodig, aangezien 285 niet kan worden voorgesteld als een 8-bits geheel getal zonder teken.

Vanaf nu heb je twee opties:

  1. Gebruik een 16-bits timer ( timer1 ), gebruik Prescaler = 1 en selecteer 142 als Compare Match; dat geeft je de volgende frequentie: 16000000 / (2 * (142 + 1)) = 55944 Hz
  2. Gebruik een 8-bit timer ( timer0 ), gebruik prescaler = 8, en selecteer 17 als vergelijkingsmatch; dat geeft minder precisie met de volgende frequentie: 16000000 / (8 * 2 * (17 + 1)) = 55555 Hz die nog steeds binnen het vereiste bereik ligt.

Nu, wat betreft het schrijven van je schets daarvoor, raad ik je aan om deze instructable te bekijken, die erg compleet en erg interessant is om te lezen.

Natuurlijk, de ATmega328P complete datasheet is ook belangrijk als u tot in de kleinste details wilt begrijpen wat u doet.

Enkele belangrijke opmerkingen:

  • An ISR wordt uitgevoerd met uitgeschakelde interrupts en moet dus zo kort mogelijk zijn. In het bijzonder zijn er verschillende functies uit de Arduino-bibliotheek die niet vanaf een ISR zullen worden aangeroepen.
  • Arduino Uno-klok is niet erg nauwkeurig (hij gebruikt een keramische resonator in plaats van een kwarts, wat veel zou zijn geweest nauwkeuriger), dus dit betekent dat de uitgangsfrequentie verder zal verschuiven.
Ook wanneer de opgegeven limiet is bereikt, kan de * hardware * een punaise omschakelen. Het is dus helemaal niet nodig om ISR's te gebruiken. Er zal altijd * jitter * zijn met een ISR omdat een instructie niet kan worden onderbroken als deze eenmaal is gestart. De hardware schakelt de pin echter altijd met de gewenste snelheid.
Het is enigszins verrassend dat de Arduino Uno een keramische resonator gebruikt, maar een bron hiervoor is * [Arduino UNO FAQ] (https://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-uno- faq) * (nabij * "Gebruikt de Uno een resonator of een kristal voor de processorklok?" *).
#2
+3
Peter Bloomfield
2014-02-24 18:02:05 UTC
view on stackexchange narkive permalink

Ik heb tone () handig gevonden voor het genereren van hoogfrequente pulsen op een pin. Het zou 56 KHz moeten aankunnen. (Bewerken: zoals opgemerkt door jfpoilpret, het dichtstbijzijnde dat je kunt krijgen op een 16 MHz Arduino is ongeveer 55.944 KHz)

De moeilijkheid zal natuurlijk zijn om het te combineren met je datasignaal. Ik denk niet dat je dat in software zou kunnen doen zonder toevlucht te nemen tot code op laag niveau. Het zou echter vrij eenvoudig moeten zijn in hardware, aangezien het digitaal is.

Het enige wat je hoeft te doen is je datasignaal op een andere pin uit te voeren en het vervolgens met de koerier te combineren met een EN-poort. Het gecombineerde signaal kan rechtstreeks naar uw IR-zender gaan.

Als u geen EN-poort bij de hand heeft, is het vrij eenvoudig om uw eigen te maken met behulp van een paar transistors. Zoek gewoon online naar "transistor en poort".

Ontvangers hebben over het algemeen vaak een actieve lage output. Als je de bovenkant van de LED op de 56khz aansluit, en de onderkant op je datapin, krijg je IR-output wanneer de datapin laag wordt, waardoor de ontvanger laag zou moeten worden. Geen poort nodig, alleen een led en weerstand. Het enige probleem is dat het beperkt blijft tot wat de huidige io-pinnen kunnen aandrijven.
#3
+2
zzz
2014-04-01 09:10:47 UTC
view on stackexchange narkive permalink

Het geaccepteerde antwoord van jfpoilpret is erg goed geschreven, perfect geldig en in 99% van de gevallen zal ik precies doen wat hij uitlegt. Zijn oplossingen vallen ruim binnen uw gedefinieerde parameters, dus ze zouden heel goed moeten werken. Maar wat is er beter dan " heel goed "? Perfectie! De vraag gaat tenslotte over het genereren van een exacte waarde. Zoals gezegd is dichtbij genoeg goed in de meeste gevallen (aantoonbaar allemaal), en zelfs als je met zoiets als een klok te maken hebt wanneer 1 seconde 1 seconde moet zijn, moet je nog steeds last hebben van onvolkomenheden in de erfelijke onderdelen.

Wat ik zal suggereren is niet altijd mogelijk. In sommige gevallen is het mogelijk, maar met veel meer gedoe en moeite dan in dit geval. Is het waardig, hangt van geval tot geval af. Mijn doel is vooral om een ​​alternatief voor toekomstige referenties te laten zien dat beter is in enigszins marginale gevallen. Dit is geschreven met beginnende Arduino-gebruikers in gedachten die geen uitgebreide ervaring hebben met elektronica.

Voor meer gevorderde mensen zal dit er waarschijnlijk te uitgebreid en saai uitzien. Maar ik geloof dat diezelfde mensen het waarschijnlijk al weten en dit antwoord niet nodig hebben. Dit geldt ook voor elke microcontroller en elke fabrikant en architectuur. Maar voor andere microcontrollers moet je de juiste datasheet raadplegen om de juiste registers en voorverkoopnamen en -waarden te vinden.

In jouw geval heb je een specifieke frequentie nodig en het leuke is dat die precies 56 kHz kan eigenlijk heel gemakkelijk worden bereikt (praktische onvolkomenheden van de onderdelen niet meegerekend). Dit is dus ook een perfect voorbeeldgeval.

Het genereren van een signaal hangt af van de timers en klokbron van de microcontroller, zoals goed uitgelegd door jfpoilpret. Zijn antwoord behandelt slechts het probleem van één gezichtspunt en dat is gehannes met timers. Maar je kunt ook met de klokbron spelen, of zelfs beter met beide voor synergie en geweldige resultaten. Door de parameters van de omgeving te wijzigen, in dit geval het systeem te hacken en de klokbron te vervangen, kunnen we een specifiek probleem met veel, veel meer gemak en eenvoud aanpakken.

Allereerst, vanwege het wisselen de pinstatus, moet u de ISR twee keer meer uitvoeren dan de signaalfrequentie. Dit is 112.000 keer per seconde. 56.000 en 16.000.000 tellen niet erg goed op, zoals al is aangegeven. We moeten de signaalfrequentie of de tactfrequentie wijzigen. Laten we nu eens kijken naar een onveranderlijke signaalfrequentie en een betere kloksnelheid zoeken.

Het zou het meest eenvoudig zijn om een ​​klok te kiezen met een orde van grootte groter dan 56 kHz (of 112 kHz, maar dat is praktisch hetzelfde), aangezien u alleen nullen toevoegt en dit soort wiskunde voor de meeste mensen het eenvoudigst is. Helaas is alles in deze wereld een soort compromis met iets. Niet elke waarde zal werken.

Het eerste voorbeeld is met een te lage tactgeneratorsnelheid.

Als je een 56.000 Hz-klok kiest, kun je niets doen zoals je zal elke cyclus de ISR moeten bellen en kan niets anders doen. Het is volkomen nutteloos. Als je kiest voor 10 keer hogere snelheid (560 kHz), heb je 9 (10 cycli voordat de timer zijn maximale waarde bereikt - één cyclus om de ISR-functie aan te roepen) microcontroller-cycli om je werk te doen en dit is heel goed mogelijk kan niet genoeg zijn. Je hebt gewoon vaak meer rekenkracht nodig.

Als je een waarde kiest die veel te groot is, zoals 56 MHz, kan de microcontroller er gewoon niet mee werken. Het is veel te snel. Dus het simpelweg kiezen van de grootste waarde in de winkel zal het ook niet besparen.

Originele Arduino Uno R3 heeft een standaardklok op 16 MHz, dus alles wat langzamer is dan gegarandeerd werkt. De volgende waarde die een grootteorde groter is dan 56 en lager dan 16 MHz is 5,6 MHz. Dit zal ertoe leiden dat we de ISR elke 50 cycli kunnen bellen en de perfecte timerfrequentie van 112.000 Hz zal creëren. En je signaal is precies 56 kHz. Je hebt 49 MCU-cycli om je programma tussen ISR-oproepen uit te voeren, maar het is nog steeds ongeveer 1/3 van de snelheid van de oorspronkelijke klok. Men kan 112 als basis gebruiken en een 11,2 MHz klok gebruiken en dit geeft ongeveer 2/3 van de standaard 16 MHz resonator. De ISR-functie wordt elke 100 cycli aangeroepen en genereert nog steeds een perfect 56 kHz-signaal.

Er zijn echter twee grote problemen met deze waarden.

  • Het eerste probleem hangt sterk af van uw behoeften: u offert ongeveer 1/3 (met 11,2 MHz) van uw maximale rekenkracht op om de exacte signaalfrequentie te krijgen die een gemakkelijk te vinden registerwaarde gebruikt (OCR iirc ). Je vindt het misschien goed of misschien niet.

  • Het tweede probleem is een harde showstopper : het is heel gemakkelijk om waarden te vinden, maar vaak bestaan ​​ze gewoon niet als een vervaardigde klokbron. Dit is Farnell's resonatorwebpagina die simpelweg zowel 5,6 MHz als 11,2 MHz mist.

Om dit te omzeilen, kunnen we kijk naar beschikbare resonatorwaarden en ontdek iets anders dat kan worden gebruikt om precies gewenste waarden te genereren. Als we 56 door 4 delen, krijgen we 14 en gelukkig is er een 14 MHz resonator. Dit geeft ons een veel hogere snelheid en meer vermogen en een even gemakkelijk te vinden registerwaarde. Om de ISR 112.000 keer per seconde te bellen, moeten we de waarde decimaal 124 of hexadecimaal 0x7C in het OCR-register plaatsen, dus met het tellen van 124 cycli + 1 voor het aanroepen van de ISR, krijgen we onze gewenste perfecte waarde.

NB

  1. ISR - interrupt service routine (dit is de code die alleen wordt uitgevoerd op gegenereerde interrupts)
  2. Hoe groot uw programma kan zijn, hangt af van de geheugengrootte! Het heeft niets te maken met de kloksnelheid en heeft niets te maken met hoe vaak je de ISR belt.
  3. Wanneer de microcontroller start met een programmacommando, wordt een teller opgehoogd. Als er een interrupt wordt gegenereerd, wordt de ISR aangeroepen en wordt deze waarde opgeslagen in een speciaal register. Wanneer de ISR-code is voltooid, wordt de waarde van de programmateller hersteld vanuit dit speciale register en gaat het programma verder waar het werd onderbroken alsof het nog nooit was gebeurd.

    Ik zal een extreem dom voorbeeld geven . Als je een purist bent, waarschuw ik je: neus- en oogbloedingen kunnen optreden.

    Stel je voor dat je van ergens naar ergens moet lopen. De stapsgewijze route-instructies zijn uw hoofdprogramma en de bijbehorende opdrachten. Hoe snel je loopt of rent, hangt af van je 'kloksnelheid', maar niet van de route-instructies (30 stappen vooruit, 1 draai 90 graden naar links, 10 stappen vooruit, 45 graden rechts, etc.) Ze zijn altijd hetzelfde . Stel je nu eens voor dat een klein kind of een hebzuchtige corrupte lokale politicus je schoenen zo nu en dan losmaakt. Dit is de gebeurtenis die een onderbreking genereert. Dan stop je na je laatste stap, kniel je en knoop je je schoen weer vast. Dit is je ISR-programma.

    Daarna ga je verder vanaf de plek waar je bent gestopt; je begint niet vanaf het begin. Als je onbezorgd in de wereld loopt en met de hele tijd loopt, maakt het je niet uit, zelfs als je je schoen om de andere stap moet strikken. Als je het echter doet met beperkte tijd, zoals 100 meter rennen op de Olympische Spelen (of rennen voor een hongerig vleesetend roofdier), kan het stoppen en strikken van je schoenen ernstige gevolgen hebben. Hetzelfde geldt voor microcontrollers. Zelfs als u slechts één regel code uitvoert, zal uw programma doorgaan, zij het traag. Als je helemaal niets om snelheid geeft, is dat geen probleem. Als u wat tijdgerelateerde dingen moet doen, zoals andere timerafhankelijke acties, kan interferentie zeer ongewenst en problematisch zijn.

  4. Minder is meer! Een snellere klok is niet altijd beter. Langzamere apparaten verbruiken aanzienlijk minder stroom. Dit kan een cruciaal punt zijn in een apparaat dat op batterijen werkt.

  5. De benodigde cycli zijn afgeleid van deze formules:
    (kloksnelheid / (voorschrijverwaarde * benodigde ISR oproepfrequentie)) - 1

TLDR: Desoldeer de keramische 16 MHz-oscillator en vervang deze door een andere die * exact * 56 kHz toestaat door een gehele deling (bijv. 14 MHz en deel door 250).
#4
  0
kiwiron
2014-03-31 14:51:33 UTC
view on stackexchange narkive permalink

U kunt de carrier eenvoudig in- en uitschakelen door de carrier-pin-modus te wisselen tussen uitvoer en invoer. Ik heb dit gebruikt om een ​​warmtepomp aan te sturen via de 37KHz infraroodpoort (afstandsbediening).

#5
  0
kiwiron
2014-04-01 13:12:01 UTC
view on stackexchange narkive permalink

Het is niet nodig om een ​​ISR te gebruiken om de koerier te maken. Stel gewoon een timer in om een ​​PWM-uitgang van 50% te produceren op de vereiste draaggolffrequentie. De ISR is dan alleen verantwoordelijk voor het moduleren van de draaggolf - meestal met intervallen van 0,5 of 1 ms - een veel comfortabelere snelheid. In mijn ervaring wordt een fout van 5% in de draaggolffrequentie door de meeste IR-ontvangers getolereerd. Ik heb een Freetronics EtherMega 2560 gebruikt (die veel timers heeft), maar ik weet zeker dat andere CPU's het net zo goed zullen doen.

Hoe wordt de modulatie van de carrier dan precies geïmplementeerd? De modus wijzigen voor de vastlegpin van de timeruitgang tussen input (carrier uit) en output (carrier aan)?


Deze Q&A is automatisch vertaald vanuit de Engelse taal.De originele inhoud is beschikbaar op stackexchange, waarvoor we bedanken voor de cc by-sa 3.0-licentie waaronder het wordt gedistribueerd.
Loading...