Område 3 · lektion 11
Binärt och logiska grundfunktioner
Ditt bygge har hittills haft en insignal. Nu ska det få två, och då uppstår en fråga som inte fanns förut: vad betyder de tillsammans? Svaret på den frågan har ett eget namn och en egen notation, och den är äldre än datorn.
Mål
- Du kan förklara varför en styrenhet arbetar med två nivåer i stället för många, och vilka spänningar de två nivåerna motsvarar på ett Uno-kort.
- Du kan räkna om ett binärt tal till decimalt och säga hur många kombinationer n insignaler ger.
- Du kan rita och läsa sanningstabellen för AND, OR, NOT och XOR utan att slå upp den.
- Du kan känna igen de fyra grindsymbolerna i ett schema och säga vilken funktion var och en gör.
Genomgång
Två nivåer, och varför det räcker
En sladd kan bära vilken spänning som helst mellan 0 och 5 V. Ändå bestämde sig den som konstruerade kortet för att bara använda två av dem. Det ser ut som slöseri, och det är motsatsen.
Databladet för ATmega328P – chippet på ditt kort – anger
inte två spänningar utan två områden, räknade som andelar av
matningsspänningen. En ingång läses som LOW under
0,3 av matningen och som HIGH över 0,6 av den. Med 5 V blir
det:
LOW: U ≤ 0,3 · 5 V = 1,5 V
HIGH: U ≥ 0,6 · 5 V = 3,0 V
Mellan 1,5 och 3,0 V är svaret odefinierat – chippet får läsa vad det
vill. Det gapet på 1,5 V är hela poängen. En störning som lyfter en
nollsignal med en halv volt gör den till 0,5 V, som fortfarande är
entydigt LOW. Skulle sladden i stället bära ett mätvärde
hade samma störning förvanskat värdet med tio procent utan att någon
märkte det.
Robusthet, inte enkelhet Två nivåer valdes inte för att de var lätta att räkna med. De valdes för att en signal som bara har två giltiga lägen kan återställas i varje steg: varje grind läser en smutsig signal och skickar vidare en ren. Ett mätvärde kan aldrig återställas på samma sätt – det du tappat i brus är borta. Därför är världens signaler analoga men världens styrsystem digitala.
Binärt: att räkna med två siffror
Med bara siffrorna 0 och 1 fungerar räknandet precis som vanligt, men varje position är värd dubbelt så mycket som den till höger i stället för tio gånger. Positionerna är alltså 1, 2, 4, 8, 16 och så vidare.
| Position | 8 | 4 | 2 | 1 |
|---|---|---|---|---|
| Talet 1011 | 1 | 0 | 1 | 1 |
| Bidrar med | 8 | 0 | 2 | 1 |
1011₂ = 8 + 0 + 2 + 1 = 11
Åt andra hållet: hur många olika värden ryms i ett visst antal bitar?
Varje bit fördubblar antalet, så n bitar ger 2ⁿ
kombinationer.
1 bit: 2¹ = 2 · 2 bitar: 2² = 4 · 3 bitar: 2³ = 8 · 8 bitar: 2⁸ = 256
Det där sista talet har du redan sett: byte i
språkreferensens typtabell rymmer 0 till 255, alltså 256 värden.
Samma räkning gäller insignaler. Två knappar kan stå i 2² = 4 lägen tillsammans. Tre knappar ger 2³ = 8. Det är därför en sanningstabell för två insignaler alltid har exakt fyra rader – varken fler eller färre – och det är också måttet på hur mycket du behöver testa när bygget är klart.
De fyra grundfunktionerna
En grind är en krets som tar en eller två insignaler och lämnar en utsignal. Symbolerna nedan är de som står i scheman och i datablad.
- AND ger etta bara när båda ingångarna är ettor. Formen känns igen på den raka vänstersidan och den runda högersidan.
- OR ger etta när minst en ingång är etta. Vänstersidan buktar inåt och högersidan går ut i en spets.
- XOR ger etta när ingångarna är olika. Den ritas som en OR med en extra båge utanför – och det är den enda skillnaden i symbolen, så titta efter bågen.
- NOT har en enda ingång och vänder på den. Ringen på spetsen är själva inverteringen; triangeln utan ring är bara en förstärkare.
- A och B är ingångarna, U är utgången. Bokstäverna är en vana, inte en regel – i ett verkligt schema heter de vad signalerna heter.
Sanningstabellerna
En sanningstabell räknar upp alla lägen ingångarna kan stå i och vad utgången blir i vart och ett. Med två ingångar är det fyra rader, av skälet som räknades ut ovan. Tabellen är inte en beskrivning av grinden – den är grinden. Två kretsar med samma sanningstabell gör samma sak, hur olika de än är byggda.
| A | B | A AND B | A OR B | A XOR B |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
NOT har bara en ingång och därför bara två rader:
| A | NOT A |
|---|---|
| 0 | 1 |
| 1 | 0 |
Läs den stora tabellen kolumnvis en gång och lägg märke till tre saker. AND-kolumnen har en enda etta, längst ned. OR-kolumnen har en enda nolla, längst upp. Och XOR skiljer sig från OR i exakt en rad: den sista, där båda är ettor. Det är hela skillnaden mellan "minst en" och "precis en av dem".
Ordningen på raderna är ingen slump Skriv alltid raderna som 00, 01, 10, 11. Det är talen 0, 1, 2 och 3 skrivna binärt, i ordning – samma räkning som i förra avsnittet. Gör du det får du aldrig en tabell med en glömd eller dubblerad rad, och en granskare kan läsa den utan att kontrollräkna.
Samma funktioner uttryckta i kod
En grind är hårdvara. I ditt bygge finns ingen grind – där finns en styrenhet som gör samma sak i mjukvara, med tre tecken som du redan sett i språkreferensens jämförelsetabell.
| Grind | I C++ | Uttalas |
|---|---|---|
| AND | && | och |
| OR | || | eller |
| NOT | ! | inte |
| XOR | != | skilt från |
Den sista raden ser fel ut och är rätt. C++ har ingen egen operator för
logiskt XOR. Men "A och B är olika" är precis vad != säger,
och för två sanningsvärden är det samma funktion som XOR-tabellen ovan.
En AND-grind mellan två knappar och en lysdiod blir alltså det här, med konstanterna deklarerade överst i filen som vanligt:
const int KNAPP_A_PIN = 2;
const int KNAPP_B_PIN = 3;
const int LAMPA_PIN = 8;
// ... och inne i loop():
if (digitalRead(KNAPP_A_PIN) == LOW && digitalRead(KNAPP_B_PIN) == LOW) {
// båda nedtryckta – LOW betyder nedtryckt med INPUT_PULLUP
digitalWrite(LAMPA_PIN, HIGH);
} else {
digitalWrite(LAMPA_PIN, LOW);
}
Två saker att lägga märke till redan nu. Det står två
et-tecken, inte ett – ett ensamt & är en annan operator
som gör en annan sak, och kompilatorn säger ingenting. Och villkoret
testar LOW, eftersom knappen med intern pull-up är
nedtryckt när den ligger på noll. Inversionen från förra området gäller
fortfarande, och den blir bara mer förvirrande när den möter en logisk
regel.
Nästa guide går igenom operatorerna ordentligt, inklusive vad det ensamma et-tecknet faktiskt gör.
I industrin och i vardagen
I industrin: innan styrenheter blev billiga byggdes maskinlogik av fysiska komponenter, och den byggs fortfarande så där det måste gå fort eller vara enkelt att granska. En krets som 74HC08 innehåller fyra AND-grindar i en kapsel med fjorton ben, och en grind i den svarar på en insignal inom storleksordningen tio nanosekunder. Samma funktion byggdes i äldre maskinskåp med reläer: ett relä per grind, med en omslagstid i storleksordningen tio millisekunder. Skillnaden är
10 ms / 10 ns = 0,01 s / 0,00000001 s = 1 000 000 gånger
En miljon gångers skillnad i snabbhet – och ändå sitter reläer kvar i säkerhetskretsar än i dag, av precis det skäl som gör dem långsamma: ett relä är en fysisk kontakt som går att se, mäta och tvångsstyra. Ett säkerhetsrelä där kontakterna är mekaniskt hopkopplade kan inte fastna i "sluten" utan att det syns på en annan kontakt. En grind i ett chip kan det.
I vardagen: hallen hemma har troligen två strömbrytare till samma lampa, en vid varje dörr. Den kopplingen är en XOR som ingen kallar för en XOR. Två växelströmbrytare ger 2² = 4 kombinationer, och lampan lyser i två av dem – de två där brytarna står i olika lägen. Beroende på hur de två ledarna mellan brytarna dras kan det bli XOR eller dess motsats XNOR, och för den som bor i huset spelar det ingen roll: den enda egenskap man bryr sig om är att vippa på endera brytaren alltid byter lampans läge, och det gäller i båda fallen. Det finns ingen elektronik i kopplingen alls – logiken sitter i hur sladdarna är dragna, vilket är den äldsta formen av logisk grundfunktion som finns i ett hem.
Prova själv
- Skriv sanningstabellerna för AND, OR, XOR och NOT ur minnet på ett papper. Rader i ordningen 00, 01, 10, 11. Jämför sedan med tabellerna ovan och rätta.
- Räkna om 1101, 0110 och 10000 till decimala tal. Kontrollera genom att addera positionsvärdena. Facit finns bland kontrollfrågorna.
- Koppla in två tryckknappar, en på D2 och en på D3,
båda mellan pinnen och GND. Ställ in båda med
INPUT_PULLUP. - Skriv en sketch som skriver ut båda knapparnas lägen till seriemonitorn ungefär fem gånger i sekunden, som två siffror på samma rad. Tryck knapparna i alla fyra kombinationerna och kontrollera att du ser 11, 10, 01 och 00. Kom ihåg att en uppsläppt knapp visar 1 på grund av pull-upen.
- Lägg till en lysdiod på D8 och låt den lysa enligt AND: bara när båda knapparna är nedtryckta. Byt sedan villkoret till OR och kontrollera att beteendet ändras som tabellen säger.
- Sista steget, och det är svårare än det låter: få lysdioden att följa
XOR, alltså lysa när precis en av knapparna är nedtryckt. Du behöver
inte fler än en rad, och
!=är den raden.
Kontrollfrågor
Vad blir 1101, 0110 och 10000 som decimala tal?
1101 = 8 + 4 + 0 + 1 = 13. 0110 = 0 + 4 + 2 + 0 = 6. 10000 = 16 + 0 + 0 + 0 + 0 = 16. Kontrollen är enkel: ett tal med en etta längst till vänster och bara nollor efter är alltid en jämn tvåpotens.
Hur många rader har sanningstabellen för fyra insignaler, och varför?
2⁴ = 16 rader. Varje ny insignal fördubblar antalet kombinationer, eftersom varje rad som fanns förut nu finns i två versioner – en där den nya signalen är 0 och en där den är 1.
En ingång på ditt kort ligger på 2,2 V. Vad läser
digitalRead()?
Det går inte att säga. 2,2 V ligger i gapet mellan 1,5 V och 3,0 V,
där databladet inte lovar någonting. Du kan få HIGH,
LOW, eller olika svar från gång till gång. En signal som
hamnar där är alltid ett fel i kopplingen, inte ett fall att hantera i
koden – den vanligaste orsaken är en ingång utan pull-up.
Vilken enda rad skiljer XOR från OR?
Raden där båda ingångarna är ettor. OR ger 1 där, XOR ger 0. I alla tre andra rader är de identiska. Det är därför XOR ibland läses som "eller, men inte båda".
Två knappar ska öppna en lucka bara när ingen av dem är nedtryckt. Vilken funktion är det, uttryckt med grindarna du kan?
Det är NOT applicerat på OR, alltså NOR: !(A || B). Den
är sann i exakt en av de fyra raderna – den översta, där båda är nollor.
Samma sak kan skrivas !A && !B, vilket är samma
funktion uttryckt som en AND mellan två inverteringar.
Varför spelar det gap på 1,5 V mellan nivåerna någon roll när signalen ändå kommer fram?
Därför att sladdar plockar upp störningar. Gapet är den marginal en störning får ta i anspråk innan signalen blir feltolkad. Ju längre sladd och ju mer elektrisk smuts i miljön, desto mer marginal behövs – och det är därför industrikretsar ofta arbetar på 24 V i stället för 5 V. Samma andelar, större absolut marginal.
Vanliga fel
- Sanningstabellen har tre rader eller fem. Antalet rader är bestämt av antalet ingångar: 2ⁿ, alltid. Fattas en rad är det ett fall bygget aldrig testades i, och det är där det senare kommer att gå sönder.
- XOR ritas som en OR. Den extra bågen utanför vänstersidan är den enda skillnaden i symbolen, och den försvinner lätt i en handritad skiss. Skriv ut XOR bredvid symbolen i ditt eget schema.
- Ringen glöms på NOT. En triangel utan ring är en förstärkare som skickar signalen vidare oförändrad. Med ring är den en inverterare. Skillnaden är hela funktionen.
- Nedtryckt antas vara 1. Med
INPUT_PULLUPär nedtrycktLOW, alltså 0. Din sanningstabell på papperet talar om ettor och nollor; din kod läser knappar som är inverterade. Bestäm dig tidigt för vilket håll tabellen beskriver och skriv ut det ovanför tabellen. - Ett et-tecken i stället för två.
&och&&är olika operatorer, och den felaktiga kompilerar utan varning. Nästa guide handlar bland annat om det. - Talet skrivs binärt men läses decimalt. 10 binärt är
2, inte tio. Skriv ut basen när det kan missförstås, som
1011₂.
Vidare
Kapitlet Villkor i
språkreferensen hör till den här guiden, särskilt tabellen som ställer
Pythons and, or och not mot C++:s
tecken. Typer och variabler
innehåller storlekarna som gör 2⁸ och 2¹⁶ till praktiska tal och inte
bara matematik.
Nästa guide är Villkor i C++. Där flyttar sanningstabellerna in i koden, och de två operatorer som ser nästan likadana ut får varsin behandling.