Räknare med sjusegmentdisplay I den här laborationen ska du styra en sjusegmentdisplay med en räknare, som stegas fram med en tryckknapp, ett steg i taget. Så här ser kopplingsschemat ut för den modul, MOD687-40, som du ska använda: Modulen ser ut så här: 1
När du slår på matningsspänningen ska displayen visa en "nolla", efter första knapptryckningen ska en "etta" visas, osv. När displayen så småningom visar en "nia" ska nästa tryckning ge en "nolla" och processen upprepas. Det är egentligen tre problem som ska lösas och det är faktiskt en god ide att lösa vart och ett av problemen för sig innan det hela sätts ihop till den slutgiltiga lösningen. 1. Alla mekaniska tryckknappar uppvisar kontaktstudsar när de trycks ned och släpps. Det tar så där 5-10 millisekunder för kontakten att stabilisera sig och under tiden alstras hundratals slutningar och brytningar. Du ska ju använda din tryckknapp för att alstra en enda klockpuls till en räknare, så vi måste lista ut något sätt att få tryckknappen att alstra en enda puls per tryckning. 2. Vi måste hitta en räknare som räknar från 0 till 9 och sedan börjar om från början igen. 3. Sjusegmentdisplayen måste drivas från räknaren så att den korrekta kombinationen lysdioder tänds för varje siffra. Låt oss börja från början med tryckknappen! Avstudsning av tryckknapp Det finns flera metoder. Ett sätt är att filtrera signalen från knappen med ett lågpassfilter (ett RC-nät) och mata in signalen på en Schmitt-trigger innan den används. Den metoden fungerar inte i vårt fall, eftersom hårdvaran redan är klar och det inte finns vare sig filter eller Schmitt-trigger tillgängliga! I vårt fall finns det en bättre metod. Tryckknappen SW1 är av växlande typ med två pull-up-motstånd R2 och R3. Om ingen trycker på knappen är CPLD pin nummer P54 jordad och P56 ligger på +5V. När knappen är nedtryckt ligger P54 på +5V och P56 är jordad. När knappen är på väg mellan de två lägena har studsarna upphört och både P54 och P56 ligger temporärt på +5V, ända tills knappen växlar tillstånd, studsar, och stannar i det nya läget. Vad som behövs för att avstudsa en sådan anordning är helt enkelt en SR-vippa (ibland kallad SRlatch) bestående av två korskopplade NAND-grindar. Switchen visas "otryckt": 2
I det visade läget på switchen är A = 0. Men om en ingång på en NAND-grind är "0" måste utgången vara "1", d v s X = 1. Den undre NAND-grindens båda ingångar är alltså båda "1". Detta är just villkoret som innebär att utgången Y = 0. Den övre NAND-grindens båda ingångar är tydligen "0" men det ändrar inget, X = 1 i alla fall. Hade switchen ritats i andra läget, alltså nedtryckt, skulle av symmetriskäl utgången istället varit "1". Hmm. Hade det inte gått precis lika bra att använda switchen direkt? Det verkar ju som om utgången följer switchen i alla fall, så vad är det då för finess med SR-vippan? Nej, det är bara det att vi ännu inte studerat vad som sker då switchen studsar och det är det som är hela finessen! Låt oss gå tillbaka till ursprungsläget på switchen, då den är "otryckt" och utgången Y = 0. Låt oss sedan trycka på knappen och studera vad som händer i allra första ögonblicket. A blir momentant "1" när switchkontakten öppnas. Detta ändrar dock ingenting på den övre NAND-grindens utgång, eftersom dess andra ingång fortfarande är "0". Utgången Y är fortfarande "0". Om switchkontakten studsar tillbaka blir det fortfarande ingen ändring på Y. Studsarna maskeras alltså av vippan. Inte förrän switchkontakten jordar den undre NAND-grindens B-ingång händer något. Eftersom den ena av den undre NAND-grindens ingångar då blir "0", blir utgången Y = 1 och vippan kantrar. Även om kontakten nu studsar ett tag innan den stabiliseras i det nya läget så står vippan envist kvar med Y = 1 och maskerar studsarna. Samma sak upprepas när kontakten släpps, Y = 0 vid första studsen då ingången A jordas och vippan står sedan kvar i detta läge. Det här arrangemanget är perfekt att ta till i alla sammanhang när mekaniska omkopplare ska styra digitala ingångar. Du kommer att använda det många gånger i CPLD-sammanhang. Starta nu Xilinx Foundation som vanligt genom att dubbelklicka på Project Manager-ikonen. Se till att du markerar "Create a New Project" och tryck på OK. 3
Ett fönster "New Project" visas. Fyll i namnet på det nya projektet, sjuseg. Se också till att "Schematic" är förprickat och att de tre rutorna i understa raden i tur och ordning visar XC9500, 95108PC84 och 15 och tryck på OK. Projektmanagern visar nu det nya projektet sjuseg och tittar du noga efter kan du också se att rätt kretstyp valts (95108PC84-15). Starta schemainmatningen genom att klicka på "AND-grinden" på den övre vänstra knappen märkt Design Entry: Programmet är nu redo för schemainmatningen! Du ska nu rita schemat för avstudsningsvippan, komplett med alla IPAD och IBUF. Använd samma signalnamn som på det tidigare visade schemat och sätt också ut pin-nummer, enligt det schema för MOD687-40 som visades allra först. Placera ingångarna längst uppe till vänster på schemat. 4
Så här ser resultatet ut: Spara filen (File-Save), generera en nätlista (Options-Create Netlist), klicka på OK, och exportera nätlistan (Options-Export Netlist). Se till att filnamnet är sjuseg och att filtypen är Edif 200 [*.EDN] och klicka på OK. Gå tillbaka till Projektmanagern. Tryckknappen för Design Entry har nu en grön bock som markering att allt är klart att gå vidare: Nu är det dags att simulera avstudsningen! Starta simulatorn genom att klicka på knappen Simulation. Simulatorfönstret kommer upp blankt och du ska nu ange vilka signaler du vill studera. Klicka därför på Signal-Add Signals. Detta 5
fönster visas då: Du ska studera signalerna A, B, X och Y. Dubbelklicka därför, i tur och ordning, på A, B, X och Y. En röd bock indikerar att respektive signal är vald. Klicka sedan på Close. Simulatorfönstret visar nu vilka signaler som valts: A och B är de två insignalerna till avstudsningsvippan. Vi vill kunna stimulera A med tangenten a och B med tangenten b, d v s sätta godtyckliga insignaler. Klicka på Signal-Add Stimulators. Detta fönster visas: 6
Så här tillordnar du tangenten a till signalen A: Klicka på signalen A längst till vänster, så att den blåmarkeras, klicka sedan på bilden av tangenten a i fönstret. Tillordna tangenten b till signalen B på motsvarande sätt. Så här blir resultatet: Du kan se att a respektive b tillordnats signalerna genom att de visas med rött vid signalerna. Observera att simulatorn skiljer på stora och små bokstäver. Det är små bokstäver som gäller, så du måste se till att Caps Lock är avstängd på 7
tangentbordet. Klicka på Close när du är klar. Om du nu trycker på tangenten a på tangentbordet ser du hur du kan påverka nivån på signalen A. Otryckt knapp innebär att A ska vara 0, så ställ in A = 0. Likaså ska B vara 1 för otryckt knapp, så ställ in B = 1. Ändra simulatorns tidskala till 10ns/div genom att klicka på den fintandade kammen alldeles ovanför signalerna. Den fintandade kammen ökar tidskalan och den glestandade minskar den. Kör simuleringen ett steg genom att klicka på Stegknappen (ser ut som fotspår ): Så här blir resultatet: Utsignalen X blev en etta och Y en nolla. Det stämmer perfekt, gå tillbaka till toppen på sidan 2 och kolla! Nu ska du själv genomföra en knapptryckning i slow motion genom att först sätta A = 1, stega, simulera en studs genom att A = 0, stega, sätt A = 1 och stega. Sätt sedan B = 0, stega, simulera studs genom att B = 1, stega, sätt B = 0 och stega. Nu är alltså knappen simulerad nedtryckt! Stega ett par gånger till utan att ändra något. Dags att släppa knappen genom att sätta B = 1, stega, simulera en studs genom att B = 0, stega, sätt B = 1 och stega. Nu nalkas knappen utgångsläget. Sätt A = 1, stega, simulera en studs genom att A = 0, stega, sätt A = 1 och stega. 8
Så här blir det: Som du ser ignorerar vippan alla studsar och utsignalen Y blir en enda snygg fyrkantpuls per fullständig knapptryckning, precis som vi ville ha det! OK, dags att gå vidare med nästa deluppgift, nämligen räknaren. Räknaren Det här blir en mycket enklare uppgift! En en-bitars räknare kan räkna 0, 1. En två-bitars räknare kan räkna 0, 1, 2, 3 En tre-bitars räknare kan räkna 0, 1, 2, 3, 4, 5, 6, 7 En fyra-bitars räknare kan räkna 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 En räknare som kan räkna mellan 0 och 9 måste alltså ha fyra bitar, tre blir för lite. Om du vill kan du modifiera räknesekvensen hos en fyra-bitars binärräknare med hjälp av avkodning och styrning av reset-ingången så att den börjar om från noll igen efter nio. Detta är dock inte nödvändigt, det finns nämligen färdiga dekadräknare i komponentlistan! Starta schemaeditorn igen och gå in och titta på komponentlistan. Där finns t ex CD4CE, som är en dekadräknare, eller BCDcounter med 4 bitar. Det första C:et betyder Counter, alltså räknare, D betyder Decimal (hade det stått B hade det betytt Binary), 4 betyder fyra bitar, nästa C betyder att räknaren har asynkron Clear, alltså nollställning, och E betyder Clock Enable, d v s att klockan kan grindas. Hämta CD4CE, och lägg in den på schemat till höger om avstudsningsvippan. Koppla CE (Clock Enable) till VCC och CLR (Clear) till GND. 9
Så här blir det: De fyra små röda och gröna kvadraterna vid vippan är minnen av simuleringen som gjordes. Om du har schemafönstret uppe samtidigt som du kör simulatorn visar dessa små kvadrater de aktuella logiska tillstånden i kretsen. Rött betyder ett och grönt noll. Det är nu dags att kolla om räknaren fungerar som utlovat. Egentligen borde vi simulera tryckknappen genom att manipulera A och B, men det går ju åt en hel del tryckande för att generera en enda klockpuls och det blir ganska jobbigt och lätt att göra fel. Dessutom vet vi att avstudsningen fungerar så det är dessutom meningslöst! Som väl är finns det ett mycket enklare sätt att förse räknaren med klockpulser under simuleringen, som du strax ska se. För att du ska kunna analysera resultatet av simuleringen måste vi också kunna titta på räknarens utgångar Q0, Q1, Q2 och Q3. Så här ska du göra: Starta först simulatorn genom att gå tillbaka till Projektmanagern och klicka på knappen Simulation. Simulatorfönstret kommer upp igen. Börja med att ta bort alla gamla kurvformer genom att klicka på knappen Delete Waveforms, som ser ut som ett tidsdiagram med ett rött kors på: 10
Ett varningsfönster visas: Klicka på OK och klicka sedan på knappen ON för att preparera en ny simuleringsomgång. Resultatet ser ut så här: Nu ska vi först se hur en klocksignal kan tillordnas räknaren. Klicka på Signal- Add Stimulator, klicka sedan på signalen Y så den blåmarkeras och klicka slutligen på den övre högra gula lysdioden i raden Bc: Klicka sedan på Close. De sexton gula lysdioderna representerar en 16-bitars 11
räknare, som kan användas som stimuli för simulatorn. Lysdioden längst till höger representerar räknarens minst signifikanta bit, kallad B0. Dess frekvens kan väljas med Options-Preferences. Klicka på tabben Simulation och se till att B0 = 100MHz. Klicka på OK. Vi ska kolla ytterligare ett par inställningar hos simulatorn. Se till att följande inställningar gäller: 2ns/div (klicka på kammarna ) Functional 50ns (steglängd) Det går åt ytterligare preparation innan det är dags att köra! Du vill ju kunna studera utgångarna från räknaren så de måste finnas med i tidsdiagrammet. Tidigare har du använt signalnamn du själv skrivit in i schemat som referens, t ex Y, men några sådana finns inte på räknarens utgångar. Gör så här: Klicka på Signal-Add signals. Detta fönster visas: 12
I mittkolumnen visas alla kretssymboler som används. Du känner säkert igen dina IPAD, IBUF o s v. Där återfinns även räknaren, CD4CE. Klicka på den! I högra kolumnen visas nu alla in- och utgångar hos CD4CE: Klicka på de fyra utgångarna du vill studera, nämligen Q0, Q1, Q2 och Q3. De markeras med röda bockar. Klicka på Close. Nu finns alla signaler med! A, B, X, Y, Q0, Q1, Q2 och Q3. Markeringen $17 är numret på kretssymbolen CD4CE i schemat. Schemaeditorn tillordnar själv automatiskt dessa nummer, i tur och ordning som symbolerna placeras ut. Ditt eget schema kan alltså ha en annan markering om du ritade i en annan ordningsföljd. Kör simulatorn 200 ns genom att klicka fyra gånger på stegknappen (4 gånger 50 ns = 200 ns). 13
Så här ser det ut: Du ser klocksignalen B0 med periodtiden 10ns, vilket motsvarar 100MHz. Innan den allra första klockpulsen är samtliga fyra räknarutgångar nollor. Efter den första klockpulsen (egentligen dess positiva flank) har Q0 blivit en etta medan övriga förblir nollor. Om du noggrant går igenom sekvensen klockpuls för klockpuls ser du att räknarens innehåll ökas med ett för varje klockpuls. Skriv ned de binära talen så du är säker på att du förstår hur räknaren fungerar. Observera att räknaren startar om igen från noll när den räknat till nio (binärt 1001), precis som vi ville ha det. Två av delmålen, avstudsningen och räknaren, är nu klara och testade. Dags att ta itu med sjusegmentdisplayen! Sjusegmentdisplayen Enligt schemat på sidan 1 benämns de sju segmenten så här: 14
Din uppgift är att se till att rätt kombination segment tänds för vart och ett av räknarens tio tillstånd. När räknaren är nollställd ska alltså alla element utom G vara tända (DP betyder Decimal Point, vi bryr oss inte om att tända den). När räknaren räknat till ett ska bara elementen B och C vara tända, o s v. Om du tittar på schemat ser du ytterligare en detalj att tänka på. Lysdioddisplayen är av typ Gemensam Anod, d v s alla elementens anoder är hopkopplade och går till +5V. Varje enskild katod går via ett 220Ω motstånd till respektive CPLD-utgång. För att ett element ska tändas ska alltså motsvarande CPLD-utgång vara en nolla. En etta släcker elementet. T ex elementet A tänds om utgången P70 = 0. För att styra displayen behövs en omkodare, med räknarens fyra bitar som insignaler och displayens sju segment som utsignaler. Tabellen visar sambandet mellan insignaler och utsignaler: Gå igenom tabellen för varje siffra och rita vilka element som är tända. Det hade förstås varit praktiskt om det funnits en sjusegmentavkodare som komponent i schemaeditorn, men det gör det inte! Du kan dock utan större svårighet konstruera en avkodare själv med hjälp av de schemakomponenter som finns tillgängliga. Vi ska emellertid gå ett steg längre, du ska nämligen själv tillverka en sjusegmentavkodare som ska sparas som en sjusegmentavkodarekomponent, som du sedan direkt kan använda i andra konstruktioner. Detta kallas att göra ett macro och är en mycket arbetsbesparande finess. Macron kan tillverkas på flera olika sätt, t ex genom att rita ett schema (som du ska göra), eller genom att skriva en beskrivning med hjälp av ett högnivåspråk som ABEL eller VHDL. Hur man än gör blir resultatet detsamma, en ny komponent. Du ska kalla den nya komponenten sju_dec (förkortning av sjusegmentdecoder). Du startar det hela genom att starta schemaeditorn igen och sedan klicka på File- New Sheet. Du har nu en blank schemablankett, färdigt att rita på. Innan du gör det ska du spara det nya tomma schemat under namnet sju_dec.sch. Gör så här: 15
Klicka på File-Save As, skriv namnet sju_dec.sch och klicka på OK. Nu glömmer du i varje fall inte bort att filen ska ha detta namn när schemat är klart! Rita nu sjusegmentavkodaren med hjälp av tabellen på föregående sida. Använd gärna en en-av-sexton omkodare, kallad D4_16E, som hjälp. D står för decoder, d v s omkodare, 4_16 anger att den har 4 ingångar och 16 utgångar och E betyder att omkodaren har en ingång enable, som måste vara 1 för att omkodaren ska fungera. D4_16E fungerar alltså på så sätt att endast en enda utgång är 1 för varje insignalkombination. T ex ingångarna 0000 gör utgången D0 = 1, 0001 gör D1=1 o s v. Använd sedan OR-grindar för att tända segmenten. Så här kan resultatet se ut (det finns många sätt att komma fram till samma mål!): Du är tvungen att sätta ut terminaler med namnen Q0, Q1, Q2 och Q3 för ingångarna och A, B, C, D, E, F och G för utgångarna. Terminalerna hittar du när du drar ledningar i schemat. När du kommer till slutet av en ledning klickar du med höger musknapp, varvid ett litet fönster med olika möjligheter visas. Du ska då klicka på Add Terminal med vänster musknapp. Ett nytt fönster visas där du väljer in- eller utgång, anger terminalens namn och klickar OK. När ditt nya schema är klart sparar du med File-Save. Klicka sedan på Hierarchy-Create Macro Symbol from Current Sheet. 16
Följande fönster visas då: Kontrollera att alla ingångar och utgångar finns med och klicka på OK. Ett nytt fönster visas: Klicka på No. Schemat sju_dec.sch stängs då automatiskt. Ditt schema finns nu sparat som en symbol med namnet sju_dec i schemaeditorns komponentlista! Om komponentlistan inte syns kan du ta fram den genom att klicka på komponentmodknappen vid vänstra kanten: Komponentlistan visas: Den nya komponenten SJU_DEC står allra först i listan, under rubriken SJUSEG, som ju är namnet på ditt projekt. Fortsättningsvis kan du vid behov hämta SJU_DEC även till nya projekt med bibliotekseditorn, den kommer alltså inte med automatiskt när du gör nya projekt. För tillfället behöver du inte veta något om bibliotekseditorn, så vi ignorerar den just nu. 17
Klicka på SJU_DEC och lägg in den i ditt originalschema, alldeles till höger om räknaren. Koppla ihop räknarens fyra utgångar med motsvarande ingångar på sjusegmentavkodaren. Koppla in en OBUF och en OPAD per utgång, skriv signalnamnen efter respektive OBUF och sätt ut pinnummer med hjälp av schemat på sidan 1. Så här ser det ut: Det lönar sig alltid att kolla schemat ett par extra gånger innan man går vidare. Här finns två fel! Vi har kallat en av ingångarna till avstudsningsvippan A och en av utgångarna som ska driva ett elemet i displayen A. Samma sak med B! Men kan det spela någon större roll? Ja, verkligen! Punkter i schemat med samma signalnamn kopplas nämligen ihop i nätlistan. Det blir allstså samma effekt som om du kopplat ihop ingången A på den övre NAND-grinden med utgången P70 och ingången B på den undre NAND-grinden med utgången P68. Ingen bra idé! A och B på NAND-grindarna har spelat ut sin roll i alla fall, så du kan ta bort dem. Gå in i editeringsmod, d v s klicka på knappen Klicka sedan på signalnamnet A vid den övre NAND-grinden. A rödmarkeras. Ta bort A med tangenten Delete på tangentbordet. Ta bort B på samma sätt. Det är alltid bra att skriva dit signalnamn på alla in- och utgångar, det underlättar simuleringen. Utgångarna är redan markerade, låt oss sätta signalnamnen U och V på de två ingångarna. Så här blir det korrigerade schemat: 18
Spara med File-Save, gör nätlista med Options-Create Netlist. En varning visas i Projektmanagerns nedre fönster. Varningen utfärdas därför att att räknarens utgångar CEO och TC inte är anslutna. Dessa används dock bara när flera räknare är kaskadkopplade. Du kan alltså ignorera varningen! Klicka slutligen på Options-Export Netlist och exportera filen som en Edif200-fil. Ditt schema är klart och det är dags att simulera. Starta simulatorn och se till att signalerna C, Q0, Q1, Q2 och Q3 på räknaren CD4CE samt signalerna A, B, C, D, E, F och G finns med. tillordna stimulatorn B0 till klockingången C på CD4CE. Stega 150ns, d v s klicka tre gånger på stegknappen. Så här blir resultatet: Dags att se om det stämmer! Börja längst till vänster i tidsdiagrammet, innan första klockpulsen. De fyra utgångarna från räknaren är alla nollor. Titta nu i tabellen på sidan 15. När räknaren innehåller 0000 ska tydligen alla segmentutgångarna A, B, C, D, E och F vara nollor och G = 1. Jämför nu med simulatorns tidsdiagram. Det stämmer! Fortsätt nu att analysera de resterande nio tillstånden så du är säker på att sjusegmentavkodaren fungerar. Om det inte stämmer är det något fel på avkodaren och du kan gå tillbaka till schemat sju_dec.sch, rätta felet, gå igenom proceduren med nätlistgenereringen etc så många gånger som behövs för att få det hela att fungera. Simulatorn är ett enormt kraftfullt verktyg för avlusning av konstruktioner. När allt är klart är det dags att köra implementeringen. Gå tillbaka till Projektmanagern och klicka på Implementation. När det är klart visas ett fönster som säger att allt är klart. Du avslutar med att klicka på OK. 19
Nu ska SVF-filen genereras, så att du kan ladda ner din konstruktion i kretsen. Klicka på Programming. Programmeringsfönstret kommer upp: Klicka på Output-Create SVF File. Ett fönster SVF Options visas. Klicka på OK. Fönstret Create a New SVF File visas. Programmet föreslår en plats att lagra filen som tyvärr blir ganska svår att hitta senare. Lägg istället filen direkt i sjuseg-foldern. Du kommer dit genom att klicka tre gånger på mappsymbolen. Så här ser det slutligen ut: Klicka på Save. För att generera SVF-filen klickar du på Operations-Program. Ett fönster Options visas, där du ska se till att det står en bock i rutan vid Erase Before Programming och klicka på OK. Då börjar filen genereras. När den är klar står det All operations were completed successfully. Kvittera med OK och stäng programmeringsfönstret. Du får frågan om du ska spara ändringarna i sjuseg. Klicka på No. Ett steg återstår innan SVF-filen kan laddas ned i kortet. Du ska nämligen flytta SVF-filen till foldern CPLD. Starta Utforskaren, leta rätt på SVF-filen som ligger i folden C-Fndtn-Active-Projects-sjuseg och flytta den till CPLD-foldern. 20
Nu ska du koppla ihop sjusegementmodulen med CPLD-modulen, koppla in spänningen samt ansluta CPLD-modulen till datorns parallellport. När det är gjort är det äntligen dags att ladda ned din konstruktion i CPLD-modulen. Öppna ett DOS-fönster, byt bibliotek till C:\CPLD, skriv xsload sjuseg och tryck på Enter. Nedladdningen tar ungefär 15 sekunder, tiden markeras med en rad plustecken. När nedladddningen är klar tänds en nolla i displayen och du kan testa din design genom att stega genom en sekvens. Om du hittar något fel får du fixa problemet i schemat och gå igenom processen tills allt fungerar som det ska. Lycka till! 14 januari 2001 Anders Andersson 21