- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 10 von 10

Thema: Programmierproblem PropClock

  1. #1
    Murus
    Gast

    Programmierproblem PropClock

    Anzeige

    Praxistest und DIY Projekte
    Hallo zusammen,

    meine Propclock funktioniert!
    Es ist zwar eine Heissleim-Sekundenkleber-McGyver-Lösung, aber sie funktioniert....

    Ich betreibe 8 Leds direkt am AVR (hat Nachteile, ich kann sie nicht gross bestromen, muss sie daher etwas länger leuchten lassen, das ergibt etwas breite Zahlen, aber es geht)

    Die Synchronisation zwischen Drehzahl und Anzeige realisiere ich über eine kleine Gabellichtschranke, die mitdreht und durch einen Draht rauscht. Über Schleifer schicke ich 15V in einen 680müF Elko, an dem ein 7805er hängt, der mir den Mega mit Saft versorgt.

    Ich habe momentan einen Timer am Laufen. (Timer0) Wenn er überläuft, wird die nächste Spalte "angeleuchtet".
    Wenn er 4 mal übergelaufen ist (so breit ist die Zahl 1), stellt er den Timer und die Leds ab. Wenn der Interrupt 0 (da hängt die Lichtschranke) reinkommt, dann wirft er den voreingestellten Timer 0 an, geht wieder an den Anfang der Zahl 1 im Array und übergibt die Kontrolle wieder dem Timer1.

    So krieg ich momentan eine schöne Zahl dargestellt.
    Eine Anpassung des Timer0 über die Drehzahl (damit die Zahlen immer gleich breit sind) werde ich nicht machen, da ich konstant drehen lasse und sowieso jetzt schon recht langsam drehe, schneller ist nicht möglich, sonst hauts mir wahrscheinlich den Aufbau um die Ohren, aber so gehts gut, die Zahlen flackern nur schwach.

    Jetzt möchte ich aber eine Uhr bauen. Mein momentan nicht aktives Hauptprogramm ist noch frei, sowie zwei Timer.
    Wie mache ich das? Das kann ich doch irgendwie auch nicht mit einem Timerinterrupt, der mit 1Hz kommt machen, da das sonst doch ein Chaos mit den anderen beiden Interrupts gibt...

    Wie könnte man das lösen? Wie berechne ich die Zeit-Zahlen, um sie anzuzeigen? (Anzeigen tu ich in der Timer0-Interruptroutine)

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Meine Uhr-Software haben folgende Struktur:
    Timer1 macht den Arbeitstakt. Die Hauptarbeit übernimmt OutCompare1. Die Interruptlast habe ich bei 10kHz, weil ich ne PWM von Hand machen muss. OutComp1 macht mir softwaremässig nen Untertakt von 100Hz (10ms) wo ich Taster nachschaue, 10ms-Timer fur Warteschleifen erniedrige, DCF-Modul abfragen, Zeit weiterzähle alls kein DCF-Signal da ist, etc...
    Das Hauptprogramm hat fast nix zu tun. Es übernimmt Initialisierung, Debugausgabe via RS232 und Menüsteuerung zur Konfiguration der Uhr (Weckzeit, Anzeigeeigenschaften, etc). Die meiste Zeit schnarcht es in der Menü-SCHleife und wartet auf EINgaben vom Benutzer.

    Timer0 brauche ich nur für RC5-Empfang (ganz praktisch).

    Wenn du high efficiency-LEDs nimmst oder super bright, brutzelst du dir mit 10mA fast die Netzhaut ab. An Helligkeit sollte es da nicht mangeln...
    Disclaimer: none. Sue me.

  3. #3
    Murus
    Gast
    Eeeeh, wie was wo jetzt? Was meinst du mit dem Arbeitstakt? Und was ist OutCompare1? Wo haste die Ausgabe verstaut? Ich hab eben so ganz kleine Leds, die brauchen net viel, dafür net so hell, aber es geht gut, man siehts klar.

  4. #4
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Timer1 hat einen Modus, inder er immer einen Interrupt auslöst, wenn der Wert von Timer1 (TCNT1) mit OCR1A (Output Compare Register 1A) übereinstimmt. Wenn man zusätzlich CTC1 (Clear Timer on Compare Match) aktiviert hat, wird beim Erreichen des Wertes der Zähler wieder auf 0 zurückgesetzt. Damit vermeidet man Ungenauigkeiten wie sie entstehen, wenn man selber den Timerwert zurücksetzt.

    Den Interrupt den ich verwende heisst "Timer/Counter1 Compare Match A".
    Die Anzeige aktualisiere ich in diesem Interrupt, der mit einer Rate von 10kHz kommt. Alle 100 Interrupt-Ereignisse erledige ich das Zeug, das nur alle 10 ms dran kommen muss. In dem Interrupt mach ich auch die Frequenz für nen kleinen Lautsprecher (Rückmeldung für Tastendruck), allerdings nur bei 2-3kHz. Die verschiedenen Frequenzen von 3kHz oder 100Hz realisiere ich einfach über Zählvariablen, die ich hochzähle.
    Für den 100Hz-Interrupt wird eine Variable auf 0 gesetzt und in jedem Interrupt eins erhöht. Bin ich bei 100, dann wird sie auf 0 zurückgesetzt und der Job, der alle 10ms dran ist, ausgeführt.
    Disclaimer: none. Sue me.

  5. #5
    Murus
    Gast
    Ahaaa, jetzt seh ichs...
    Hmmm
    Bei dir kommt der Interrupt alle 10kHz... Zeigst du dann jedesmal die nächste Led-Reihe an?
    Aber wenn du dann ab und zu noch andere Sachen abfragst, dann gibt es doch ab und zu Lücken zwischen den Zahlen...???
    Du hast das Ding ja über Funk gelöst..
    Wie könnte ich das machen? Ich möchte die Zeit über einen Timer berechnen, nur wie? Einen Timer verwende ich ja eben zum Anzeigen.. ??

  6. #6
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Du kannst auch Timer1 verwenden um die Zeit zu machen und Timer0 für die Anzeige. Jedanfalls ist das eine Lösung, wo du nicht viel oder nix in deiner Anzeigeroutine ändern musst.

    Timer1 macht dir die Zeit, könnte sogar nur 1 Interrupt alle Sekunde machen (über Prescaler). Das reicht schon. Die Zeit schreibst du in Variablen: Sekunde, Minute, Stunde, Wochentag, was du anzeigen willst und benutz das in Timer0. Ob du sukzessive Interrupts erlaubst, kommt drauf an wie stark deine Echtzeitanforderung ist. Falls Timer0 den Timer1-Interrupt unterbrechen darf, könnte passieren, daß zwischen Minute hochzählen und Stunde zählen Timer0 zuschlägt. Nach 12:59 wird dann nicht 13:00 angezeigt sondern fälschlicherweise 12:00. Da gibt es 2 Möglichkeiten mit umzugehen:
    - du ignorierst es. Die falsche Zeit wird nur sehr kurz angezeigt. Beim nächsten Umlauf stimmt wieder alles. Wahrscheinlich fällt das nicht mal auf.
    - für die Zeit wo die Daten inkonsisten sind, deaktivierst du Timer0 Interrupt oder alle Interrupts. Danach werden die IRQs wieder freigegeben. IRQ gehen dabei keine verloren.

    Lücken gibt es bei mir nicht. Meine Anzeige ist kein Rotor, aber ich muß auch fix sein, sonst flackert die Anzeige.

    Du kannst auch alles in einer ISR machen. Erst die Anzeige setzen bzw die neue LED-Spalte. Danach machst du sonstiges Zeug das ansteht. Dadurch hast du die LED-Aktualisierung immer im gleichen Zeitraster. Daß die Zeit erst danach angepasst wird stört nicht. Wenn dein Rotor mit 50 U/s dreht und du in 7.2°-SChritten aktualisieren musst (1/50 Vollwinkel), brauchst du eine IRQ-Rate von 2.5kHz. Bei 16MHz MCU-Takt hast du 6400 Zyklen bis wieder ein IRQ kommt. Massig Zeit!
    Disclaimer: none. Sue me.

  7. #7
    Murus
    Gast
    Jo, hab das AVR-Zeitgefühl noch net so drauf...

    Ich habs jetzt mal mit Timer1, der 1 Interrupt/s liefert gemacht... funktioniert gut!
    Tja, dann gehts weiter mit verbessern und experimentieren...

    Herzliche Grüsse und vieelen Dank!!

    Mario

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Wenn ich's richtig verstanden hab, ist der Aufbau so:

    15V -- Schleifer -- Elko -- 7805 -- µC + LEDs ?

    Wie laut ist das Teil eigentlich? Und mit welcher Drehzahl arbeitest du?
    Disclaimer: none. Sue me.

  9. #9
    Murus
    Gast
    Ja, Aufbau stimmt....

    Das Ding ist höllisch laut, Bürstenmotor halt.
    Drehzahl weiss ich net, aber ziemlich langsam, das Ding ist net gewuchtet, funktioniert aber gut.

    Soll natürlich keine Uhr zum Zeitablesen werden, mehr ein Experimentierträger.

  10. #10
    Murus
    Gast
    Also, ihr mit den hohen Mehrwertsteuern,

    die Propclock zeigt mir jetzt die Sekunden und Minuten an. Zeit kann nicht eingestellt werden, da ich keine Taster dran hab, sie zählt einfach hoch und zeigt die Minuten und Sekunden an.
    Timer1 erzeugt mir jede Sekunde einen Interrupt, in dem hochgezählt wird. 1800 mal in der Sekunde kommt ein Timer0-Interrupt, in dem die nächste Spalte angezeigt wird. Das Ganze funktioniert nicht schlecht, ab und zu flackert die Anzeige, da sich die Interrupts in die Wege kommen. (eine Zahl bleibt zu lange stehen). Zudem sind die "Pixel" etwas lang, da meine Leds nicht grad dolle hell sind, ich betreibe sie direkt am AVR, kann also net zuviel Strom geben.
    Aber sonst funktioniert. Hier ist mal der Code, für alle, die Interesse haben:

    $regfile = "m8def.dat"
    $crystal = 1000000

    Dim A As String * 2 ' Wird gebraucht, um die Zahlen in einen String zu verwandeln
    Dim I As String * 2 ' Eine Ziffer des Strings/der Zahl
    Dim O As String * 2 ' Eine Ziffer des Strings/der Zahl
    Dim Z As Byte ' Zählvariable für die Sekunden
    Z = 0
    Dim M As Byte ' Absolute Ziffer des Strings
    Dim N As Byte ' Absolute Ziffer des Strings
    Dim G As Byte ' Startzahl zweite Ziffer der ersten Zahl(Sekunden)
    Dim U As Byte ' Startzahl erste Ziffer der ersten Zahl (Sekunden)
    Dim W As Byte ' Stopzahl erste Ziffer der ersten Zahl (Sekunden)
    Dim H As Byte ' Stopzahl zweite Ziffer der ersten Zahl (Sekunden)
    Dim K As Byte ' Zählvariable, zur Bestimmung, wann die nächste Zahl dargestellt wird
    Dim J As Byte ' Kopie von U
    Dim E As Byte ' Kopie von W
    Dim T As Byte ' Kopie von G
    Dim P As Byte ' Kopie von H
    Dim B As Byte ' Zählvariable für die Minuten
    B = 0
    Dim C As Byte ' Startzahl erste Ziffer der zweiten Zahl (Minuten)
    Dim V As Byte ' Stopzahl erste Ziffer der zweiten Zahl (Minuten)
    Dim F As Byte ' Stopzahl zweite Ziffer der zweiten Zahl (Minuten)
    Dim S As Byte ' Startzahl zweite Ziffer der zweite Zahl (Minuten)
    Dim Q As Byte ' Kopie von C
    Dim R As Byte ' Kopie von V
    Dim D As Byte ' Kopie von S
    Dim Y As Byte ' Kopie von F
    Dim Lk As Byte ' Variable für die For-Schleife für den Doppelpunkt
    Dim Mn As Byte ' Variable für die Stelle im String, wo ausgelesen wird


    Ddrb = &B11111111 ' Led-Ausgänge (ganzer Port B)
    Ddrd.2 = 0 ' Lichtschranken-Eingang
    Portd.2 = 1 ' Pullup vom Lichtschranken-Eingang angeschaltet

    Dim X(51) As Byte ' In diesem Array werden die einzelnen Ziffern definiert

    X(1) = &B11111111
    X(2) = &B10000001
    X(3) = &B10000001
    X(4) = &B11111111
    X(5) = &B00000000

    X(6) = &B00100000
    X(7) = &B01000000
    X( = &B11111111
    X(9) = &B00000000
    X(10) = &B00000000

    X(11) = &B01100111
    X(12) = &B10001001
    X(13) = &B10010001
    X(14) = &B01100001
    X(15) = &B00000000

    X(16) = &B11100011
    X(17) = &B10001001
    X(1 = &B10011001
    X(19) = &B11111111
    X(20) = &B00000000

    X(21) = &B00010000
    X(22) = &B00110000
    X(23) = &B01010000
    X(24) = &B11111111
    X(25) = &B00000000

    X(26) = &B11100111
    X(27) = &B10100001
    X(2 = &B10100001
    X(29) = &B10111111
    X(30) = &B00000000

    X(31) = &B00111111
    X(32) = &B01001001
    X(33) = &B10001001
    X(34) = &B10000111
    X(35) = &B00000000

    X(36) = &B10000111
    X(37) = &B10001000
    X(3 = &B10010000
    X(39) = &B11100000
    X(40) = &B00000000

    X(41) = &B11111111
    X(42) = &B10010001
    X(43) = &B10010001
    X(44) = &B11111111
    X(45) = &B00000000

    X(46) = &B11110001
    X(47) = &B10010001
    X(4 = &B10010001
    X(49) = &B11111111
    X(50) = &B00000000


    X(51) = &B00100100



    On Timer0 Timerinterrupt ' Timer0 löst mit etwa 1800Hz aus. Bei jedem Interrupt wird die nächste Spalte angezeigt
    Config Timer0 = Timer , Prescale = 8
    Timer0 = 190
    Enable Timer0
    Enable Interrupts

    On Timer1 Zeitinterrupt ' Timer 1 löst jede Sekunde aus und lässt die Sekunden/Minuten hochzählen
    Config Timer1 = Timer , Prescale = 64
    Timer1 = 49911
    Enable Timer1

    On Int0 Lichtinterrupt ' Bei diesem Interrupt wird die Anzeige neu aufgesetzt: Die momentanen Zahlen werden wieder neu dargestellt
    Config Int0 = Rising
    Enable Int0

    Mn = 2

    A = Str(b) ' Hier werden die Ziffern zerlegt und jeder Ziffer werden zwei Werte (Start-Stop) im Array zugeordnet
    If B < 10 Then
    U = 1
    W = 6
    Mn = 1
    Goto Klein3
    End If
    O = Mid(a , 1 , 1)
    N = Val(o)

    U = N * 5
    U = U + 1
    W = U + 5

    Klein3:
    I = Mid(a , Mn , 1)
    M = Val(i)

    G = M * 5
    G = G + 1
    H = G + 5

    Mn = 2
    A = Str(z)
    If Z < 10 Then
    C = 1
    V = 6
    Mn = 1
    Goto Klein4
    End If
    O = Mid(a , 1 , 1)
    N = Val(o)

    C = N * 5
    C = C + 1
    V = C + 5

    Klein4:
    I = Mid(a , Mn , 1)
    M = Val(i)

    S = M * 5
    S = S + 1
    F = S + 5

    J = U ' Hier werden Kopien der Start-Stop-Werte angelegt.
    E = W
    T = G
    P = H
    Q = C
    R = V
    D = S
    Y = F
    K = 0


    Do ' In der Hauptschleife wird nichts ausgeführt.
    Loop

    Timerinterrupt: 'Timer-Überlauf-Routine: Nächste Array Spalte anzeigen
    Timer0 = 190


    Portb = X(u) ' Die momentane Array-Spalte wird angezeigt
    Incr U

    If U = W Then ' Hier wird die zweite Ziffer der momentanen Zahl unter U und W gespeichert.
    Incr K
    U = G
    W = H
    End If

    If K = 2 Then ' Hier wird die zweite Zahl unter U/W und G/H eingestellt.
    Incr K
    U = C
    W = V
    G = S
    H = F
    nop
    nop
    nop
    nop
    nop
    For Lk = 1 To 5 Step 1 ' Hier wird der Doppelpunkt dargestellt.
    Portb = X(51)
    Next
    End If

    If K = 5 Then ' Wenn beide Zahlen dargesellt sind, wird der Port B abgeschaltet und die Interrupts von Timer1 gestoppt.
    Portb = &B00000000
    Disable Timer0
    End If

    Return

    Lichtinterrupt: ' Lichtschranken-Interrupt-Routine: Im Array wieder von vorne beginnen

    Timer0 = 190
    Enable Timer0


    U = J ' Die Variablen für die Zahlen werden aus den Kopien wiederhergestellt.
    W = E
    G = T
    H = P

    C = Q
    V = R
    S = D
    F = Y

    K = 0
    Return

    Zeitinterrupt: ' Wird jede Sekunde ausgelöst und lässt die Sekunden/Minuten hochzählen.
    Timer1 = 49911
    Incr Z

    If Z = 60 Then ' Nach einer Minute wird zur Minuten-Variable eins dazugezählt
    Z = 0
    B = 0
    Incr B
    End If


    Mn = 2

    A = Str(b) ' Hier werden die neuen Start-Stopwerte der beiden Zahlen berechnet.
    If B < 10 Then
    U = 1
    W = 6
    Mn = 1
    Goto Klein1
    End If
    O = Mid(a , 1 , 1)
    N = Val(o)

    U = N * 5
    U = U + 1
    W = U + 5

    Klein1:
    I = Mid(a , Mn , 1)
    M = Val(i)

    G = M * 5
    G = G + 1
    H = G + 5

    Mn = 2
    A = Str(z)
    If Z < 10 Then
    C = 1
    V = 6
    Mn = 1
    Goto Klein2
    End If
    O = Mid(a , 1 , 1)
    N = Val(o)

    C = N * 5
    C = C + 1
    V = C + 5

    Klein2:
    I = Mid(a , Mn , 1)
    M = Val(i)

    S = M * 5
    S = S + 1
    F = S + 5

    J = U ' Hier werden wieder die neuen Kopien angelegt, damit sie im Lichtinterrupt neu aufgesetzt werden können.
    E = W
    T = G
    P = H
    Q = C
    R = V
    D = S
    Y = F
    K = 0
    Return
    End 'end program

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test