Virr3 skrev:okej.. nu har jag lyckats med att blinka min diod i tre färger
men nu vill jag blinka den röd grön blå..
i takt..
men hur pausar jag?
wait(1000)? eller något i den i stilen?
Funktionen _delay_loop_1(x) "pausar" 3*x klockcykler. OBS! x måste vara mellan 0 och 255
Funktionen _delay_loop_2(x) "pausar" 4*x klockcykler. OBS! x måste vara mellan 0 och 65535
Tiden en klockcykel tar beror på vilken frekvens du kör AVR:en i.
4 MHz: 1/4000000 s = 0.25 µs
8 MHz: 1/8000000 s = 0.125 µs
12 MHz: 1/12000000 s = ca 0.8333 µs
Så vill du ha en paus på 1µs vid 4 MHz så kör du:
_delay_loop_2(1); // Därför att 1/(0.25*4) är 1
...och vid 8 MHz:
_delay_loop_2(2); // Därför att 1/(0.125*4) är 2
Räkna på samma sätt för andra frekvenser.
Eftersom _delay_loop_2() som max kan ta 65535 som argument, så kan du som mest göra en paus på 65535 µs vid 4 MHz (32767.5 µs vid 8 MHz osv). För att komma upp i runt en sekund så får du anropa _delay_loop_2() flera gånger.
Antingen genom att helt enkelt lägga fler på rad:
_delay_loop_2(60000); //Väntar 60 ms vid 4 MHz
_delay_loop_2(40000); //Väntar 40 ms vid 4 MHz
Totalt blir det alltså 100 ms (0.1 s)
Eller lägga dom i en for-loop som i exemplet jag visade först.
Som du märker blir det lite jobbigt att "pausa" i t ex en sekund. Men det är egentligen inget hinder, eftersom man aldrig brukar behöva ha sådana jättelånga pausar. Istället löser man sådana långa uppehåll med hjälp av timers och interrupts.
Nu blir det lite avancerat här. Förstår du inte så är det bara att titta tillbaka på koden när du har lärt dig lite mer om AVR och C.
Kod: Markera allt
// Koden växlar värdet på PB0 varje sekund. Kopplar du en lysdiod till PB0 kommer den alltså växla en gång per sekund.
#include <inttypes.h> // Innehåller lite variabeltyper. Används inte i det här exemplet men brukar ändå vara bra att ha
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
SIGNAL (SIG_OUTPUT_COMPARE1A) //Interrupt för "Compare Output Match"
{
PORTB ^= _BV(PB0); // Växlar värdet på PB0
}
int main()
{
DDRB = _BV(PB0); //Sätter PB0 till utgång.
OCR1 = 62499;
TCCR1A = 0;
TCCR1B = _BV(CS10)|_BV(CS11) | _BV(WGM12); // Kombinationen CS10 och CS11 ger en prescaler på 64. WGM12 betyder att TCCR1A nollställs när interrupten inträffar. (WGM12 heter CTC1 i äldre modeller)
TIMSK = _BV(OCIE1A); //Säger till att vi vill ha en interrupt för "Output Compare Match"
sei(); //Aktiverar interrupts
while(1) //Loopar i en evighet. Kommer avbrytas varje sekund.
{
}
return 1;
}
Nu till förklaringen. Jag antar att oscillatorn är på 4 MHz. Använder du någon annan hastighet, så är det bara att räkna om det till det.
För att nå upp till en sekund så går det åt 4000000 klockcykler. Det värdet är för stort för ett 16-bitsregister (två 8-bitars). Därför behöver vi dela ner det värdet så att det blir max 65535. De "prescalers" som finns är /1, /8, /64, /256 och /1024.
4000000 / 1 = 4000000 Större än 65535, går inte!
4000000 / 8 = 500000 Större än 65535, går inte!
4000000 / 64 = 62500 Mindre än 65535, Går bra!
Vi bestämmer oss därför för att använda en prescaler på 64 och räkna från 0 upp till 62500-1. TCNT1 kommer öka med 1 var 64:e klockcykel och kommer hela tiden jämföras med värdet i OCR1. När TCNT1 når upp till värdet i OCR1 kommer en interrupt inträffa. Då kommer programexeveringen avbrytas och hoppa till "Compare Match"-rutinen (SIGNAL-raden i exemplet). Samtidigt kommer TCNT1 nollställas och fortsätta räkna uppåt medan interrupten körs.
Lätt som en plätt!
Det var visst något stort DNS-fel hos Telia såg jag.
edit: Felrättning: Ändrat TCCR1A till TCNT1 (bättre sent än aldrig

)