3.11. Avstudsning¶
En strömställare ritas som en perfekt öppen-eller-sluten kontakt, men kontakterna i en verklig strömställare växlar inte rent mellan de två tillstånden. De skallrar – skapar och bryter elektrisk kontakt många gånger inom några få millisekunder innan de stabiliseras. En GPIO-ingång som läser stiftet uppfattar detta som en skur av kanter; en oförsiktig avsökningsslinga räknar flera ”tryckningar” för en enda verklig tryckning, och en avbrottshanterare körs flera gånger per faktisk tryckning.
En studsande strömställare ger en skur av snabba övergångar innan den stabiliseras.¶
Avstudsning är metoden att filtrera bort skallret så att varje fysisk tryckning registreras som en enda händelse. Två tillvägagångssätt löser detta – mjukvara (en tidsregel i den fasta programvaran) eller hårdvara (ett litet filter på ledningen). De utesluter inte varandra.
3.11.1. Avstudsning i mjukvara¶
Tanken är att komma ihåg när ingången senast ändrades och avvisa ytterligare ändringar inom ett kort fönster efter den tidsstämpeln. Kontaktstuds varar typiskt under 10 ms; en verklig tryckning tar 50 – 100 ms; ett fönster på 30 – 50 ms fångar alla studsar utan att blockera verkliga tryckningar.
I en avsökningsslinga: läs stiftet, jämför med det senaste stabila värdet och godta en ändring först efter att avstudsningsfönstret har löpt ut:
import time
from machine import Pin
button = Pin("P0", Pin.IN, Pin.PULL_UP)
last_state = 1
last_change = 0
DEBOUNCE_MS = 50
while True:
now = time.ticks_ms()
state = button.value()
if state != last_state and time.ticks_diff(now, last_change) > DEBOUNCE_MS:
last_change = now
last_state = state
if state == 0:
do_action()
time.sleep_ms(10)
För avbrottsdrivna läsningar tillämpar du samma tidsregel inuti hanteraren och lämnar sedan över den verkliga tryckningen till huvudkontexten via micropython.schedule() (se GPIO-ingång):
import time
import micropython
from machine import Pin
button = Pin("P0", Pin.IN, Pin.PULL_UP)
last_irq = 0
DEBOUNCE_MS = 50
def handle_press(pin):
do_action()
def on_press(pin):
global last_irq
now = time.ticks_ms()
if time.ticks_diff(now, last_irq) < DEBOUNCE_MS:
return
last_irq = now
micropython.schedule(handle_press, pin)
button.irq(handler=on_press, trigger=Pin.IRQ_FALLING)
ISR-rutinen filtrerar studsar efter tidsstämpel och köar återanropet; handle_press körs tillbaka i huvudkontexten, där allokering och långsam I/O är säkra.
3.11.2. Avstudsning i hårdvara¶
Avstudsning i hårdvara filtrerar bort skallret elektriskt, innan det ens når stiftet. Standardverktyget är en kondensator.
En kondensator är en komponent med två anslutningar som lagrar elektrisk laddning. Fysiskt är den två ledande plattor som hålls ett kort avstånd från varandra, åtskilda av en isolator (dielektrikumet).
En plattkondensator: två ledare åtskilda av ett isolerande skikt.¶
Att lägga en spänning över dess anslutningar driver lika stora och motsatta laddningar till de två plattorna; sambandet är
Q = C × V
där Q är den lagrade laddningen (coulomb), V är spänningen över kondensatorn och C är dess kapacitans (farad). Kapacitansen är bestämd av komponentens konstruktion; mer kapacitans betyder mer lagrad laddning vid samma spänning.
Konsekvensen: en kondensator kan inte ändra sin spänning omedelbart. Laddning som flödar in eller ut måste passera genom vilket motstånd som än finns i banan, och det motståndet avgör hur snabbt spänningen kan ändras.
3.11.2.1. RC-tidskonstanten¶
Att ladda en kondensator genom ett motstånd ger en mjuk exponentiell stigning mot matningsspänningen, inte ett steg. Den karaktäristiska tiden för den stigningen är RC-tidskonstanten:
τ = R × C
Efter en τ har kondensatorn nått ungefär 63 % av matningsspänningen. Efter 5 τ är den över 99 % – ”fulladdad” i praktiken.
En kondensator laddas längs en exponentiell kurva. τ = RC är tiden för att nå 63 % av slutspänningen.¶
Urladdning genom ett motstånd följer spegelbilden: spänningen faller exponentiellt från sitt initialvärde mot noll och sjunker till 37 % av startspänningen efter en τ, och till under 1 % efter 5 τ.
En kondensator laddas ur längs ett exponentiellt avtagande. τ = RC är tiden för att falla till 37 % av startspänningen.¶
3.11.2.2. Avstudsningskretsen¶
En kondensator mellan ett ingångsstift och jord, matad genom ett seriemotstånd, bildar ett lågpassfilter. Snabba spikar hinner inte ladda eller ladda ur kondensatorn genom det motståndet; stiftet stannar nära den spänning det hade före spiken. Långsamma ändringar – en avsiktlig tryckning – laddar eller laddar ur kondensatorn och avläsningen följer med.
R1 drar strömställarens högsida upp till Vcc och ger en rå strömställarsignal som studsar. R2 och C lågpassfiltrerar sedan den signalen in i stiftet:
Avstudsning i hårdvara: R2 och C lågpassfiltrerar den råa strömställarsignalen innan den når stiftet.¶
Typiska värden: R1 = 10 kΩ (pull-up), R2 = 10 kΩ (serie), C = 100 nF.
När strömställaren är öppen flödar ström Vcc → R1 → R2 → kondensator (i serie) och laddar kondensatorn till Vcc med τ_charge = (R1 + R2) × C = 2 ms.
När strömställaren sluts klamras strömställarnoden till jord och kondensatorn laddas ur genom enbart R2 till den jorden med τ_discharge = R2 × C = 1 ms.
Båda kanterna är RC-filtrerade. Eftersom kondensatorn sitter på sin egen nod, nedströms om R2 från strömställaren, svänger den rent mellan Vcc (öppen) och 0 V (sluten) – ingen ström behöver flöda genom R1 i stationärt tillstånd i något av fallen.
3.11.3. Att välja mellan dem¶
Mjukvara är förvalet. Den kostar inget i komponenter, tröskelvärdet är lätt att finjustera och den fungerar på vilket stift som helst som CPU:n läser.
Hårdvara är värd komponenterna när studsen når något annat än CPU:ns avsökningskod – ett avbrott som inte får utlösas dubbelt, en hårdvaruräknare, en kringutrustning utan eget filter.
Avstudsning i mjukvara och hårdvara samexisterar också fredligt: ett litet RC-filter dämpar de värsta spikarna, och ett mjukvaruavstudsningsfönster täcker det som återstår.