ecenier: att läsa knappar, sedan vänta 10ms och läsa igen o jämföra fungerar helt klart.
Men man kastar bort 10ms (vänttiden) i onödan och med en µC som kör 16.000.000 instruktioner/sek är det 160.000instruktioner som kastas bort i onödan. Det är dock ett ganska vanligt sätt för personer som inte klarar att använda interrupt.
Kollar man sedan knappar 10 gg/sek går 10% av CPU-kraften till att vänta och det känns knappast vettigt eller hur?
Men tar man en interrupt på (ung.) 100 Hz är det 10ms mellan varje interrupt. Så läser man knapp-porten och sparar i ett register kan man jämföra med förra sparade värde och få exakt samma funktion - med det undantag att µC'n faktisk använder långt störstaparten av de annars bortkastade 160.000 instruktioner till verkligt arbete.
Knapp-avkänningen med debounce och allt kommer då att förbruka kanske 0,0156% av CPU-kraften vid 25 interrupts/sek och en rimlig snabb ISR på 100 instruktioner, alltså en skillnad på 640 gg.
Och har man gjort det en gång är det hur enkelt som helst. Sedan är det rimligt vanligt (i min värld iaf.) att man har en basal timer-interrupt för att sätta delay och liknande och då använder jag nästan alltid den samma till knapp-avkänning.
Men vänta, jag skriver om delay fastän jag just
avråder från dom! Varför då?
Jo, ibland ska vissa funktioner ha lov att starta något, få svar eller annat. Och många sätter hela programmet till att stanna av och vänta på att detta händer.
Men vad nu om man är lite smart?
Jag utgår ifrån att det finns en timer-interrupt med en hastighet på TIMER_SPEED per sekund.
det finns en variabel ("volatile unsigned short Delay_Counter_1") som behandlas som följer i samma ISR:
if(Delay_Counter_1) Delay_Counter_1--;
Faktisk ska alla efterföljande Delay_Counter_x man använder behandlas på liknande sätt.
Självklart kan variabels storlek anpassas till vad man gör, en BYTE i en 8-bit µC där man inte behöver vänta längre tid än den kan hålla vill vara en fördel osv.
I main-loop kan man sedan ha:
Kod: Markera allt
while(true)
{
if(NåntingSkaSke)
{
if(!Nånting) Delay_Counter_1 = TIMER_SPEED / 2; // Max. 0,5 sek väntande och bara om Nånting inte är aktiv
Nånting = true; // Slå på Nånting men först EFTER raden ovan!
if(Delay_Counter_1 && Nånting)
{
if(Nånting_Kör) // OK, Nånting har startat
{
// Gör vad som ska göras när Nånting kör
NåntingSkaSke = false; // OK, klart med det, nolla flaggan
}
}
else
{
// Hoppla, time-out, felhantering, t.ex:
Nånting = false; // Hann inte starta, stäng av
NåntingSkaSke = false; // Jahopp, det gick ju inte, så det så!
}
}
// Här kör resten av main-loop vidare oavsett status på Nånting och timeout osv.
}
Självklart kan man ha fler Delay_Counter_x och använda dom på olika sätt.
Om man t.ex. ska aktivera/utlösa en funktion i main-loop varje sekund (eller annat intervall) utan att spilla tid på den annars:
Kod: Markera allt
if(!Delay_Counter_x) // Sann om Delay_Counter_x är noll
{
Delay_Counter_x = TIMER_SPEED; // Ladda om tidräknaren
// Här ska funktionen utföras.
}
OBS: Timingen är inte exakt!!! Den varierar mellan Inställd värde och inställd värde - 1. Om main-loop tar längre tid än 1 timer-tick kommer den tid att läggas till!
Men till "småsaker" duger det alldeles utmärkt och undviker man helt och totalt de "gammaldags" Delay() brukar det gå tämligen bra om man inte klantar sig i programmeringen, en rundtur i main-loop ska nämligen inte ta så värst lång tid ändå.