Mach' die Umschalterei von Anfang an über einen Timer. Alles andere wirst du später bereuen.
Und denke daran, immer erst alles abzuschalten, bevor du neue Werte auf die Ports gibst. Sonst bekommst du die leidigen Geisterbilder.
Druckbare Version
Mach' die Umschalterei von Anfang an über einen Timer. Alles andere wirst du später bereuen.
Und denke daran, immer erst alles abzuschalten, bevor du neue Werte auf die Ports gibst. Sonst bekommst du die leidigen Geisterbilder.
Hab mich jetzt mal ein wenig mit dem multiplexen beschäftigt. Die Schaltung der gem. Anoden und den Transistoren funktioniert soweit. Leider hängt es wieder bei der Programmierung. Ich hab einen atmega8 mit 1Mhz Frequenz. Soweit ich es verstanden habe wird dem 8bit Timer automatisch ein 10bit prescaler also /1024 eingeschaltet. Stelle ich jetzt in der config einen prescaler 8 ein komm ich auf 122 Hz (richtig??). Mein eigentlches Problem ist die programmierung, um die beiden Ausgänge für die gem. Anoden an bzw. aus zu schalten. Ich komm nicht so richtig mit den variablen klar. Müssen jetzt die einzelnen Segmente abwechselnd oder jede einfach für sich ein/ausgeschaltet werden und wie sage ich jedem Ausgang das bei den Zehnern jetzt ne 1 und bei den Einern ne null angezeigt werden soll. Vielleicht kann mir jemand mal in Worten den Ablauf erklären?
Deine 1MHz sind natürlich nicht so umwerfend schnell, aber es sollte trotzdem gehen.
Deine Angaben mit dem Prescaler habe ich nicht verstanden. Was ist ein 10bit prescaler?
Wenn du 2 Stellen umschalten willst und dies flimmerfrei mit 100Hz, dann muss deine ISR Frequenz folglich mindestens 200 Hz betragen.
Du kommst auf die richtigen Werte für Prescale und Anzahl Überläufe über diesen Zusammenhang:
Gewünschte Frequenz (bei dir 200) = $crystal / prescale / overflow_count
Bei 1MHz Crystal also z.B.
200 ~ 1.000.000 / 1024 / 5 oder
200 ~ 1.000.000 / 64 / 78
200 ~ 1.000.000 / 8 / 312
Da du einen 8-bit Timer benutzen willst, wird die letzte Version nicht mehr gehen, da der Timer nur bis 255 zählen kann.
Je kleiner der Prescale um so genauer kannst du den gewünschten Wert treffen. Das ist bei dir aber eher unerheblich.
In der Timer_isr schaltest du jetzt bei jedem Aufruf zwischen den beiden Ausgängen für die gemeinsamen Anoden um und legst den neuen Wert auf die Ausgänge für die Segmente. Wenn die alle an einem Port liegen, kannst du dies sehr einfach mit einem Befehl tun. So ähnlich wie oben also mit
PortD = Segmente(wert_der_stelle)
Die Info mit dem 10bit Prescaler hab ich aus nem Buch für Atmel-Programmierung. "....Timer0 ist ein 8-Bit-Timer mit einem vorgeschaltetem 10-Bit-Prescaler."
Das Schalten der Ausgänge für die Zehner/Einer hab ich so gelöst:
Trotz viel Lesen und probieren ist es mir aber noch nicht gelungen z.B. eine "10" darzustellen. Ich hab ein Paar Beispiele mit "Select Case" gesehen, hab sie aber nicht verstanden? Ist das eine Möglichkeit die ich verwenden sollte?Code:$regfile = "M8def.dat"
$crystal = 1000000
'--------Segmente---------------
Config Portd = Output
Portd = 1
'----------Anode Display---------
Config Portb = Output
Digit1 Alias Portb.1
Digit2 Alias Portb.2
Portb = 0
'---------AD-Wandler Config-------------
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc
'--------Timer Config----------------
Dim A As Byte 'Umschaltung einer/zehner
Config Timer0 = Timer , Prescale = 8
On Timer0 Timer_routine
Enable Timer0
Enable Interrupts
Dim Messung As Integer
Dim I As Byte
Dim X(10) As Byte
Restore Segmente
For I = 1 To 10
Read X(i)
Next I
Do
Messung = Getadc(0) / 103 'Wert vom ADC/103 in Variable speichern
Portd = X(messung + 1)
Loop
End
Timer_routine:
Incr A 'Variable um 1 erhöhen
Portb = A 'portb.1 /portb.2 an/aus schalten
Return
'---------------------------------------------------------------------------
Segmente:
'gemeinsame Anode:
' 0 1 2 3 4 5 6 7 8 9
'Data &H3F , &H6 , &H05B , &H04F , &H066 , &H06D , &H07D , &H7 , &H7F , &H6F
'gemeinsame kathode:
' 0 1 2 3 4 5 6 7 8 9
Data &H40 , &H79 , &H24 , &H30 , &H19 , &H12 , &H02 , &H78 , &H00 , &H10
Sieht doch gar nicht so schlecht aus. Ich habe mal ein paar kleine Änderungen gemacht. Probier es mal aus.
Code:$regfile = "M8def.dat"
$crystal = 1000000
'--------Segmente---------------
Config Portd = Output
Portd = 1
'----------Anode Display---------
Config Portb = Output
Digit1 Alias Portb.1
Digit2 Alias Portb.2
Portb = 0
'---------AD-Wandler Config-------------
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc
'--------Timer Config----------------
Dim A As Byte 'Umschaltung einer/zehner
Config Timer0 = Timer , Prescale = 8
On Timer0 Timer_routine
Enable Timer0
Enable Interrupts
A = 1
Dim Messung As Word
Dim Stelle(2) As Byte
Dim I As Byte
Dim X(10) As Byte
Restore Segmente
For I = 1 To 10
Read X(i)
Next I
Do
Messung = Getadc(0) / 11 'Wert vom ADC/11 (0-99) in Variable speichern
Stelle(1) =messung / 10 'Hinter dem Komma wird abgeschnitten, enthält also die Zehner
Incr Stelle(1) 'Damit die Werte von 1-10 gehen
Stelle(2)=messung mod 10 'gibt den Rest, also die Einer
Incr Stelle(2)
Loop
End
Timer_routine:
Portb.a = 0 'Vorherige Stelle ausschalten
Incr A
If A=3 Then A=1
Portd=X(Stelle(A)) 'Neue Segmente ausgeben
Portb.a = 1 'Neue Stelle einschalten
Return
Segmente:
'gemeinsame Anode:
' 0 1 2 3 4 5 6 7 8 9
'Data &H3F , &H6 , &H05B , &H04F , &H066 , &H06D , &H07D , &H7 , &H7F , &H6F
'gemeinsame kathode:
' 0 1 2 3 4 5 6 7 8 9
Data &H40 , &H79 , &H24 , &H30 , &H19 , &H12 , &H02 , &H78 , &H00 , &H10
super!!! Manchmal flackkern die Zahlen zwar ein bisschen aber ich denke das hängt mit der niedrigen Grundfrequenz des Atmegas zusammen?! Ich werd mich mal durch den Code wuseln um zu verstehen was du alles gemacht hast.
Vielen Dank :)
Nachdem ich mir meinen Atmega "Verfused" habe und ihn nach viel lesearbeit, mit nem tiny wieder flott gemacht habe, sitz ich nun vor dem nächsten Problem.
Es geht um die Berechnung des ADC-Wertes in eine Anzeigbare Temperatur.
Hab schon viel über die KTY-Reihe gelesen und wie diese linearisiert werden (darauf kommts mir erstmal nicht an).
Also ich verwende einen KTY81-120. Ich hab ihn über einen Spannungsteiler 1K am ADC-Pin angeschlossen. Nun hab ich mit meinem Multimeter eine Zimmertemperatur von 20 Grad gemessen. Dies wollte ich als Ausgangstemperatur nehmen. Am Sensor liegt also bei 20 Grad eine Spannung von 2,5 Volt an. Das entspricht einem ADC-Wert von 512. Der Widerstandbereich des KTY liegt bei 1721 Ohm (20 Grad = 1KOhm).
Ich krieg die Formel für die Umrechnung einfach nicht hin, obwohl es doch gar nicht so schwer sein kann???
@ for_ro
Kannst du mir den Befehl "mod" und den Code-Abschnitt (siehe unten) noch erklären? Hab in der Hilfe keine Erklärung gefunden.
Code:If A = 3 Then A = 1
Portd = X(stelle(a))
Ich hab mir nun folgendes Programm erarbeitet:). Die Temperatur haut schonmal ganz gut hin. Allerdings hab ich es immer noch nicht hinbekommen eine weiter Stelle der 7-Segment-Anzeige anzusprechen. Hier soll einfach ein "°" angezeigt werden. Den Code in der Timer-Routine hab ich immer noch nicht ganz verstanden. Vielleicht kann mir jemand auf die Sprünge helfen.Code:$regfile = "M8def.dat"
$crystal = 4000000
'--------Segmente---------------
Config Portd = Output
Portd = 1
'----------Anode Display---------
Config Portb = Output
Digit1 Alias Portb.1
Digit2 Alias Portb.2
Digit3 Alias Portb.3
Portb = 0
'---------AD-Wandler Config-------------
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc
'--------Timer Config----------------
Dim A As Byte 'Umschaltung einer/zehner
A = 1
Config Timer0 = Timer , Prescale = 64
On Timer0 Timer_routine
Enable Timer0
Enable Interrupts
Dim Messung As Word
Dim Stelle(3) As Word
Dim I As Byte
Dim X(11) As Byte
Restore Segmente
For I = 1 To 10
Read X(i)
Next I
Do
Messung = Getadc(0) * 64
Messung = Messung / 101
Messung = Messung - 151
Stelle(1) = Messung / 10
Incr Stelle(1)
Stelle(2) = Messung Mod 10
Incr Stelle(2)
Loop
End
Timer_routine:
Portb.a = 0 'Vorherige Stelle ausschalten
Incr A 'Neue Segmente ausgeben
If A = 3 Then A = 1
Portd = X(stelle(a))
Portb.a = 1
Return
Segmente:
'gemeinsame Anode:
' 0 1 2 3 4 5 6 7 8 9
'Data &H3F , &H6 , &H05B , &H04F , &H066 , &H06D , &H07D , &H7 , &H7F , &H6F
'gemeinsame kathode:
' 0 1 2 3 4 5 6 7 8 9 Grad
Data &H40 , &H79 , &H24 , &H30 , &H19 , &H12 , &H02 , &H78 , &H00 , &H10 , &H63
Hallo Malte0815,
ich hatte nicht gesehen, dass du mich schon einmal direkt gefragt hattest.
If A = 3 Then A = 1
Portd = X(stelle(a))
A ist die Stelle, die aktuell eingeschaltet ist, in Stelle(A) steht der aktuelle Wert, der ausgegeben werden soll.
In X(Stelle(A)) steht der entsprechende Segment-Wert für diese Ziffer.
Wenn du jetzt 3 Stellen hast, dann musst du A bis 4 laufen lassen, bevor es wieder auf ein gesetzt wird. Also
If A = 4 Then A = 1
Das Gradzeichen würde ich am Anfang einmal fest in Stelle(3) schreiben, dann brauchst du sonst nichts mehr zu ändern. Also hinter
For I = 1 To 10
Read X(i)
Next I
einfach noch
Read Stelle(3) oder direkt
Stelle(3) = &H63
Hier mal alles zusammen (mit noch etwas Kosmetik):
Code:$regfile = "M8def.dat"
$crystal = 4000000
'--------Segmente---------------
Config Portd = Output
Portd = 0 'anfangs alles aus
'----------Anode Display---------
Config Portb = Output
Digit1 Alias Portb.1
Digit2 Alias Portb.2
Digit3 Alias Portb.3
Portb = 0 'auch hier alles aus
'---------AD-Wandler Config-------------
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc
'--------Timer Config----------------
Dim Stelle As Byte 'Umschaltung zehner/einer/grad_zeichen
Stelle = 1 'start mit Zehner
Config Timer0 = Timer , Prescale = 64
On Timer0 Timer_routine 'wird 4.000.000/64/256 ~ 244 mal pro Sekunde aufgerufen
Enable Timer0
Enable Interrupts
Dim Messung As Word
Dim Wert_stelle(3) As Byte
Dim I As Byte
Dim Temp As Word
Dim Segmente(11) As Byte
Restore Segment_daten
For I = 1 To 10
Read Segmente(i)
Next I
Wert_stelle(3) = &H63 '°fest auf Stelle 3
Do
Messung = Getadc(0) * 64
Messung = Messung / 101
Messung = Messung - 151
Messung = Messung
Temp = Messung / 10 'ganzahlige Division, also 47 / 10 = 4
Wert_stelle(1) = Temp + 1
Temp = Messung Mod 10 'Mod ergibt den Rest der Division, also bei 47 / 10 ist Mod = 7
Wert_stelle(2) = Temp + 1
Waitms 100 'hier vielleicht noch eine kleine Pause
Loop
End
Timer_routine:
Portb.stelle = 0 'Vorherige Stelle ausschalten
Portd = 0 'zusätzlich alle Segmente aus
Incr Stelle 'auf nächste Stelle umschalten
If Stelle = 4 Then Stelle = 1 'am Ende wieder zurück zur ersten Stelle
Portd = Segmente(wert_stelle(stelle)) 'Neue Segmente ausgeben
Portb.stelle = 1 'neue Stelle einschalten
Return
Segment_daten:
'gemeinsame Anode:
' 0 1 2 3 4 5 6 7 8 9
'Data &H3F , &H6 , &H05B , &H04F , &H066 , &H06D , &H07D , &H7 , &H7F , &H6F
'gemeinsame kathode:
' 0 1 2 3 4 5 6 7 8 9 Grad
Data &H40 , &H79 , &H24 , &H30 , &H19 , &H12 , &H02 , &H78 , &H00 , &H10 ', &H63
Hmm...ich bin nun schon den ganzen Morgen am probieren aber irgdwo steckt noch der Wurm drin.
Hab auch eben deinen überarbeiteten Code(danke für die Mühe O:)) probiert aber immer das selbe Phänomen.
Sobald ich bei" If Stelle = 3 Then Stelle = 1" die 3 durch eine 4 ersetze, leuchten bei beiden Digits alle segmente auf und die zu darstellenden Zahlen leuchten etwas heller durch. Beim dritten Digit leuchtet eine Mischung aus Zehnern und einern.
Anfangs dachte ich es hätte etwas mit der Frequenz zu tun aber mit Teiler 8 ist das selbe.
Wenn ich nun wieder 3 einsetze, werden Einer und Zehner wieder normal angezeigt und beim dritten Digit unverändert eine Mischung aus beiden Zahlen.
Ich versteh es nicht....wenn die Variable des Portb einfach um eins weiter zählen soll, kann sich doch bei der Darstellung nichts ändern, außer das die Frequenz ohne Anpassung niedriger wird, oder seh ich da was falsch?