Arduino Timer onderbreekt

Met timeronderbrekingen kunt u een taak met zeer specifiek getimede intervallen uitvoeren, ongeacht wat er nog meer in uw code gebeurt. In deze instructable zal ik uitleggen hoe je een interrupt instelt en uitvoert in Clear Timer in Compare Match of CTC Mode. Ga direct naar stap 2 als u op zoek bent naar voorbeeldcode.

Normaal gesproken voert de Arduino bij het schrijven van een Arduino-schets alle opdrachten uit die zijn ingekapseld in de functie loop () {} in de volgorde waarin ze zijn geschreven, maar het is moeilijk om gebeurtenissen in de loop () te timen. Sommige opdrachten hebben meer tijd nodig dan andere om uit te voeren, sommige zijn afhankelijk van voorwaardelijke instructies (als, terwijl ...) en sommige Arduino-bibliotheekfuncties (zoals digitalWrite of analogRead) bestaan ​​uit veel opdrachten. Met Arduino-timeronderbrekingen kunt u de normale reeks gebeurtenissen die plaatsvinden in de loop () -functie tijdelijk onderbreken met nauwkeurig getimede intervallen, terwijl u een afzonderlijke set opdrachten uitvoert. Zodra deze opdrachten zijn uitgevoerd, pakt de Arduino weer op waar hij zich in de lus bevond ().

Onderbrekingen zijn handig voor:

Meten van een inkomend signaal met gelijkmatig verdeelde intervallen (constante bemonsteringsfrequentie)

Berekening van de tijd tussen twee gebeurtenissen

Een signaal uitzenden met een specifieke frequentie

Periodiek controleren op inkomende seriële gegevens

veel meer...

Er zijn een paar manieren om onderbrekingen te doen, voor nu zal ik me concentreren op het type dat ik het meest nuttig / flexibel vind, genaamd Clear Timer in Compare Match of CTC Mode. Bovendien zal ik in dit instructieve specifiek schrijven over de timers voor de Arduino Uno (en elke andere Arduino met ATMEL 328/168 ... Lilypad, Duemilanove, Diecimila, Nano ...). De belangrijkste ideeën die hier worden gepresenteerd, zijn ook van toepassing op de Mega- en oudere boards, maar de opstelling is een beetje anders en de onderstaande tabel is specifiek voor ATMEL 328/168.

Stap 1: Prescalers en het Compare Match Register

De Uno heeft drie timers genaamd timer0, timer1 en timer2. Elk van de timers heeft een teller die wordt verhoogd met elke tik op de timerklok. CTC-timeronderbrekingen worden geactiveerd wanneer de teller een bepaalde waarde bereikt, opgeslagen in het vergelijkingsregister. Zodra een timerteller deze waarde bereikt, wordt deze gewist (gereset naar nul) bij het volgende vinkje van de timerklok, waarna hij opnieuw doorgaat met tellen tot de vergelijkingswaarde. Door de vergelijkingswaarde te kiezen en de snelheid in te stellen waarmee de timer de teller verhoogt, kunt u de frequentie van timeronderbrekingen regelen.

De eerste parameter die ik zal bespreken, is de snelheid waarmee de timer de teller verhoogt. De Arduino-klok loopt op 16 MHz, dit is de hoogste snelheid waarmee de timers hun tellers kunnen verhogen. Bij 16 MHz vertegenwoordigt elke tik van de teller 1 / 16.000.000 seconde (~ 63ns), dus een teller heeft 10 / 16.000.000 seconden nodig om een ​​waarde van 9 te bereiken (tellers zijn 0 geïndexeerd) en 100 / 16.000.000 seconden om een ​​waarde te bereiken van 99.

In veel situaties zult u merken dat het instellen van de telsnelheid op 16 MHz te snel is. Timer0 en timer2 zijn 8 bit timers, wat betekent dat ze een maximale tellerwaarde van 255 kunnen opslaan. Timer1 is een 16 bit timer, wat betekent dat het een maximale tellerwaarde van 65535 kan opslaan. Zodra een teller zijn maximum bereikt, tikt hij terug naar nul (dit wordt overflow genoemd). Dit betekent dat bij 16 MHz, zelfs als we het vergelijkingsregister instellen op de maximale tellerwaarde, er onderbrekingen zullen plaatsvinden om de 256 / 16.000.000 seconden (~ 16us) voor de 8-bit tellers en elke 65.536 / 16.000.000 (~ 4 ms) seconden voor de 16 bit teller. Dit is duidelijk niet erg handig als u slechts één keer per seconde wilt onderbreken.

In plaats daarvan kunt u de snelheid van de toename van de timerteller regelen door iets te gebruiken dat een voorschrijver wordt genoemd. Een voorschrijver dicteert de snelheid van uw timer volgens de volgende vergelijking:

(timersnelheid (Hz)) = (Arduino-kloksnelheid (16 MHz)) / voorschrijver

Dus een 1-voorschrijver verhoogt de teller bij 16 MHz, een 8-voorschrijver verhoogt deze bij 2 MHz, een 64-voorschrijver = 250 kHz, enzovoort. Zoals aangegeven in de bovenstaande tabellen, kan de voorschrijver gelijk zijn aan 1, 8, 64, 256 en 1024. (Ik zal de betekenis van CS12, CS11 en CS10 in de volgende stap uitleggen.)

Nu kunt u de interruptfrequentie berekenen met de volgende vergelijking:

interruptfrequentie (Hz) = (Arduino-kloksnelheid 16.000.000Hz) / (voorschrijver * (vergelijk wedstrijdregister + 1))
de +1 staat daar omdat het vergelijkingsregister nul geïndexeerd is

door de vergelijking hierboven opnieuw te rangschikken, kunt u de vergelijkingswaarde van het vergelijkingsregister oplossen die uw gewenste interruptfrequentie geeft:

vergelijk matchregister = [16.000.000Hz / (voorschrijver * gewenste interruptfrequentie)] - 1
onthoud dat wanneer u timers 0 en 2 gebruikt, dit aantal kleiner moet zijn dan 256 en minder dan 65536 voor timer1

dus als je elke seconde een onderbreking wilde (frequentie van 1Hz):
vergelijk overeenkomstregister = [16.000.000 / (voorschrijver * 1)] -1
met een voorschrijver van 1024 krijg je:
vergelijk overeenkomstregister = [16.000.000 / (1024 * 1)] -1
= 15.624
sinds 256 <15.624 <65.536, moet je timer1 gebruiken voor deze interrupt.

Stap 2: Structureren van timeronderbrekingen


De code voor het instellen van de timer wordt gedaan binnen de functie setup () {} in een Arduino-schets.

De code die nodig is voor het instellen van timeronderbrekingen is een beetje ontmoedigend om naar te kijken, maar het is eigenlijk niet zo moeilijk. Ik kopieer vrijwel hetzelfde grote stuk code en verander de voorschrijver en vergelijk het wedstrijdregister om de juiste interruptfrequentie in te stellen.

De hoofdstructuur van de interruptconfiguratie ziet er als volgt uit:
 ////www.instructables.com/id/Arduino-Timer-Interrupts/ void setup () cli (); // stop interrupts // stel timer0 interrupt in op 2 kHz TCCR0A = 0; // stel het volledige TCCR0A-register in op 0 TCCR0B = 0; // hetzelfde voor TCCR0B TCNT0 = 0; // Initialiseer tellerwaarde op 0 // Stel vergelijk matchregister in voor stappen van 2 kHz OCR0A = 124; // = (16 * 10 ^ 6) / (2000 * 64) - 1 (moet <256 zijn) // schakel de CTC-modus in TCCR0A // Einde setup 
Merk op hoe de waarde van OCR # A (de vergelijkingswaarde voor overeenkomsten) verandert voor elk van deze timeropstellingen. Zoals uitgelegd in de laatste stap, werd dit berekend volgens de volgende vergelijking:

vergelijk matchregister = [16.000.000Hz / (voorschrijver * gewenste interruptfrequentie)] - 1
onthoud dat wanneer u timers 0 en 2 gebruikt, dit aantal kleiner moet zijn dan 256 en minder dan 65536 voor timer1

Merk ook op hoe de instellingen tussen de drie timers enigszins verschillen in de lijn die de CTC-modus inschakelt:
TCCR0A | = (1 << WGM01); // voor timer0
TCCR1B | = (1 << WGM12); // voor timer1
TCCR2A | = (1 << WGM21); // voor timer2
Dit volgt direct uit de datasheet van de ATMEL 328/168.

Merk ten slotte op hoe de setup voor de prescalers de tabellen in de laatste stap volgt (de tabel voor timer 0 wordt hierboven herhaald),
TCCR2B | = (1 << CS22); // Stel CS # 2 bit in voor 64 voorschrijver voor timer 2
TCCR1B | = (1 << CS11); // Stel CS # 1 bit in voor 8 voorschrijver voor timer 1
TCCR0B | = (1 << CS02) | (1 << CS00); // Stel CS # 2 en CS # 0 bits in voor 1024 voorschrijver voor timer 0

Merk in de laatste stap op dat er verschillende voorinstellingsopties zijn voor de verschillende timers. Timer2 heeft bijvoorbeeld niet de optie 1024 voorschrijver.

De opdrachten die u tijdens deze timeronderbrekingen wilt uitvoeren, bevinden zich in de Arduino-schets die als volgt is ingekapseld:
ISR (TIMER0_COMPA_vect) {// verander de 0 in 1 voor timer1 en 2 voor timer2
// onderbrekingscommando's hier
}
Dit stukje code moet zich buiten de functies setup () en loop () bevinden. Probeer ook de onderbrekingsroutine zo kort mogelijk te houden, vooral als u met een hoge frequentie onderbreekt. Het kan zelfs de moeite waard zijn om de poorten / pinnen van de ATMEL-chip rechtstreeks aan te spreken in plaats van de functies digitalWrite () en digitalRead () te gebruiken. Meer info daarover vind je hier.

Voorbeeld: de volgende schets stelt 3 timerinterrupts in en voert deze uit:

 // timer onderbreekt // door Amanda Ghassaei // juni 2012 // //www.instructables.com/id/Arduino-Timer-Interrupts/ / * * Dit programma is gratis software; u kunt het verspreiden en / of wijzigen * onder de voorwaarden van de GNU General Public License zoals gepubliceerd door * de Free Software Foundation; ofwel versie 3 van de licentie, of * (naar keuze) een latere versie. * * / // timerinstelling voor timer0, timer1 en timer2. // Voor arduino uno of elk bord met ATMEL 328/168 .. diecimila, duemilanove, lilypad, nano, mini ... // deze code zal alle drie de arduino timer-interrupts mogelijk maken. // timer0 wordt onderbroken bij 2 kHz // timer1 wordt onderbroken bij 1 Hz // timer2 wordt onderbroken bij 8 kHz // opslagvariabelen boolean toggle0 = 0; boolean toggle1 = 0; boolean toggle2 = 0; ongeldige setup () // set pinnen als uitgangen pinMode (8, OUTPUT); pinMode (9, OUTPUT); pinMode (13, OUTPUT); cli (); // stop onderbreekt // zet timer0 interrupt op 2kHz TCCR0A = 0; // zet het volledige TCCR2A-register op 0 TCCR0B = 0; // hetzelfde voor TCCR2B TCNT0 = 0; // initialiseer tellerwaarde op 0 // set vergelijk wedstrijdregister voor stappen van 2 kHz OCR0A = 124; // = (16 * 10 ^ 6) / (2000 * 64) - 1 (moet <256 zijn) // schakel CTC-modus in TCCR0A // eindconfiguratie ISR (TIMER0_COMPA_vect) { // timer0 onderbreken 2 kHz schakelt pin 8 // genereert pulsgolf met frequentie 2 kHz / 2 = 1 kHz (duurt twee cycli voor volledige golf - schakelt hoog en vervolgens laag) als (toggle0) {digitalWrite (8, HIGH); toggle0 = 0; } anders {digitalWrite (8, LOW); toggle0 = 1; }} ISR (TIMER1_COMPA_vect) {// timer1 onderbreken 1Hz schakelt pin 13 (LED) // genereert pulsgolf met frequentie 1Hz / 2 = 0, 5kHz (duurt twee cycli voor volledige golf - schakel hoog en vervolgens laag) if (toggle1) { digitalWrite (13, HIGH); toggle1 = 0; } anders {digitalWrite (13, LOW); toggle1 = 1; }} ISR (TIMER2_COMPA_vect) {// timer1 onderbreken 8 kHz schakelt pin 9 // genereert pulsgolf van frequentie 8 kHz / 2 = 4 kHz (duurt twee cycli voor volledige golf - schakelt hoog en vervolgens laag) als (toggle2) {digitalWrite (9, HOOG); toggle2 = 0; } anders {digitalWrite (9, LOW); toggle2 = 1; }} void loop () {// doe hier andere dingen} 

De afbeeldingen hierboven tonen de uitgangen van deze timeronderbrekingen. Figuur 1 toont een blokgolf die oscilleert tussen 0 en 5V bij 1 kHz (timer0 onderbreken), figuur 2 toont de LED die is bevestigd aan pin 13 en wordt gedurende één seconde ingeschakeld en vervolgens gedurende één seconde uitgeschakeld (timer1 onderbreking), figuur 3 toont een pulsgolf die oscilleert tussen 0 en 5V bij een frequentie van 4khz (timer2 interrupt).

Stap 3: Voorbeeld 1: fietssnelheidsmeter

In dit voorbeeld heb ik een arduino aangedreven fietssnelheidsmeter gemaakt. Het werkt door een magneet op het wiel te bevestigen en de hoeveelheid tijd te meten die nodig is om door een magnetische schakelaar op het frame te gaan - de tijd voor een volledige rotatie van het wiel.

Ik heb timer 1 ingesteld om elke ms (frequentie van 1 kHz) te onderbreken om de magnetische schakelaar te meten. Als de magneet de schakelaar passeert, is het signaal van de schakelaar hoog en wordt de variabele "tijd" op nul gezet. Als de magneet niet in de buurt van de schakelaar is, wordt "tijd" met 1 verhoogd. Op deze manier is "tijd" eigenlijk slechts een maat voor de hoeveelheid tijd in milliseconden die is verstreken sinds de magneet voor het laatst door de magnetische schakelaar is gegaan. Deze informatie wordt later in de code gebruikt om het toerental en km / u van de fiets te berekenen.

Hier is het stukje code dat timer1 instelt voor 1kHz-interrupts

cli (); // stop onderbreekt
// stel timer1 interrupt in op 1 kHz
TCCR1A = 0; // zet het volledige TCCR1A-register op 0
TCCR1B = 0; // hetzelfde voor TCCR1B
TCNT1 = 0; // Initialiseer tellerwaarde naar 0
// stel het aantal timers in voor stappen van 1 kHz
OCR1A = 1999; // = (16 * 10 ^ 6) / (1000 * 8) - 1
// moest 16 bit timer1 gebruiken voor deze BC 1999> 255, maar kon overschakelen naar timers 0 of 2 met grotere voorschrijver
// schakel de CTC-modus in
TCCR1B | = (1 << WGM12);
// Set CS11 bit voor 8-voorschrijver
TCCR1B | = (1 << CS11);
// schakel timer vergelijk interrupt in
TIMSK1 | = (1 << OCIE1A);
sei (); // Allow interrupts

Hier is de volledige code als je een kijkje wilt nemen:
 // fietssnelheidsmeter // door Amanda Ghassaei 2012 ////www.instructables.com/id/Arduino-Timer-Interrupts/ ////www.instructables.com/id/Arduino-Timer-Interrupts/ / * * This programma is vrije software; u kunt het verspreiden en / of wijzigen * onder de voorwaarden van de GNU General Public License zoals gepubliceerd door * de Free Software Foundation; ofwel versie 3 van de licentie, of * (naar keuze) een latere versie. * * / // voorbeeldberekeningen // bandradius ~ 13, 5 inch // omtrek = pi * 2 * r = ~ 85 inch // maximale snelheid van 35 mph = ~ 616 inches / seconde // max rps = ~ 7, 25 #define reed A0 / / pin verbonden met leesschakelaar // opslagvariabelen zwevende straal = 13, 5; // bandradius (in inches) - VERANDER DIT VOOR JE EIGEN FIETS int reedVal; lange tijd = 0; // Tijd tussen één volledige rotatie (in ms) zwevende mph = 0, 00; zwevende omtrek; booleaanse achtergrondverlichting; int maxReedCounter = 100; // min tijd (in ms) van één rotatie (voor debouncing) int reedCounter; leegte setup () {reedCounter = maxReedCounter; omtrek = 2 * 3, 14 * straal; pinMode (1, OUTPUT); // tx pinMode (2, OUTPUT); // backlight schakelaar pinMode (reed, INPUT); // redd schakelaar checkBacklight (); Serial.write (12); // clear // TIMER SETUP- de timerinterrupt laat precieze tijdmetingen van de reed-schakelaar toe // voor meer informatie over de configuratie van arduino-timers, zie //arduino.cc/playground/Code/Timer1 cli ( ); // stop onderbreekt // zet timer1 interrupt op 1 kHz TCCR1A = 0; // zet het volledige TCCR1A-register op 0 TCCR1B = 0; // hetzelfde voor TCCR1B TCNT1 = 0; // initialiseer tellerwaarde op 0; // stel het aantal timers in voor stappen van 1 kHz OCR1A = 1999; // = (16 * 10 ^ 6) / (1000 * 8) - 1 // schakel de CTC-modus in TCCR1B | = (1 << WGM12); // Set CS11 bit voor 8 voorschrijver TCCR1B | = (1 << CS11); // activeer timer vergelijk interrupt TIMSK1 | = (1 <0) {// laat reedCounter niet negatief gaan reedCounter - = 1; // verklein reedCounter}}} anders {// als reed-schakelaar open is als (reedCounter> 0 ) {// laat reedCounter niet negatief worden reedCounter - = 1; // afname reedCounter}} als (tijd> 2000) {mph = 0; // als er geen nieuwe pulsen van reed-schakelband stil zijn, zet mph op 0} anders {tijd + = 1; // incrementele timer}} ongeldige displayMPH () {Serial.write (12); // clear Serial.write ("Speed ​​="); Serial.write (13); // Start een nieuwe regel Serial.print (mph); Serial.write ("MPH"); //Serial.write("0.00 MPH "); } void loop () {// print mph eenmaal per seconde displayMPH (); vertraging (1000); checkBacklight (); } 

Stap 4: Voorbeeld 2: Seriële communicatie

Dit project is een 4x4 verlicht toetsenblok. Het project wordt via usb op mijn computer aangesloten, het stuurt informatie over de knoppen naar de computer en ontvangt informatie over het oplichten van de leds. Hier is een video:



Voor dit project gebruikte ik timer2-interrupts om periodiek te controleren of er binnenkomende seriële gegevens waren, deze te lezen en op te slaan in de matrix "ledData []". Als je de code bekijkt, zul je zien dat de hoofdlus van de schets is wat eigenlijk verantwoordelijk is voor het gebruik van de info in ledData om de juiste LED's te laten oplichten en de status van de knoppen te controleren (een functie genaamd "shift ( ) "). De interruptroutine is zo kort mogelijk: u controleert gewoon op inkomende bytes en slaat ze op de juiste manier op.

Hier is de setup voor timer2:

cli (); // stop onderbreekt
// set timer2 onderbreken elke 128us
TCCR2A = 0; // Zet het volledige TCCR2A-register op 0
TCCR2B = 0; // hetzelfde voor TCCR2B
TCNT2 = 0; // Initialiseer tellerwaarde naar 0
// set vergelijk wedstrijdregister voor stappen van 7, 8 kHz
OCR2A = 255; // = (16 * 10 ^ 6) / (7812.5 * 8) - 1 (moet <256 zijn)
// schakel de CTC-modus in
TCCR2A | = (1 << WGM21);
// Set CS21 bit voor 8-voorschrijver
TCCR2B | = (1 << CS21);
// schakel timer vergelijk interrupt in
TIMSK2 | = (1 << OCIE2A);
sei (); // Allow interrupts

Hier is de complete Arduino-schets:
 // KNOPTEST met 74HC595 en 74HC165 en seriële communicatie // door Amanda Ghassaei // juni 2012 ////www.instructables.com/id/Arduino-Timer-Interrupts/ / * * Dit programma is gratis software; u kunt het verspreiden en / of wijzigen * onder de voorwaarden van de GNU General Public License zoals gepubliceerd door * de Free Software Foundation; ofwel versie 2 van de licentie, of * (naar keuze) een latere versie. * * / // deze firmware verzendt gegevens heen en weer met de maxmsp patch "beat slicer" // pinverbindingen #define ledLatchPin A1 #define ledClockPin A0 #define ledDataPin A2 #define buttonLatchPin 9 #define buttonClockPin 10 #define buttonDataPin A3 / / looping variabelen byte i; byte j; byte k; byte ledByte; // opslag voor led-toestanden, 4 bytes byte ledData [] = {0, 0, 0, 0}; // opslag voor knoppen, 4 bytes byte buttonCurrent [] = {0, 0, 0, 0}; byte buttonLast [] = {0, 0, 0, 0}; byte buttonEvent [] = {0, 0, 0, 0}; byte buttonState [] = {0, 0, 0, 0}; // knop debounceteller- 16 bytes byte buttonDebounceCounter [4] [4]; leegte setup () = (1 << WGM21); // Stel CS21 bit in voor 8 voorschrijver TCCR2B // buttonCheck - controleert de status van een gegeven knop. // deze buttoncheck-functie wordt grotendeels gekopieerd van de monome 40h-firmware door Brian Crabtree en Joe Lake Void Button Check (byte row, byte index) {if (((buttonCurrent [row] ^ buttonLast [row]) & (1 << index) ) && // als de huidige fysieke knopstatus verschilt van de ((buttonCurrent [rij] ^ buttonState [rij]) & (1 << index))) {// laatste fysieke knopstatus EN de huidige ontkrachte status als (buttonCurrent [rij] & (1 << index)) // als de huidige fysieke knopstatus is ingedrukt buttonEvent [rij] = 1 << index; // Wachtrij een nieuwe knopgebeurtenis onmiddellijk buttonState [rij] anders {buttonDebounceCounter [rij] [index] = 12; } // anders was de knop eerder ingedrukt en nu // is vrijgegeven, dus we hebben onze debounceteller ingesteld. } anders als (((buttonCurrent [rij] ^ buttonLast [rij]) & (1 << index)) == 0 && // als de huidige fysieke knopstatus hetzelfde is als (buttonCurrent [rij] ^ buttonState [rij] ) & (1 <0 && --buttonDebounceCounter [row] [index] == 0) {// als de debounceteller // is verlaagd naar 0 (wat betekent dat de // de knop is gebruikt voor // kButtonUpDefaultDebounceCount / / iteraties /// buttonEvent [rij] = 1 << index; // Wachtrij voor een wijziging van knopstatus als (buttonCurrent [rij] & (1 << index)) = (1 << index); anders {buttonState [ rij] & = ~ (1 << index);}}}} void shift () {for (i = 0; i <4; i ++) {buttonLast [i] = buttonCurrent [i]; byte dataToSend = (1 < > 3; // latchpin low digitalWrite (buttonLatchPin, LOW); voor (k = 0; k <4; k ++) {buttonCheck (i, k); if (buttonEvent [i] <  1) & 3; byte ledx = (ledByte >> 3) & 3; if (ledstate) = 8 >> ledx; anders {ledData [ledy] & = ~ (8 >> ledx); }} // einde indien serieel beschikbaar} // einde doen terwijl (Serial.available ()> 8); } void loop () {shift (); // werkt leds bij en ontvangt gegevens van knoppen} 

download de MaxMSP-patch hieronder (deze wordt ook in Max Runtime uitgevoerd).

Bijlagen

  • beat slicer.zip Downloaden

Stap 5: Voorbeeld 3: DAC

In dit project heb ik een timerinterrupt gebruikt om een ​​sinusgolf met een specifieke frequentie van de Arduino uit te voeren. Ik heb een eenvoudige 8 bit R2R DAC gesoldeerd aan digitale pinnen 0-7. Deze DAC is gemaakt van 10k- en 20k-weerstanden die zijn gerangschikt in een spanningsdeler met meerdere niveaus. Ik zal meer plaatsen over de constructie van de DAC in een andere instructable, voor nu heb ik de foto's hierboven opgenomen.
Ik heb de uitgang van de DAC aangesloten op een oscilloscoop. Als je hulp nodig hebt bij het begrijpen / gebruiken van de oscilloscoop, bekijk dan deze tutorial. Ik heb de volgende code op de Arduino geladen:
 // 63Hz sinusgolf // door Amanda Ghassaei 2012 ////www.instructables.com/id/Arduino-Timer-Interrupts/ / * * Dit programma is gratis software; u kunt het verspreiden en / of wijzigen * onder de voorwaarden van de GNU General Public License zoals gepubliceerd door * de Free Software Foundation; ofwel versie 3 van de licentie, of * (naar keuze) een latere versie. * * / // stuurt 63Hz sinus naar arduino PORTD DAC float t = 0; leegte setup () = (1 << CS21); // activeer timer vergelijk interrupt TIMSK2 ISR (TIMER2_COMPA_vect) {// increment t t + = 1; if (t == 628) {// 40 kHz / 628 = ~ 63 Hz t = 0; }} void loop () {// sinusgolf van frequentie ~ 63Hz // stuur sinuswaarden naar PORTD tussen 0 en 255 PORTD = byte (127 + 127 * sin (t / 100)); } 
Ik heb een timeronderbreking ingesteld die de variabele t verhoogt met een frequentie van 40 kHz. Zodra t 627 bereikt, wordt het teruggezet naar nul (dit gebeurt met een frequentie van 40.000 / 628 = 63 Hz). Ondertussen stuurt de Arduino in de hoofdlus een waarde tussen 0 (00000000 in binair) en 255 (11111111 in binair) naar digitale pinnen 0 tot en met 7 (PORTD). Het berekent deze waarde met de volgende vergelijking:

PORTD = byte (127 + 127 * sin (t / 100));

Dus als t oploopt van 0 tot 627, beweegt de sinusfunctie door een volledige cyclus. De waarde die naar PORTD wordt gestuurd, is een sinusgolf met een frequentie van 63 Hz en een amplitude van 127, die rond 127 oscilleert. Wanneer deze wordt verzonden via de 8-bit weerstandsladder DAC, geeft hij een oscillerend signaal af rond 2, 5 V met een amplitude van 2, 5 V en een frequentie van 63 Hz.

De frequentie van de sinusgolf kan worden verdubbeld door de (t / 100) term te vermenigvuldigen met 2, te verviervoudigen door te vermenigvuldigen met 4, enzovoort ...
Merk ook op dat als u de frequentie van de timeronderbreking te veel verhoogt door de voorschrijver of OCR2A te verlagen, de sinusgolf niet correct zal worden uitgevoerd. Dit komt omdat de functie sin () rekenkundig duur is en bij hoge interruptfrequenties niet genoeg tijd heeft om uit te voeren. Als u hoogfrequente interrupts gebruikt, in plaats van een berekening uit te voeren tijdens de interruptroutine, overweeg dan om waarden op te slaan in een array en deze waarden eenvoudig aan te roepen met behulp van een soort index. Je kunt een voorbeeld daarvan vinden in mijn arduino-golfvormgenerator - door 20.000 waarden van sin in een array op te slaan, kon ik sinusgolven uitvoeren met een bemonsteringsfrequentie van 100 kHz.

Stap 6: Timer- en Arduino-functies

Een laatste ding om op te merken: bepaalde timeropstellingen zullen sommige Arduino-bibliotheekfuncties daadwerkelijk uitschakelen. Timer0 wordt gebruikt door de functies millis () en delay (), als je timer0 handmatig instelt, zullen deze functies niet correct werken.
Bovendien onderschrijven alle drie de timers de functie analogWrite (). Het handmatig instellen van een timer zorgt ervoor dat analogWrite () niet meer werkt.

Als er een deel van uw code is dat u niet wilt onderbreken, overweeg dan om cli () en sei () te gebruiken om onderbrekingen globaal uit te schakelen en in te schakelen.

Meer hierover leest u op de Arduino-website.

Verwante Artikelen