PIC Opg 4 Løsning

Fra HTX Arduino
Spring til navigation Spring til søgning

Denne side gennemgår løsningen for PIC Opgave 4 - Kombinatorik

Løsningsforslag for Kombinatoriske opgaver.

Generelt er alle løsningerne lavet med den sædvanlig opstartskode til en PIC16F684, og selve funktionen realiseret i et forever loop.

Opstartskoden kan ses generelt gennemgået i

Koden som jal-filer

Alle eksemplerne kan hentes i denne ZIP-fil.

Den binære Adder

Addition af tal sker mange steder, men specielt inde i en mikroprocessor.

Denne opgave præsenterer princippet i det.

Den 1 bits binære full-adder

Til den simple adder anvendes to bit-indgange (de to bits der skal adderes) og en udgang med resultatet og en udgang med carry. Til en full adderskal der også en carry-indgang til.

Indgange og udgange til programmet defineres som følger:

porta_direction = all_input
alias bit0 is pin_a0         -- De 2 bit der skal adderes
alias bit1 is pin_a1
alias carry_in  is pin_a2    -- Carry ind fra inputtet

portc_direction = all_output
alias res0 is pin_c0         -- Resultatet på den bit der kommer ud
alias carry_out is pin_c3    -- Carry ud på resultatet

I programmet udregnes resultatet af half-adderen som et mellemresultat. Dette resultat placeres i en bit, der defineres som følger:

var bit res_ha    -- mellemresultat, der er half adder-sum

Hele koden inde i forever-loopet ser ud som følgende:

37   res_ha = bit0 ^ bit1    -- Først regnes en half-adder
38   carry_out = (bit0 & bit1) | (res_ha & carry_in)   -- så beregnes carry_out
39   res0 = res_ha ^ carry_in    -- og derefter selve resultatet på full-adderen

Linje 37 beregner summen af de to indgangsbit, og gemmer det i den interne variabel.

Linje 38 beregner carry out ud fra begge indgangsbit, mellemresultatet og den carry der kommer ind - resultatet placeres direkte på udgangen.

Linje 38 beregner summen af både de to indgangsbit og carry in - igen lægges det direkte ud på resultat-udgangen.

Koden ligger som opg-4a-full-add.jal i denne ZIP-fil.

2x3 bits full adder

Ideen med full-adders er at de kan lægge større tal sammen, og for at illustrere det, så er der her realiseret en full-adder der tager en carry id og 2 stk. 3 bits tal ind, og lægger dem sammen til et 3 bits tal samt en carry ud.

Indgange og udgange til programmet defineres som følger:

porta_direction = all_input
alias tal1_bit0 is pin_a0    -- De 3 bit der bliver til tal1
alias tal1_bit1 is pin_a1
alias tal1_bit2 is pin_a2

alias tal2_bit0 is pin_a3    -- De 3 bit der bliver til tal2
alias tal2_bit1 is pin_a4
alias tal2_bit2 is pin_a5

portc_direction = all_output
alias res_bit0 is pin_c0     -- Resultatet på de 3 bit der kommer ud
alias res_bit1 is pin_c1
alias res_bit2 is pin_c2
alias carry_out is pin_c3    -- Carry ud på resultatet
--
alias carry_in  is pin_c5    -- Carry ind fra inputtet

pin_c5_direction = input

Hen gennem de 2 x 3 bit der skal adderes anvendes igen et mellemresultat som er en halfadder. Mellem 1. og 2. fulladder kommer der en carry ud af den første fulladder, som, skal virke som carry ind på den 2. fulladder. Til dette anvendes en intern variabel som mellemresultat. Den samme variabel kan anvendes mellem 2. og 3. fulladder.

var bit res_ha    -- mellemresultat, der er half adder-sum
var bit carry_mel -- Mellemresultat på carry

Hele koden inde i forever-loopet ser ud som følgende:

48   -- Først beregnes full-adder på de to lave bit, der giver et output og en intern carry
49   res_ha = tal1_bit0 ^ tal2_bit0    -- Først regnes en half-adder
50   carry_mel = (tal1_bit0 & tal2_bit0) | (res_ha & carry_in)   -- så beregnes carry mellemresultat
51   res_bit0 = res_ha ^ carry_in    -- og derefter selve resultatet på full-adderen
52   -- Dernæst regnes på de to næste bit, der igen giver et output og en intern carry
53   res_ha = tal1_bit1 ^ tal2_bit1    -- Først regnes en half-adder
54   res_bit1 = res_ha ^ carry_mel    --  så selve resultatet på full-adderen
55   carry_mel = (tal1_bit1 & tal2_bit1) | (res_ha & carry_mel)   -- og derefter beregnes carry mellemretultat
56   -- Dernæst regnes på de to sidste bit, der igen giver et output og den endelige carry out
57   res_ha = tal1_bit2 ^ tal2_bit2    -- Først regnes en half-adder
58   carry_out = (tal1_bit2 & tal2_bit2) | (res_ha & carry_mel)   -- så beregnes carry_out
59   res_bit2 = res_ha ^ carry_mel    -- og derefter selve resultatet på full-adderen

Linje 49-51 regner de første to bit sammen med carry ind, og lægger summen direkte på udgangen, mens den carry der kommer ud af det gemmes, så den kan bruges ved beregning af de næste to bit.

Linje 53-55 regner de næste to bit sammen med carryen der ligger som mellemresultat, og lægger summen direkte på udgangen, mens den carry der kommer ud af det gemmes, så den kan bruges ved beregning af de sidste to bit.

Linje 57-59 regner de sidste to bit sammen med carryen der ligger som mellemresultat, og lægger summen direkte på udgangen. Den carry der kommer ud af det placeres direkte ud på carry out.

Koden ligger som opg-4a-bit.jal i denne ZIP-fil.

Binær addition som tal

Ved at betragte indgangene som binære tal, så kan det laves noget enklere. Til dette formål defineres to variabler:

var byte tal1
var byte tal2

Disse to variabler læses ind fra indgangene

Hele koden inde i forever-loopet ser ud som følgende:

46   tal1 =  porta & 0b0000_0111        -- Hent det ene 3 bits tal over i tal1
47   tal2 = (porta & 0b0011_1000) >> 3  -- Hent det andet 3 bits tal over i tal2
48   tal1 = tal1 + tal2                 -- Læg tallene sammen (det sker som bit i variablerne)
49   if carry_in then
50      tal1 = tal1 + 1                 -- Læg carry til, hvis den er der
51   end if
52   portc = tal1                       -- output resultatet, hvor carry ligger i det 4. bit

Linje 46 læser det ene 3 bits tal ind, og sikrer ved en AND-maske, at det kun er fra de 3 bit der kommer noget.

Linje 47 gør det tilsvarende, bare med 3 bit der ligger et andet sted i porta. Der anvendes igen en AND-maske, og derefter skiftes de 3 bit ned på position 2, 1 og 0, så det er et tal fra 0 til 7.

Linje 48 lægger de to tal sammen (det kan give 0-14, så carry er nu placeret i bit position 3 inde i tal1

Linje 49-51 lægger en carry-bit til fra carry in, hvis den er der, så tallet nu kan være 0-15.

Linje 52 lægger resultatet ud på portc. De 3 bit i tallet kommer ud på pin_c0 - pin_c2 og carryen kommer ud på pin_c3.

Koden ligger som opg-4a.jal i denne ZIP-fil.

Binær comperator

Denne opgave handler om at sammenligne to tal

Kun sammenligning af tal

I disse to løsninger sammenlignes 2 sæt 3 bit tal, og der sættes 3 udgange ud fra det.

Indgange og udgange til programmet defineres som følger:

porta_direction = all_input
-- De to tal der læses ind ligger på hhv. A0-A2 og A3-A5
portc_direction = all_output
-- Definition af de 3 udgange
alias   greater is pin_c0
alias   equal   is pin_c1
alias   smaller is pin_c2

De to binære tal læses ind i 2 variabler:

var byte tal1
var byte tal2

Hele koden inde i forever-loopet ser ud som følgende:

38   tal1 = porta & 0b0000_0111        -- Læs det første 3 bit tal fra A0-A2
39   tal2 = (porta & 0b0011_1000) >> 3 -- Læs det andet 3 bit tal fra A3-A5
40   if tal1 > tal2 then     -- Sammenlign de to tal, og sæt
41      greater = high       -- de relevante udgange
42      equal   = low
43      smaller = low
44   elsif tal1 < tal2 then
45      greater = low
46      equal   = low
47      smaller = high
48   else
49      greater = low
50      equal   = high
51      smaller = low
52   end if

Linje 38-39 læser de 2 x 3 bit ind i variablerne tal1 og tal2

Linje 40-43 sætter udgange op, hvis tal1 er større end tal2 - de resterende linjer håndterer mindre end og lig med.

Koden ligger som opg-4b.jal i denne ZIP-fil.

Et program der løser det samme kan skrives som:

38   tal1 = porta & 0b0000_0111        -- Læs det første 3 bit tal fra A0-A2
39   tal2 = (porta & 0b0011_1000) >> 3 -- Læs det andet 3 bit tal fra A3-A5
40   greater = tal1 > tal2
41   equal   = tal1 == tal2
42   smaller = tal1 < tal2

Her løser linje 40-42 det der blev lavet i en elsif struktur.

Koden ligger som opg-4b1.jal i denne ZIP-fil.

Sammenligning med cascading input

Kigger man på databladet for en binær comperator som digital kreds, så vil den have 3 input mere, der kan påvirke resultatet. Ideen i det er at man kan sammenligne 2 x 8 med to kredse der hver kan håndtere 2 x 4 bit, og man kan ekspandere til det antal bit man ønsker, ved at lægge flere kredse til.

Der skal defineres nogle indgange der tager imod inputtene:

alias   in_greater is pin_c3
alias   in_equal   is pin_c4
alias   in_smaller is pin_c5
pin_c3_direction = input
pin_c4_direction = input
pin_c5_direction = input

Ekspanderingen kan ske to veje - enten at outputtet går til en kreds med mindre betydende bit, eller at de går til en kreds med mere betydende bit.

Ekspandering mod mindre betydende cifre

Hvis outputtet går til en kreds med mindre betydende cifre, så kan koden skrives på følgende måde:

47   tal1 = porta & 0b0000_0111        -- Læs det første 3 bit tal fra A0-A2
48   tal2 = (porta & 0b0011_1000) >> 3 -- Læs det andet 3 bit tal fra A3-A5
49   if in_greater then          -- Sæt Greater, hvis det højere ciffer siger Greater
50      greater = high
51      equal   = low
52      smaller = low
53   elsif in_smaller then       -- Sæt Smaller, hvis det højere ciffer siger Smaller
54      greater = low
55      equal   = low
56      smaller = high
57   elsif in_equal then         -- Hvis det højere tal siger Equal
58      portc = tal1 > tal2      -- Sammenlign de to tal, og sæt
59      portc = tal1 < tal2      -- udgangene derefter
60      portc = tal1 == tal2
61   else                        -- Sæt ikke noget hvis det højere ciffer ikke siger noget
62      greater = low
63      equal   = low
64      smaller = low
65   end if

Linje 47-48 læser de to tal ind.

Linje 49-56 håndterer hvis det større tal siger større eller mindre.

Linje 57-60 håndterer hvis det større tal siger lig med - her anvendes løsningen fra før.

Linje 61-65 håndterer hvis det større tal ikke indikerer noget fornuftigt, så sættes alle udgange lave, som en fejltilstand.

Koden ligger som opg-4b2.jal i denne ZIP-fil.

Ekspandering mod mere betydende cifre

Hvis outputtet går til en kreds med mere betydende cifre, så kan koden skrives på følgende måde:

47   tal1 = porta & 0b0000_0111        -- Læs det første 3 bit tal fra A0-A2
48   tal2 = (porta & 0b0011_1000) >> 3 -- Læs det andet 3 bit tal fra A3-A5
49   greater = tal1 > tal2             -- Sammenlign de to tal, og sæt
50   smaller = tal1 < tal2             -- de relevante udgange
51   if tal1 == tal2 then              -- tag fra cascading input, hvis tallene er ens
52      greater = in_greater
53      equal   = in_equal
54      smaller = in_smaller
55   end if

Linje 47-48 læser de to tal ind.

Linje 49-50 laver sammenligningen på større end eller mindre end.

Linje 51-55 håndterer hvis de to tal er ens, så sendes cascading input videre til næste ciffer, eller ud som resultat.

Koden ligger som opg-4b3.jal i denne ZIP-fil.

Dekoder 3 bit binær til 8

Dekoderen tager 3 bit ind, og fra det tal de danner sættes en udgang, så kombinationerne 0-7 kommer ud på 8 udgangen, hvor den første bliver høj, når der kommer 0 ind, den næste bliver høj når der kommer 1 ind osv.

Indgange og udgange til programmet defineres som følger

porta_direction = all_input
portc_direction = all_output

Her anvendes de 3 lave bit i porta til tallet ind, og hele portc er udgangene

Der anvendes 2 variabler. tal1 indeholder det tal der læses ind, og tal2 anvendes til at behandle det der skal ud på udgangen.

var byte tal1
var byte tal2

Løsning med for-løkke

I den første løsning, der anvendes en for-løkke til at finde den rigtige udgang.

Hele koden inde i forever-loopet ser ud som følgende:

32   tal1 = porta & 0b0000_0111
33   tal2 = 0b0000_0001
34   for tal1 loop
35      tal2 = tal2 * 2
36   end loop
37   portc = tal2

Linje 32 læser tallet ind fra porta ind i tal1 - tallet begrænses til 3 bit, så det kun kan være 0-7.

Linje 32 sætter det tal op der skal ende med at komme ud på udgangen - det starter med at ligge med en høj i bit 0, så hvis der ikke ændres på det, så er det pin_c0 der går høj.

Linje 34-36 er det for-loop der sætter bittet hen på den ønskede udgang. Loopet gennemløbes det antal gange der er i tal1, og i linje 35 rykkes bittet en tak ad gangen, det kan gøres ved at gange tallet med 2, eller man kunne også have anvendt en skifte-operator << 1 til det.

I linje 37 lægges resultatet ud på porten.

Koden ligger som opg-4c.jal i denne ZIP-fil.

Løsning med skift af bit

I stedet for at anvende et for-loop, så kan man bruge skiftefunktionen direkte.

Hele koden inde i forever-loopet ser ud som følgende:

32   tal1 = porta & 0b0000_0111
33   tal2 = 0b0000_0001
34   tal2 = tal2 << tal1
35   portc = tal2

Linje 32 læser tallet som før.

Linje 33 sætter tallet der skal skiftes op.

Linje 34 laver selve skifteoperationen, hvor tal2 skiftes fra 0 til 7 gange. Hvis det skiftes 0 gange, så bliver det som det oprindelige, og pic_c0 sættes høj. Hvis der skiftes 7 gange, så skulle det være pin_c7 der bliver sat høj, men da en PIC16F684 ikke har dette ben, så er alle 6 bit der er i porten bare lave. Hvis man vil teste de to sidste bit i portc, så skal man vælge en anden PIC, som f.x. en PIC16F690 der har 8 bit i portc.

Linje 35 er der hvor tallet faktisk lægges ud på porten.

Koden ligger som opg-4c2.jal i denne ZIP-fil.

Løsning med reducering ved skift af bit

Dette er blot en reduktion af det ovenstående eksempel, hvor der er sparet en variabel (tal2) væk, og tingene bliver gjort mere direkte.

Hele koden inde i forever-loopet ser ud som følgende:

31   tal1 = porta & 0b0000_0111
32   portc = 0b0000_0001 << tal1

Linje 31 læser tallet som før.

Linje 32 udfører skifteoperationen, og lægger resultatet ud på portc.

Koden ligger som opg-4c3.jal i denne ZIP-fil.

Koden kan også skrives sammen på en linje, hvor man slet ikke bruger en variabel som vist her:

31   portc = 0b0000_0001 << (porta & 0b0000_0111)

Det sjove er at denne løsning ikke sparer hverken hukommelse eller data-areal, selvom man skulle tro det. Grunden er at den mere komplicerede beregning kræver at den opretter midlertidig hukommelse, og at det kodemæssigt ikke gør nogen forskel, når der alligevel skal bruges midlertidig hukommelse. Denne løsning er ikke med i ZIP-filen.

PIC
PIC-Typer PIC16F84 - PIC12F675 - PIC16F628 - PIC16F684 - PIC16F690 - PIC16F877 - PIC18F2550
Programmeringsbegreber Maskinkode - Mikrocontroller
Programmeringsmiljø PIC-brænder - UsbPicProg - Analog indgang - ICSP


Digitale Opgaver
Kombinatorisk Logik Opgave 1a - Opgave 1b - Opgave 2 - Opgave 3 - Opgave 4 - Opgave 5 - Opgave 6 - Opgave 7 - Opgave 8 - Opgave 9 - Opgave 10
Sekvensiel Logik Opgave 11 - Opgave 12 - Opgave 13 - Opgave 14
Analoge Opgaver
Modstande og Ohms lov Modstands Opgave 1 - Modstands Opgave 2 - Modstands Opgave 3 - Modstands Opgave 4 - Modstands Opgave 5 - Modstands Opgave 6 - Modstands Opgave 7 - Modstands Opgave 8 - Modstands Opgave 9 - Modstands Opgave 10
Kondensator og Spole Kondensator opgaver 1 - Kondensator DC opgave 1 - Kondensator AC opgave 1 - Spolen 1 - Seriekobling og parallelkobling - Spolen 2 - Beregning af spoleværdier (selvinduktionen) - Spolen 3 - Tidskonstant for RL-led - Spolen 4 - Beregning af induktiv-reaktansen
Operationsforstærker Opamp Opgave 1 - Opamp Opgave 2 - Opamp Opgave 3
Diverse Opgaver Opgaver Diagram - Opgaver Transformator - Transistor opgave - Zenerdiode Opgave 1
Programmerings Opgaver
Arduino Arduino Blink - Arduino Opgave 01 - Blink - Arduino Button - Analog Out - Arduino StateChangeDetection - Arduino termometer - Arduino termostat - Arduino udgangsforstærkning
PIC PIC Opgave 1 - Blink - PIC Opgave 2 - Gates - PIC Opgave 3 - Udvidet blink - PIC Opgave 4 - Kombinatorik - PIC Opgave 5 - Flip-flops - PIC Opgave 6 - Løbelys - PIC Opgave 6a - kontakt - PIC Opgave 7 - Udvidet løbelys - PIC Opgave 8 - Sekventielle kredsløb - PIC Opgave 9 - Multivibratorer - PIC Opgave 10 - Samtidighed - PIC Opgave 11 - Tastatur - PIC Opgave 12 - Display - PIC Opgave 13 - A-D converter - PIC Opgave 14 - Interrupt - PIC Opgave 15 - Seriel komm - PIC Opgave 16 - Lyskryds - PIC Opgave 17 - Tyverialarm
PIC Opgave Løsninger PIC Opg 1 Løsning - PIC Opg 2 Løsning - PIC Opg 3 Løsning - PIC Opg 4 Løsning - PIC Opg 5 Løsning