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.