Hallo, ich habe vor zur Übung eine Stoppuhr zu programmieren. Sie soll zweistellig die Minuten, zweistellig die Sekunden und einstellig die Zehntel anzeigen. Das hat (mit etwas Recherche im Internet) auch bis her recht gut funktioniert. Jetzt möchte ich die Zeit durch 7 Segment Anzeigen ausgeben lassen und Letztere per Multiplexverfahren ansteuern. Das Verfahren habe ich verstanden und es funktioniert auch soweit, mein Problem besteht darin, dass ich einen Tipp benötige, wie ich meine Zeit an den binär am PortC ausgeben kann. Muss ich dazu 2 7Segment Decoder benutzen, oder kann ich die 5 Segmente auch mit einem Decoder ansteuern? und wie bringe ich dem Decoder bei, dass die Segmente nur Zahlen von 1-9 verstehen und nicht von 1-15? Ich nutze den Atmega8 und programmiere per Bascom. Der 7Segment Decoder ist ein CD4511BE und mein Bisheriges Programm befindet sich im Anhang (im Moment werden nur 2 stellen angesteuert und diesen sind noch keine Zahlenwerte zugeordnet. Sie zeigen also nur 0 an) Ich hoffe ich konnte mein Problem einigermaßen verständlich beschreiben, falls nicht, einfach fragen =) Vielen Dank schonmal für eure Hilfe, Grüße, Tom
> und wie bringe ich dem Decoder bei, dass die Segmente nur Zahlen von 1-9 > verstehen und nicht von 1-15? Dem kannst du gar nichts beibringen. Du musst dafür sorgen, daß er nur 0..9 zu sehen bekommt. > Der 7Segment Decoder ist ein CD4511BE Klick doch einfach auf den Link. Da findest du nicht nur das Datenblatt, sondern auch die Threads, die sich mit dem Thema befassen. mfg.
Also Angesteuert werden diese Treiber MEISTENS durch BCD (Binär Codierte Dezimalzahl) also mit 4 BIT Daten D C B A - PIN 0 0 0 0 = 0 0 0 0 1 = 1 0 0 1 0 = 2 0 0 1 1 = 3 0 1 0 0 = 4 0 1 0 1 = 5 0 1 1 0 = 6 0 1 1 1 = 7 1 0 0 0 = 8 1 0 0 1 = 8 (ICH HOFFE DIE TABELLE IS RICHTIG) Ich kann mich nicht mehr genau entsinnen aber gabs bei bascom nicht mal die Lookup Table? damit kannst du den Zahlen 0..9 einen entsprechenden Wert zuweisen, um mit deinem PORT die Daten auszugeben. Multiplexen kann man damit Eben je nach CC oder CA mit PNP oder NPN Transistor die 7-Segment ein ausschalten
Hallo, vielen Dank schonmal für eure Antworten. Mit dem Multiplexen komme ich wunderbar zurecht. Mein Problem ist, in meinem Fall den PortC jeweils so einzustellen, dass er die Einzelnen Stellen genau so wie in dieser Tabelle anzeigt: Matthias Li. schrieb: > also mit 4 BIT Daten > > D C B A - PIN > 0 0 0 0 = 0 > 0 0 0 1 = 1 > 0 0 1 0 = 2 > 0 0 1 1 = 3 > 0 1 0 0 = 4 > 0 1 0 1 = 5 > 0 1 1 0 = 6 > 0 1 1 1 = 7 > 1 0 0 0 = 8 > 1 0 0 1 = 9 ( <- habe diese Stelle korrigiert ) Ich habe die einzelnen Ziffern schon in den Variablen St1, St2 , M1,M2, Sek1,Sek2 gespeichert. (Format SS:MM:SS) Meine Überlegung war, es irgendwie so zu lösen: "Multiplex" ist die Funktion, die 100 mal pro Sekunde ausgelöst wird. Multiplex: Timer2 = Timer2_start portb = &BSt1 Portb = &B00000001 waitms 2 portb = &BSt2 Portb = &B00000010 waitms 2 portb = &BM1 Portb = &B00000100 waitms 2 portb = &BM2 Portb = &B00001000 waitms 2 portb = &BSek1 Portb = &B00010000 waitms 2 portb = &BSek2 Portb = &B00100000 waitms 2 Return aber das funktioniert nicht :-/
Tom schrieb: > Meine Überlegung war, es irgendwie so zu lösen: > "Multiplex" ist die Funktion, die 100 mal pro Sekunde ausgelöst wird. > > Multiplex: > Timer2 = Timer2_start > portb = &BSt1 > Portb = &B00000001 > waitms 2 > portb = &BSt2 usw. 1. Du hast Multiplex nicht verstanden! Die Funktion, die mehrmals pro Sekunde aufgerufen wird, stellt immer nur eine Stelle dar. z.B. den Minuten-Zehner. Beim nächsten Mal den Minuten-Einer dann den Sekunden-Zehner usw. Bei 100 mal pro Sekunde flimmert es aber zu sehr, bei Dir wären 400-500 mal besser. Solche Sachen: > portb = &BSt1 > Portb = &B00000001 > waitms 2 führen dazu, daß am Portb nur die 1 für 2 ms ansteht, St1 wird ja gleich überschrieben! Die Konstruktion "&BSt1" sieht sowieso eigenartig aus. Gibts das überhaupt unter BASCOM?
Hi Was willst du mit Decodern? Wie viel freie Portpins für die Anzeige stehen denn zur Verfügung? 7 für die Segmente und 5 für die Stellen wären 12 und dann kann der Controller den Code liefern. Dazu gehst du wie folgt vor: Du erzeugst ein Array of Byte, wo du den Portpins für die Segmente alias a-g die Signallage zuordnest. Bei gemeinsamer Kathode "1"er und bei gemeinsamer Anode "0"er. Das Array fängt bei Index 0 an, also ist dein Segmentcode für 0 im Arrayfeld mit dem Index 0 Hast du eine Zahl 4, nimmst du die Basisadresse vom Array (das ist die mit dem Index0) und addierst darauf deine Zahl. Die zeigt dann auf die Adresse mit dem Index 4 und damit auf den Code der Anzeige 4. Somit hast du die Ziffer konvertiert. Um eine mehrstellige Zahl zu konvertieren baust du dir einen Zahlenpuffer, bspw.für deine Zeit im Format <m><m><s><s><z>. Dann setzt du einen Index auf <z>, wobei auch diesmal <z> im Puffer mit der niedrigsten Adresse steht.Das Konstrukt für den programmcode kann ich dir in BASCOM nicht geben, da das nicht meine Welt ist, aber etwas allgemein gültiges schon. Zeitpuffer -> Array of Byte mit fünf Feldern Matrix -> Array of Byte mit zehn Feldern Anzeigepuffer: Array of Byte mit fünf Feldern For j = 0 to 4 Lade Zeitpuffer(i) Addiere auf Basisadresse Matrix Wert aus Zeitpuffer Adressiere damit Matrixpuffer kopiere den dort abgelegten Wert nach Anzeigepuffer Next Dieser Block wird im Hauptprogramm entweder bei Änderung der Werte im Zahlenpuffer oder in jedem Zyklus bearbeitet. Im Interrupt setzt du im mSek. Bereich einfach einen Zeiger auf den Ausgabepuffer, wo deine Matrix der anzuzeigenden Zahlen steht und mit Ziffer 0 adressierst du Anzeigepuffer(0). Zur Selektion der Ziffer eignet sich ein Byte, in dem du einfach ein Bit von der ersten Ziffer bis zur letzten schiebst und dann von vorn beginnt, Zählt dein Adresszähler vom Ausgabepuffer mit, hast du die Adresse des Anzeigepuffers. In fedem Interrupt erst Anzeige dunkel schalten, nächste Adresse für Ausgabepuffer. Stellenbit schieben. Grenzwert überschritten dann Adresse Ausgabepuffer 0 und Schiebebit auf Anfang Schließlich den Segmentcode aus Anzeigepuffer auf den Port schreiben und die Ziffern wieder zuschalten. Damit löst du Zahlenwerte von deiner Anzeige. Es ist egal, aus welcher Zahlenaufbereitung der Code im Ausgabepuffer kommt. Die ISR greift nur auf den Puffer zu, was da drin steht, ist ihr völlig egal. Auch wenn du da "HILFE" rein schreibst, wird sie es abbilden. Die Skizze soll dir die Trennung ISR und Main mit der gemeinsamen Schnittstelle "Anzeigepuffer" zeigen
Es geht auch mit lookup.. falls du Speicherprobleme hast $regfile = "m32def.dat" $crystal = 16e6 $baud = 100000 $hwstack = 100 $swstack = 500 $framesize = 500 $sim ' Sieben Segment Funktion Config Timer0 = Timer , Prescale = 1 Config Portc = Output Enable Timer0 Enable Interrupts On Timer0 Tmr0isr Dim Zahl As Byte Main: NOP NOP Goto Main Siebenseg: Data &B00111111 , '0 Data &B00000110 , '1 Data &B01011011 , '2 Data &B01001111 , '3 Data &B01100110 , '4 Data &B01101101 , '5 Data &B01111101 , '6 Data &B00000111 , '7 Data &B01111111 , '8 Data &B01101111 , '9 Data &B01110111 , 'A Data &B01111111 , 'B Data &B00111001 , 'C Data &B00111111 , 'D Data &B01111001 , 'E Data &B01101001 , 'F Tmr0isr: ' Mache irgendwas damit... z.b. Laufvariable und Select & case ' Segemt 1..2..3..4..5..6..1..2..3..4..5..6 usw... ' z.B. Portb = 0 ' Das ist die Funktion die deine Zahl in eine für deine ' 7 Segment Anzeige "lesbare Zahl" umwandelt Portc = Lookup(zahl , Siebenseg) Select Case Stelle Case 1 : Portb = 1 'Stellen ansteuern Case 2 : Portb = 2 'Stellen ansteuern Case 3 : Portb = 4 'Stellen ansteuern Case 4 : Portb = 8 'Stellen ansteuern Case 5 : Portb = 16 'Stellen ansteuern Case 6 : Portb = 32 'Stellen ansteuern End Select Incr Stelle If Stelle = 7 Then Stelle = 1 End If Return So sollte es klappen und erfüllt alle Anforderungen des Multiplexing... Hoffe ich konnte helfen! EDIT: Falsche Reihenfolge :-)
:
Bearbeitet durch User
Wow, das sind mal Antworten =D DANKE! Ich werde mich in den nächsten Tagen mal dran machen und eure Tipps durcharbeiten; beim ersten Durchlesen habe ich noch nicht alles verstanden, aber ich schau mal was so draus wird. Matthias Lindner schrieb: > Main: > NOP > NOP > Goto Main Ehm, NOP ist laut Wikipedia ein Befehl der nichts macht, richtig? Route 66 schrieb: > Solche Sachen: >> portb = &BSt1 >> Portb = &B00000001 >> waitms 2 > führen dazu, daß am Portb nur die 1 für 2 ms ansteht, St1 wird ja gleich > überschrieben! Die Konstruktion "&BSt1" sieht sowieso eigenartig aus. > Gibts das überhaupt unter BASCOM? Ich glaube nicht, dass es diesen Befehl in Bascom gibt, er funktioniert auch nicht ;). Ich wollte damit nur deutlich machen, was ich vorhabe. Übrigens funktioniert die Anzeige wunderbar, wenn ich dem Port bestimmte Zahlen vorgebe, z.B.: Multiplex: Timer2 = Timer2_start portB = &B00000101 '5 wird an erster Stelle ausgegeben PortC = &B00000001 waitms 2 portB = &B00000011 '3 wird an zweiter Stelle ausgegeben PortC = &B00000010 waitms 2 portB = &B00001000 '8 wird an dritter Stelle ausgegeben PortC = &B00000100 waitms 2 portB = &B00000011 '3 wird an vierter Stelle ausgegeben PortC = &B00001000 waitms 2 .....usw Return ------------------------------------------------------------------------ --- Wichtiger Nachtrag: Mit dem PortC werden übrigens die einzelnen Stellen nacheinander angezeigt. Dh. PortC wird zum Multiplexen verwendet. Ich hatte in meinem letzten Beitrag einen Fehler gemacht. Dort hatte ich erneut PortB anstelle von PortC geschrieben. ------------------------------------------------------------------------ --- Ich müsste also nur dem PortB beibringen, wie er die Ziffern von 1-9, die ich in den Variablen St1, St2 , M1,M2, Sek1 und Sek2 gespeichert habe binär an den 7Segment-Decoder weitergibt. Weil der versteht nur Bit-förmige Informationen. Ich melde mich wieder, falls ich irgendwo nicht alleine weiterkomme. Falls jemand noch einen Tipp für mich hat, ich bin dankbar für alles! ;) Vielen Dank nochmal! Grüße, Tom
Matthias Lindner schrieb: > Es geht auch mit lookup.. Aaaaaahhhh ich habe gerade mal gegoogelt, was denn der Lookup Befehl ist. Ich glaube damit werde ich es mal versuchen. Grüße, Tom
Juhuuhh, hat schon funktioniert! Vielen Dank nochmal für eure Hilfe. Ich werde mir die anderen Tipps trotzdem nochmal durchlesen und evtl. noch etwas dazulernen. ;) Grüße, Tom Stoppuhr (allerdings bisher noch ohne Start- oder Stoppknopf): $regfile "m8def.dat" $crystal = 1000000 $hwstack = 100 $swstack = 100 $framesize = 100 $baud = 2500 Ddrd = &B111110011 'Pins an PortD 0,1,4,5,6,7 sind Outputs; Pins an PortD.2,3 sind Inputs Portd = &B00001100 'interne Pullups von Pd2 und Pd3 einschalten Ddrb = &B11111111 'Alle Pins an PortB sind Outputs Portb = &B00000001 'Anfangsstatus für PortB Ddrc = &B000001111 Dim Timer1_start As Word Dim Timer2_start As Word Dim Sekunde As Word Dim Minute As Word 'Varriablen deffinieren Dim Stunde As Word Dim Sek1 As Byte Dim Sek2_zwischenergebnis As Byte Dim Sek2 As Byte Dim M1 As Byte Dim M2_zwischenergebnis As Byte Dim M2 As Byte Dim St1 As Byte Dim St2_zwischenergebnis As Byte Dim St2 As Byte Config Timer1 = Timer , Prescale = 1024 'Timer1 als Timer definieren, mit einem Vorteilungsdivisor von 1024 On Timer1 Sekundenzaehlen 'wenn Timer1 überläuft, dann gehe zur Funktion "Sekundenzaehlen" Enable Timer1 'Timer1 einschalten Config Timer2 = Timer , Prescale = 128 'Systemtakt wird durch 100 geteilt und dann an Timer2 übergeben. Timer2 zählt On Timer2 Multiplex 'diesen dann und lößt bei jedem Überlaufen einen Interrupt aus. Enable Timer2 'Timer2 einschalten Enable Interrupts 'Interrupts global einschalten Sekunde = 0 Minute = 0 Stunde = 0 Timer1_start = 64559 'Startwert des Timers, sodass die Sekundenzählfrequenz passt. Er zählt von 64559 bis 65535. (= 976 Zählschritte) Timer2_start = 177 'Startwert des Timers. Er zählt von 177 bis 255. (= 78 Zählschritte) Timer1 = Timer1_start 'Timer2 soll den Startwert 64559 bekommen Timer2 = Timer2_start Dim Stunden As Byte Do If Sekunde > 59 Then 'erklärt sich von selbst . Minute = Minute + 1 Sekunde = 0 End If If Minute > 59 Then 'erklärt sich von selbst Stunde = Stunde + 1 Minute = 0 End If 'Zerlegen der einzelnen Teilzeiten in ihre jeweiligen Stellen auf der Anzeige (Bsp: 46 Sekunden; Sek1 = 4, Sek2 = 6 ) Sek2 = Sekunde Mod 10 'Sek2 ist die zweite stelle der Sekundenanzeige. S2 = Rest von sekunden/10 Sek2_zwischenergebnis = Sekunde - Sek2 'Hilfsergebnis ist aktuelle Sekunden - Einer Sek1 = Sek2_zwischenergebnis / 10 'Sek1 ist die erste stelle der Sekundenanzeige. S1 ist Hilfsergebnis/10 M2 = Minute Mod 10 'M2 ist die zweite stelle der Minutenanzeige. M2 = Rest von Minuten/10 M2_zwischenergebnis = Minute - M2 'Hilfsergebnis ist aktuelle Minuten - Einer M1 = M2_zwischenergebnis / 10 'M2 ist die erste stelle der Minutenanzeige. M1 ist Hilfsergebnis/10 St2 = Stunde Mod 10 'St2 ist die zweite Stelle der Hundertstelanzeige. H2 = Rest von Hundertstel/10 St2_zwischenergebnis = Stunde - St2 'Hilfsergebnis ist aktuelle Stunden - Einer St1 = St2_zwischenergebnis / 10 'St1 ist die erste stelle der Stundenanzeige. St1 ist Hilfsergebnis/10 Print St1 ; " " ; St2 ; " " ; M1 ; " " ; M2 ; " " ; Sek1 ; " " ; Sek2 Loop End Sekundenzaehlen: 'wenn der Timer1 überläuft, soll die Varriable "Sekunde" um 1 erhöht werden, dann Incr Sekunde 'soll Timer1 wieder am Wert "Timerstart" anfangen zu zählen. Außerdem soll Led2 Timer1 = Timer1_start 'dabei Blinken. Toggle Portd.5 Return Multiplex: Timer2 = Timer2_start 'Timer2 auf Startwert zurücksetzen Portc = Lookup(sek1 , Tabelle) 'Lookup-Befehl: (Für jeden Wert von Sek1 wird der dazugehörige wert in der Tabelle an PortC ausgegeben) Portb = &B00000001 'Erste Stelle der Sekundenanzeige einschalten Waitms 2 Portc = Lookup(sek2 , Tabelle) 'Lookup-Befehl: (Für jeden Wert von Sek2 wird der dazugehörige wert in der Tabelle an PortC ausgegeben) Portb = &B00000010 'Zweite Stelle der Sekundenanzeige einschalten Waitms 2 Portc = Lookup(m1 , Tabelle) 'Lookup-Befehl: (Für jeden Wert von M1 wird der dazugehörige wert in der Tabelle an PortC ausgegeben) Portb = &B00000100 'Erste Stelle der Minutenanzeige einschalten Waitms 2 Portc = Lookup(m2 , Tabelle) 'Lookup-Befehl: (Für jeden Wert von M2 wird der dazugehörige wert in der Tabelle an PortC ausgegeben) Portb = &B00001000 'Zweite Stelle der Minutenanzeige einschalten Waitms 2 Return Tabelle: Data &B00000000, '0 Data &B00000001, '1 Data &B00000010, '2 Data &B00000011, '3 Data &B00000100, '4 Data &B00000101, '5 Data &B00000110, '6 Data &B00000111, '7 Data &B00001000, '8 Data &B00001001, '9
Tom schrieb: > Ehm, NOP ist laut Wikipedia ein Befehl der nichts macht, richtig? Jup, genau richtig... NOP = No Operation aus dem Assembler Befehlssatz. Der verbrät einfach nur 1 Takt! das ist der große Vorteil von Bascom das man zwischendruch mal schnell ein paar Assemblerzeilen schreiben kann. Geht in AVR GCC aber nicht ganz soo schön! Zu deiner ISR: Waitms hat im Interrupt mal garnix verloren! damit bremst du das ganze Programm aus! In der Zeit kann kein anderer Interrupt erfolgen, da das I-Flag im SREG während der ISR gelöscht wird! Folgende Rechnung: Systemtakt: 1 MHZ / Prescale: 128 / Takte bis Überlauf:78 1/1MHZ = 1µS Also: 1µS X 128 X 78 = 10ms von Interrupt zu Interrupt... Wenn du das mit waitms machst, bekommst du rechnerisch bei 6 Anzeigen schon 10ms Wartezeit!! Sowas kann man in der Do - Loop schleife machen aber NICHT in einer ISR! Das was du machst ist kein Richtiges Multiplexing. Multiplexing sieht so aus: HAUPTPROGRAMM INTERRUPT: Anzeige 1 aktualisieren HAUPTPROGRAMM INTERRUPT: Anzeige 2 aktualisieren HAUPTPROGRAMM INTERRUPT: Anzeige 3 aktualisieren HAUPTPROGRAMM INTERRUPT: Anzeige 4 aktualisieren HAUPTPROGRAMM INTERRUPT: Anzeige 5 aktualisieren HAUPTPROGRAMM INTERRUPT: Anzeige 6 aktualisieren HAUPTPROGRAMM und dann wieder von Vorne! In SUMME: Bei jedem Interrupt von Timer2 1!!!!!!!!!!! Anzeige aktualisieren und dann auch bis zum nächsten Interrupt stehen lassen.
:
Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.