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 :-)
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.
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.
