Bascom HDD Uhr Ansteuerung der einzelnen Ziffern

Kampfkartoffel

Neues Mitglied
10. März 2015
14
0
1
Sprachen
Hallo Community

Das Projekt nähert sich seiner fertigstellung :)

Hardwaretechnisch sind wir fertig, jezt fehlt nur noch die Software.

Doch von anfang an. ich habe vor, eine HDD Uhr zu bauen, diese sieht von der Hardware her etwa aus wie dieses modell: https://www.youtube.com/watch?v=7Qyawcw-ots
Jezt ist nur das große Problem: wie steuer ich die einzelnen LED Reihen (5 an der Zahl) genau an.
Eine einzelne Reihe ansteuern stellt kein großes Problem dar und klappt mit ein wenig feinjustierung ziemlich gut.
Hier einmal der funktionierende code:


CodeBox BascomAVR
$regfile "m8adef.dat"                                       'ATmega8a auswählen
$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 3686400                                          'Prozessor auf 3,6864 MHz setzen
$baud = 19200                                               'Datenrate Setzen

'Ports Deklarieren

Config Portb = Output                                       'LED Ports auf Ausgang
Config Portd.7 = Output

'Aliase festlegen
Led1 Alias Portb.1

Config Int0 = Falling                                       ' Configuriere Int0 (PortD.2) Auf Low Level
Enable Interrupts                                           'einschalten Der Interrupts
Enable Int0                                                 'einschalten Von Interrupt Int0
On Int0 Isr_hall_sensor                                     'springe Zu Isr_von _int0

'Config Timer1 = Timer , Prescale = 8                        'Timer Konfigurieren mit tmax=142ms
Config Timer1 = Timer , Prescale = 1                        'Timer Konfigurieren mit tmax=17,7ms
Enable Timer1                                               'Timer starten
'On Timer0 Isr_timer1


Config Adc = Single , Prescaler = Auto , Reference = Avcc   'Analogwandler definieren


'Variablen
Dim Led1out As Byte

Dim Periodendauer As Single
'Periodendauer = 1 / 460800                                  'Zeit errechnen, die nach 1 Timer vergeht
Periodendauer = 1 / 3686400
Dim Winkeldauer As Single

Dim Led1_winkel As Word
Dim X As Bit
Dim Umdrehung As Word

'Led1_winkel = 180
Portd.7 = 1

Do                                                          'Hauptprogramm starten
Led1_winkel = Getadc(0)


Gosub Led_ausgabe                                           'Zur LED ansteuerung springen

Loop                                                        'Hauptprogramm Ende

Isr_hall_sensor:
'Toggle Led1                                                 'Wenn Hall Sensor Signal bekommt, wird hierher gesprungen
'Umdrehung = Timer1 * Periodendauer
'Winkeldauer = Umdrehung / 360
Winkeldauer = Timer1 / 360                                  'Timmer Pro Winkel errechnen
Timer1 = 0                                                  'Timer zurücksetzen
X = 1
Return

Led_ausgabe:
'LED1
Umdrehung = Winkeldauer * Led1_winkel                       'Timer Wert mit Winkel und Zeit errechnen
If Timer1 >= Umdrehung And X = 1 Then                       'Wenn der Timer die richtige Zeit erreicht hat
   Led1 = 1                                                 'LED1 einschalten
   Waitus 250                                               '900 µs warten
   Led1 = 0                                                 'LED1 wieder ausschalten
   X = 0
End If                                                      'If Abfrage beenden

Return


Dabei wird bei jeder Umdrehung ein Interrupt vom Hall Sensor ausgelöst. Ab diesem Zeitpunkt wird der Timer 1 aktiviert und soll nach einer bestimmten Zeit die LED ein und dannach auschalten.
Die Zeit wird über einen Winkel errechnet. So wird nach einer Umdrehung der Timer ausgelesen und durch 360 geteilt.
Dann wird dieser Wert mit dem errechneten Winkel multipliziert.
In diesem Test kann man den winkel via Poti einstellen um eine feinjustierung zu erreichen.

Das große Problem an der Sache ist das ansteuern aller 5 LED reihen zu verschiedenen Zeiten.
Meine bisherigen Versuche produzierten nur flackerden Mist :D

Und wenn ich es dann geschafft habe alle 5 Reihen anzusteuern, bleibt immer noch das Problem, wann und wie er die Zeit darstellen kann. Diese würde in 2 Variablen vorliegen: _hour und _min
Ich habe das Gefühl, dass der µC einfach nicht hinterherkommt.

Danke schonmal für eure Hilfe :)
 
Hallo,

ich denke du hast mit deiner Vermutung recht, dass der Mikrocontroller einfach nicht hinter her kommt.

Du machst die LED-Ausgabe im Hauptprogramm, also innerhalb der do-loop Schleife. In der Schleife ist noch eine AD-Wandlung (single conversion), die dauert und blockiert zu lange, so dass die Routine Led_ausgabe in zu großen Zeitabständen aufgerufen wird. Je nach Konfiguration des ADC kannst du grob mit 200us rechnen. Da der ADC-Takt nicht synchron zur Festplatte läuft, "steht" die LED nicht fest an einer Stelle.

In der ISR für den Hallsensor ist eine 16/16 bit Division (Winkeldauer = ...), das dauert eventuell auch zu lange, die Rechendauer kann auch variieren, je nachdem wie die Division in Bascom realisiert wird.

Die Berechnung der "Umdrehung" innerhalb Led_ausgabe verstehe nicht ganz (ist mir jetzt schon zu spät um das genauer anzuschauen :eek:), es könnte noch damit etwas zu tun haben.

EDIT:
Ich habe mal überschlagen:
Bei 5000UPM benötigt die Platte etwa 10ms pro Umdrehung. 1° Winkelfehler wären dann 10ms/360 = 28us.

EDIT 2: :eek:
Ich habe mir dein Programm nochmal genauer angesehen und dein Text genauer durchgelesen. Eine Zeile kannst du schon einigermaßen gut darstellen.

Die LED-Ausgabe würde ich in einer TimerISR erledigen. Der zugehörige Timer (A) müsste mit Ext0 synchronisiert werden.
Im Moment misst du in der Ext0ISR wie lange 1° dauert (hier würde sich auch InputCapture anbieten, falls vorhanden). Diese Zeit würde ich für den TimerInterrupt (A) verwenden (also den Comparewert des Timer A immer anpassen). Dadurch hast du 360 "Striche" pro Umdrehung, 360 TimerInterrupts pro Umdrehung. Im TimerInterrupt (A) zählst du den Winkel mit. Mit dem Winkel und einer Dezimalzahl könntest du dann die LED-Werte einer Spalte aus einer Tabelle im Flash holen und ausgeben. Beim nächsten Grad werden dann andere Werte ausgegeben. Der Winkel-Zähler müsste mit Ext0 synchronisiert werden, nicht unbedingt der Timer A.



Dirk :ciao:
 
Moin Dirk

Die AD Wandlung ist nur temporär, später sollen die Winkel durch die Zahlen bestimmt werden.
Der Poti dient immoment dazu, zu schauen, welcher Winkel wirklich für die Zahl benötigt wird.

Der Hall Sensor steht im 120° Winkel zur ersten led Reihe.
Jede weitere reihe steht jeweils im 30° Winkel zur vorigen.
Auf der Platte befinden sich die Ziffern ebenfalls in einem Abstandswinkel von 30°

Achja: Die Festplatte dreht mit 5200 rpm aber konntest du ja nicht wissen ;)

Die Große Frage ist halt nun, wie ich das Programm auf maximale Geschwindigkeit optimiere.
Ich muss ja später nicht nur die Ziffern ansteuern, sondern zusätzlich noch Die Uhrzeit von einem DS1307 Echtzeituhr auslesen, die Variablen in einzelne Zeichen aufsplitten und diese dann anzeigen.
Dazu habe ich auch bereits ein bisschen programmiert, jedoch kackt der µC da Total ab :D



CodeBox BascomAVR
$regfile "m8adef.dat"                                       'ATmega8a auswählen
$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 3686400                                          'Prozessor auf 3,6864 MHz setzen
$baud = 9600                                                'Datenrate Setzen

'Ports Deklarieren

Config Portb = Output                                       'LED Ports auf Ausgang
Config Portd.7 = Output

'Aliase festlegen
Led1 Alias Portb.1
Led2 Alias Portb.2
Led3 Alias Portb.3
Led4 Alias Portb.4
Led5 Alias Portb.5

Config Int0 = Falling                                       ' Configuriere Int0 (PortD.2) Auf Low Level
Enable Interrupts                                           'einschalten Der Interrupts
Enable Int0                                                 'einschalten Von Interrupt Int0
On Int0 Isr_hall_sensor                                     'springe Zu Isr_von _int0

'Config Timer1 = Timer , Prescale = 8                        'Timer Konfigurieren mit tmax=142ms
Config Timer1 = Timer , Prescale = 1                        'Timer Konfigurieren mit tmax=17,7ms
Enable Timer1                                               'Timer starten
'On Timer0 Isr_timer1

'Arrays
Dim Stunde_a(3) As Byte
Dim Minute_a(3) As Byte
Dim Drehzahl_a(5) As Byte


'Temporäre Variablen (werden später durch time Funktion ersetzt)
Dim _hour As Byte
_hour = 18
Dim _min As Byte
_min = 42

'Variablen
Dim Led1out As Byte
Dim Led2out As Byte
Dim Led3out As Byte
Dim Led4out As Byte
Dim Led5out As Byte

Const Wartezeit = 200

Dim Periodendauer As Single
'Periodendauer = 1 / 460800                                  'Zeit errechnen, die nach 1 Timer vergeht
Periodendauer = 1 / 3686400
Dim Winkeldauer As Single

Dim Led1_winkel As Word
Dim Led2_winkel As Word
Dim Led3_winkel As Word
Dim Led4_winkel As Word
Dim Led5_winkel As Word

Dim Umdrehung As Single
Dim Drehzahl As Word

'Strings deklarieren
Dim Stunde_s As String * 2
Dim Minute_s As String * 2
Dim Drehzahl_s As String * 5

Portd.7 = 1                                                 'Motor einschalten


Do                                                          'Hauptprogramm starten

Stunde_s = Str(_hour)                                       'Stundenvariable in String schreiben
Minute_s = Str(_min)                                        'Minutenvariable in String schreiben
Drehzahl_s = Str(drehzahl)                                  'Drehzahlvariable in String schreiben

Str2digits Stunde_s , Stunde_a(1)                           'Strings in Array schreiben
Str2digits Minute_s , Minute_a(1)
Str2digits Drehzahl_s , Drehzahl_a(1)

Led1out = Stunde_a(3)                                       'LED Ausgang 1 mit 1. Ziffer von
Select Case Led1out                                         'LED Variable abfragen
   Case 0
      Led1_winkel = 30                                      'Winkel für Ziffer 0
   Case 1
      Led1_winkel = 30
   Case 2
      Led1_winkel = 30
   Case 3
      Led1_winkel = 220
   Case 4
      Led1_winkel = 30
   Case 5
      Led1_winkel = 30
   Case 6
      Led1_winkel = 30
   Case 7
      Led1_winkel = 30
   Case 8
      Led1_winkel = 30
   Case 9
      Led1_winkel = 30
   Case 10
      Led1_winkel = 30
   Case 11
      Led1_winkel = 30
End Select

Gosub Led_ausgabe                                           'Zur LED ansteuerung springen

Loop                                                        'Hauptprogramm Ende

Isr_hall_sensor:
'Toggle Led1                                                 'Wenn Hall Sensor Signal bekommt, wird hierher gesprungen
'Umdrehung = Timer1 * Periodendauer
'Winkeldauer = Umdrehung / 360
Winkeldauer = Timer1 / 360                                  'Timmer Pro Winkel errechnen
Timer1 = 0                                                  'Timer zurücksetzen
Return

Led_ausgabe:
'LED1
Led1_winkel = Winkeldauer * Led1_winkel                     'Timer Wert mit Winkel und Zeit errechnen
If Timer1 >= Led1_winkel Then                               'Wenn der Timer die richtige Zeit erreicht hat
   Led1 = 1                                                 'LED1 einschalten
   Waitus Wartezeit                                         '10 µs warten
   Led1 = 0                                                 'LED1 wieder ausschalten
End If                                                      'If Abfrage beenden

'LED2
Led2_winkel = Winkeldauer * Led2_winkel
If Timer1 >= Led2_winkel Then
   Led2 = 1
   Waitus 200
   Led2 = 0
End If

'LED3
Led3_winkel = Winkeldauer * Led3_winkel
If Timer1 >= Led3_winkel Then
   Led3 = 1
   Waitus 200
   Led3 = 0
End If

'LED4
Led4_winkel = Winkeldauer * Led4_winkel
If Timer1 >= Led4_winkel Then
   Led4 = 1
   Waitus 200
   Led4 = 0
End If

'LED5
Led5_winkel = Winkeldauer * Led5_winkel
If Timer1 >= Led5_winkel Then
   Led5 = 1
   Waitus 200
   Led5 = 0
End If

Return
 
Hi,

Der Hall Sensor steht im 120° Winkel zur ersten led Reihe.
Jede weitere reihe steht jeweils im 30° Winkel zur vorigen.
Auf der Platte befinden sich die Ziffern ebenfalls in einem Abstandswinkel von 30°

Achja: Die Festplatte dreht mit 5200 rpm aber konntest du ja nicht wissen ;)

Die Große Frage ist halt nun, wie ich das Programm auf maximale Geschwindigkeit optimiere.

in dem du deine ja vorhandenen Daten zusammenrechnest damit du im Programm möglichst nur noch mit Konstanten arbeiten kannst und den armen Atmel nicht noch mit Divisionen/Multiplikationen ärgerst :p

Die Drehzahl gibt dir doch die Zeit für das Überstreichen eines bestimmten Winkels (bei dir 30°).
Dann mußt du doch nur noch nen Taschenrechner anwerfen und die entsprechenden Mikrosekunden ausrechnen.
Damit kann man das Programm schon mal ne Menge beschleunigen.
Dann alles unnütze aus der ISR rauswerfen und die LED-Steuerung dafür in die ISR reinbauen.
Die ISR würde ich dann alle 30° aufrufen lassen. In der ISR werden dann nach einem Steuerbyte gemäß die entsprechenden LEDs an/ausgeschaltet.

Versuch möglichst alles auf Byte-Ebene runterzubrechen. Möglichst wenig Word-Variablen in zeitkritischen Bereichen.
Single,Double,Float,...(also Kommazahlen) solltest du dir komplett ersparen.

pro Umdrehung 11538µs
das macht für 30° also /12 ... 961µs pro 30°-Segment.
Da man selbst die 120° des Hallsensors durch 30° teilen kann sollte das alles kein Thema sein.
Die ISR sollte also möglichst genau alle 961µs aufgerufen werden.
Der Hallsensor ist also sozusagen 4 Segmente (oder 4 Positionen) gegen die erste LED-Reihe verschoben.
Da der HD-Motor ja auch per Quarz läuft (so wie der Atmel), sollte das auch alles halbwegs zusammen passen.
Du kannst zB mit Increment (+1) auch durch den Zahlenbereich eines Bytes durchrotieren. Das geht dann so ... 254, 255, 0, 1, 2, 3, ... . Nutze den Überlauf intelligent aus um dir Rechnereien oder zusätzliche Bedingungen im Programm zu sparen. Der INC-Befehl benötigt lediglich einen Prozessortakt.
Schalte die nicht mehr benötigten LEDs im neuen Segment erst ab. Danach die benötigten LEDs anschalten. Das erspart dir Geisterbilder (siehe auch 7Segment-Multiplexing)

Gruß
Dino
 
Dazu hatte ich doch bereits in Deinem ersten Anlauf meine Meinung geschrieben. Da diese Ausgabe ja ja eigentlich der Kern Eures Projektes ist, hätte ich mich als erstes damit beschäftigt - stabil an jeder Stelle (LED-Position) ein beliebiges Zeichen aus dem Vorrat des Rades anzeigen zu lassen. Weitmöglichst durch die Controller-Hardware selbst.

Wie damals schon gesagt:
Ein geeigneter Timer ist im frequenzkorrektem FastPWM so einzustellen, daß er immer genau dann überlauft, wenn sich ein Zeichen genau über einer LED befindet. Mit dem Hall-Sensor am Input-Capture und den gezählten Überlaufen sollte sich dann eigentlich die Synchronisation des PWM bewerkstelligen lassen.
Bei jedem Überlauf hat sich das Rad also eine Position weitergedreht, für jeden dieser Positionen wird ein Byte im Speicher festgelegt, Display-RAM sozusagen. Als Array. Die gezählten Überläufe indizieren dann das entsprechende Byte im Array, welches die eine Seite der LEDs schaltet. Die andere Seite aller LEDs zusammen wird durch den PWM-Ausgang des Timers gesteuert. Damit wird dann die Leuchtdauer der LEDs festgelegt.
Werden die LEDs also durch das PWM beim Überlauf ein-, und beim compare-match ausgeschaltet, sollte man statt der Überläufe da oben die compare-matches im Interrupt von 1 bis 12 durchzählen, und den entsprechenden Eintrag aus dem Display-RAM-Array auf den Port mit den LEDs legen. In dem Moment sind die LEDs ja wegen dem PWM aus, und werden erst bei der nächsten Stelle (Überlauf) kurz (bis zum compare-match) aufblitzen. Dann schlägt der nächste Compare-IRQ zu, der die LEDs für die nächste Radposition vorbereitet, das eigentliche Blitzen macht die Hardware mit dem PWM vollständig selbst im Hintergrund - lediglich einmal pro Umdrehung wird dann noch mittels Input-Capture eine eventuelle (wahrscheinliche) Winkelabweichung korrigiert. (Statt des IC-Events kann man natürlich auch'n externen IRQ triggern lassen, und brutal den Timer und den Positionszähler festsetzen lassen...)

Damit sollte dann eigentlich der Inhalt des 12-Byte-Arrays statisch auf dem "Display" erscheinen.

Wenn das geht, brauchst Du 'ne Methode, die aus einer darzustellenden Zeichenkette die Werte berechnet, die im Array landen. das ist für die Darstellung selbst unkritisch, wenn Du im Sekundentakt was neues darstellen willst, darf das aber trotzdem nicht beliebig lange dauern.

Der nächste Schritt ist dann, die Uhr im AVR umzusetzen, und hier hast Du bereits den Timer1 für Display und PWM verbraucht. Aber eigentlich brauchst Du dafür keinen Timer - der DS1307 gibt ja selbst ein sauberes Sekundensignal aus. Ob IRQ-getriggert oder gepollt (reicht wahrscheinlich) kannst Du darauf reagieren und die Zeit zählen. Die neue Zeit dann an die Darstellungs-Methode übergeben, die Das Display-RAM füllt.

Idee soweit verstanden?

Edit:
...das macht für 30° also /12 ... 961µs pro 30°-Segment...
Ich bin bei dem Quarz auch auf ein Compare-Wert von 3544 gekommen;) Allerdings trotzdem zwölf mal 104ns zu langsam.
 
Hi,

Wie damals schon gesagt:
Ein geeigneter Timer ist im frequenzkorrektem FastPWM so einzustellen, daß er immer genau dann überlauft, wenn sich ein Zeichen genau über einer LED befindet. Mit dem Hall-Sensor am Input-Capture und den gezählten Überlaufen sollte sich dann eigentlich die Synchronisation des PWM bewerkstelligen lassen.

also sozusagen durch einen "LED-Blitz" das Zeichen für das Auge statisch werden lassen. Wie bei einem Stroboskop das man damals beim Auto für die Einstellung des Zündzeitpunktes verwendet hat (wer das noch kennt).

Gruß
Dino
 
Hallo zusammen,

ich kann zwar hier momentan gar nicht helfen, aber ich möchte gerne anmerken, dass mir dieses Projekt außerordentlich gut gefällt.
Aus meiner Sicht eine kleine Herausforderung!

Besten Gruß
Uni
 
Hi,

ich kann zwar hier momentan gar nicht helfen, aber ich möchte gerne anmerken, dass mir dieses Projekt außerordentlich gut gefällt.
Aus meiner Sicht eine kleine Herausforderung!

die Schwierigkeit ist nicht unbedingt die Programmierung oder Programmiersprache. Die Schwierigkeit der Aufgabe liegt hier darin, die Teile herauszufinden die zusammen abgearbeitet werden müssen, die Teile in die richtige Reihenfolge zu bekommen und die dann notfalls auch noch laufzeitmäßig zu optimieren. Wenn man vorher nie etwas mit Timingverhalten zu tun hatte, dann kann man schon ganz gut dran rumknabbern. Es ist eben etwas anderes einfach ein Programm für einen PC zu schreiben. Ein Anwender wartet notfalls auch mal 0,5sec länger auf eine Ausgabe. Eine drehende Scheibe macht das nicht :p Man lernt an dieser Aufgabe auch sehr gut wie man sich Arbeit von der Hardware abnehmen lassen kann (Timer, Interrupts, ...)

Gruß
Dino
 
...die Schwierigkeit ist nicht unbedingt die Programmierung oder Programmiersprache. Die Schwierigkeit der Aufgabe liegt hier darin, die Teile herauszufinden die zusammen abgearbeitet werden müssen, die Teile in die richtige Reihenfolge zu bekommen und die dann notfalls auch noch laufzeitmäßig zu optimieren...
eben.
Eigentlich sogar noch einen Schritt tiefer - wie kann ich die Prozessorhardware ausnutzen, um gar nicht selbst was programmieren zu müssen, sondern das die Hardware selbst machen zu lassen. (Ok, die Konfiguration der Hardware ist natürlich auch Programmierung, aber die zeitkritischen Sachen lassen sich damit entschärfen.)

Die Schwierigkeit hier ist die eher spezielle Form des Multiplexing, die eben nicht wie bei Siebensegmentanzeigen ist. Dort muß ja lediglich das darzustellende LED-Muster aus 'ner ... Character-Tabelle auszulesen, und auf die anzuzeigende Stelle zu legen.
Hier hast Du jetzt kein Muster einzelner LEDs (es wird ja mit ener LED das genze Zeichen gezeigt), allerdings rotiert die Scheibe.
Wenn für die "Eins" an der ersten Stelle die erste LED im ersten Rotations (Überlauf)-Slot blitzen muß, wäre das bei der zweiten Stelle der 2te Slot (also im 2ten Byte im Array)

Die Methode müßte also etwa so arbeiten:
Das was an der n-ten Stelle auf dem Display dargestellt werden soll, setzt das n-te Bit in einem der Bytes im Array. Welches Byte? Einerseits hast Du die Nummer des Charcters (quasi den ASCII, nur eben auf Deiner Scheibe), andererseits die anzuzeigende Stelle. Beide wären zu addieren. Davon Modulo12 wäre das Byte im Display-RAM, in dem das Bit gesetzt werden muß, wobei man statt Modulo mit 'ner bedingten Subtraktion auskommt.
Es ist also aus dem darzustellenden Zeichen die Nummer auf dem Rad zu bestimmen (das zu setzende Bit 0..6?), dann wird auf die Position (nullte bis nte Stelle) die Bitnummer addiert. Ist das Ergebnis größer 11, werden 11 abgezogen (mit 16 Zeichen würde man einfach das High-Nibble wegmaskieren). Diese Zahl addiert auf die Anfangsadresse des Disply-RAMs ergibt das Byte, in dem das zuerst festgelegte Bit gesetzt werden muß. In allen anderen Bytes muß es gelöscht werden - am einfachsten indem man immer alle Stellen komplett ausgibt, und vorher alle Bytes null setzt.

Läßt sich so auch in BASCOM umsetzen (zumindest mit eingebettetem Assembler), aber der Algorythmus erfordert schon Verständnis der Arbeitsweise des Controllers in seiner Hardware...
 
Hi,

Modulo 11 , Modulo 12, Display-RAM, Subtraktion, ... :rolleyes:

Ich hätte da folgende Vorgehensweise. ...
Für jede Stelle ein Byte mit dem gewünschten Wert ( ja ... ist quasi nen Display-RAM :p )

( ääähhhh ... Machen wir im Moment nicht grade seine Hausaufgaben ? War das nicht ne Art "Schul-/Semester-/...-arbeit"? ) :eek:

Positionen auf der Scheibe ... ( Index bei der 0 )

I
0 1 2 3 4 5 6 7 8 9 : -
H - - 1 2 3 4 5 .... Position


Wenn also der Index-Puls am (H)allsensor ausgelöst wird (Flanken-Interrupt), dann wäre an der LED-Position 1 die Ziffer 3. Ich würde dann in einer INT-ISR einen "Main"-Zeichenzähler beim Indexpuls auf 3 setzen.

Innerhalb der Timer-ISR wird dann ...
Der Wert des Main-ZZ wird dann am Anfang der Timer-ISR in einen Hilfs-ZZ geladen.
Wert für die erste Zeichenposition mit dem Hilfs-ZZ (im Moment =3) vergleichen . Wenn gleich, dann LED an sonst aus.
Hilfs-ZZ plus eins da ja an der 2.Zeichenposition ein anderes Zeichen steht.
Wert für die zweite Zeichenposition mit dem Hilfs-ZZ (jetzt =4) vergleichen. Wenn gleich, dann LED an, sonst aus.
Hilfs-ZZ ... usw.
...
Wert für die fünfte Zeichenposition mit dem Hilfs-ZZ (jetzt =7) vergleichen. Wenn gleich, dann LED an, sonst aus.
Ein paar Mikrosekunden verweilen damit man die LEDs überhaupt aufblitzen sieht.
Alle Positionen abgearbeitet. Vorbereitung für den nächsten ISR-Aufruf machen....
Main-ZZ plus 1 da ja beim nächsten ISR-Aufruf alles ein Zeichen weitergerückt ist.
Test ob Main-ZZ >11 ist (also über dem Minuszeichen) dann Main-ZZ auf 0 setzen.
Zum Ende der Timer-ISR alle LEDs wieder ausschalten.

So sollte das eigentlich grob gesagt ablaufen. Damit ist in den ISRs keine zeitfressende Berechnung drin. Bis auf die kleine Verzögerungszeit in der Timer-ISR damit man die LEDs überhaupt wahrnehmen kann. Diese Verzögerungszeit sollte ein mehrfaches größer sein als die Verarbeitungszeit der 5 Positionsvergleiche aber nur einen Bruchteil der Zeit für den Lauf über das Positionssegment haben. Zu lange dann verschwimmen die Zeichen und zu kurz dann sieht man die LEDs nicht mehr.

Wenn man die Hardware (also Position des Hallsensors und der LEDs) so gebaut hat das alles im richtigen Winkel zueinander steht, dann benötigt man nicht mal ne zusätzliche Zeitanpassung vom Indexpuls zum Anzeige der ersten Position. Die LEDs sollten dann genau unter der Ziffer stehen. Wenn das nicht der Fall ist, dann muß man da noch ein wenig am Timing innerhalb der INT-ISR drehen. Evtl noch ne kleine Verzögerung mit reinbauen um alle Positionen einpaar Grad nach hinten zu verlagern.

In der Hauptroutine liegen dann eigentlich nur noch die Füllung der Wertvariablen für die 5 Stellen, die RTC-Klamotten und etwas Kleinkram. Ich würde mir die Uhr da lieber selber programmieren damit der Bascom-Uhreninterrupt die Anzeige nicht im Zeitverhalten durcheinander wirft.

EDIT: OK ... du mußt beim Hilfs-ZZ auch noch nen Überlauf abfangen ... :p

INT-ISR: Index ... MZZ=3
TI-ISR: HZZ=MZZ(3) , P1=?=HZZ(3) , HZZ+1 , P2=?=HZZ(4) , ... , P5=?=HZZ(7) , MZZ+1
TI-ISR: HZZ=MZZ(4) , P1=?=HZZ(5) , HZZ+1 , P2=?=HZZ(6) , ... , P5=?=HZZ(8) , MZZ+1
TI-ISR: HZZ=MZZ(5) , P1=?=HZZ(6) , HZZ+1 , P2=?=HZZ(7) , ... , P5=?=HZZ(9) , MZZ+1
...
TI-ISR: HZZ=MZZ(10) , P1=?=HZZ(10) , HZZ+1 , P2=?=HZZ(11) , ... , P5=?=HZZ(7) , MZZ+1
TI-ISR: HZZ=MZZ(11) , P1=?=HZZ(11) , HZZ+1 , P2=?=HZZ(0) , ... , P5=?=HZZ(3) , MZZ+1
TI-ISR: HZZ=MZZ(0) , P1=?=HZZ(0) , HZZ+1 , P2=?=HZZ(1) , ... , P5=?=HZZ(4) , MZZ+1
...
TI-ISR: HZZ=MZZ(2) , P1=?=HZZ(2) , HZZ+1 , P2=?=HZZ(3) , ... , P5=?=HZZ(6) , MZZ+1
INT-ISR: Index ... MZZ=3
TI-ISR: HZZ=MZZ(3) , P1=?=HZZ(3) , HZZ+1 , P2=?=HZZ(4) , ... , P5=?=HZZ(7) , MZZ+1
...

Die saubere Position der Zeichen über den LEDs könnte man damit erzwingen, wenn man beim Index-Interrupt den Zähler des Timers auf einen bestimmten Anfangswert setzt. Damit hat man dann die Möglichkeit die Position um +/-15° zu verschieben.

Gruß
Dino
 
Naja, eben nicht wirklich Modulo rechnen - nur prüfen ob das Ergebnis größer 11 ist, und nur dann einmal Subtrahieren.
Mein Vorschlag war, nur das allernötigste in den Interrupt zu packen.
Positionsindex der 12 Positionen durchzählen (Inkrement und Überlauf 11->12=0 abfangen), Byte von da aus dem Display-RAM (SRAM) laden, und auf den PORT mit den LEDs schreiben. Fertig.
natürlich zählt man dann nicht von 0..11 und addiert den Anfangsindex des Display-RAM, sondern hat da schon den Offset drin.

Die Rechnerei , was ins Display-RAM geschrieben wird hat dann ausserhalb der Darstellungs-Interrupts Zeit... aber wenn man "in Tabellen denkt" auch nicht wirklich komplex...

Und NEIN, wir machen nicht seine Hausaufgabe - das setzt er weder auf Deinem, noch auf meinem Weg so um...
(Ich werde für meinen nämlich keinen Code schreiben...)
 
sorry, dass ich mich jezt erst melde :)

zuerst einmal seit ihr hier ne super Hilfe für mich.
Lotadac hat recht, ihr macht nicht meine Hausaufgaben. Ihr gebt mir lediglich super Denkanregungen.
ich möchte auch gar keinen Code von euch, da ich mir das Programm selbst erarbeiten möchte.

jezt zu deinem Beitrag ersten Lotadac:
Ich musste es mir echt ca 5 mal durchlesen, damit ich es so langsam verstanden hab.
Was mir klar ist, ist, dass ich Pro weitere Ziffer auf dem Rad einen Interrupt auslöse also insgesamt 12 Interrupts. Somit wird alle 961 µs ein Interrupt ausgelöst. Dabei wird eine Variable mit incr hochgezählt.
Das Interrupt löse ich via OCR1A bei 3544 aus (961µs)

Jezt jedoch, was ich nicht verstanden habe: Was soll in das Display-RAM array?
und wie soll das jetzt mit der PWM ansteuerung der LED funktionieren funktionieren :)

Grüße
Kampfkartoffel

Edit: ich habe jetzt statt eines 3,6864 Mhz Quar6 einen 12Mhz Quarz eingelötet.
Jetzt funktioniert mein code aus meinem ersten post fasst perfekt. Also die ansteuerung einer einzelnen led. Ich hoffe mit einem 12Mhz quarz wird die restliche berechnug weniger Zeitkritisch :)
 
...jezt zu deinem Beitrag ersten Lotadac:
...
Was mir klar ist, ist, dass ich Pro weitere Ziffer auf dem Rad einen Interrupt auslöse also insgesamt 12 Interrupts. Somit wird alle 961 µs ein Interrupt ausgelöst. Dabei wird eine Variable mit incr hochgezählt.
Das Interrupt löse ich via OCR1A bei 3544 aus (961µs)

Jezt jedoch, was ich nicht verstanden habe: Was soll in das Display-RAM array?...
Dann nochmal zur Grundidee. Letztlich nichts anderes als Multiplexing bei mehreren Siebensegmentanzeigen. Dort reserviert man irgendwo Speicher für jede Ziffer/Stelle, in den das gerade darzustellende LED-Muster dieser Stelle geschrieben wird. Mittels Timerinterrupt werden dann alle Stellen abgeschaltet, das LED-Muster einer Stelle auf eine Seite der LEDs gelegt, und dann die andere Seite (Common) angeschaltet. Im nächsten Timerinterrupt dasselbe mit der nächsten Stelle. So werden alle Stellen immer nacheinander durchgeleiert. Wenn das so mit den Interrupts und dem Speicher umgesetzt ist, läuft das unabhängig von Deinem Hauptprogramm mehr oder weniger im Hintergrund. Der Interrupt schlägt halt nur regelmässig dazwischen, um auf die nächste Stelle umzuschalten. Es wird immer der Inhalt des reservierten Speichers dargestellt. Grafikspeicher sozusagen. Display-RAM. Oder wie auch immer Du das nennen willst.
Wenn Dein Hauptprogramm irgendwas anderes ausgeben will, schreibt es einfach das entsprechende Muster in den Display-RAM, die Ausgabeinterrupts verwirklichen das dann.

Bei Deinem Projekt kann man das ähnlich machen. Allerdings hast Du keine Muster die Ziffer für Ziffer ausgegeben werden, stattdessen 'ne Ganze Ziffer in einem Bit, auf der anderen Seite ist 'ne "7" auf der ersten Stelle 'n anderes Muster als auf der letzten.
...und wie soll das jetzt mit der PWM ansteuerung der LED funktionieren funktionieren...
Das zweite Problem ist, daß die Scheibe sich dreht, und nicht diskret von einer Position auf die nächste wechselt - die LEDs dürfen also nur möglichst kurz aufblitzen (natürlich hinreichend lang, um was zu erkennen).
Mal angenommen das korrekte Muster ist gelöst, dann brauchst Du immer noch zwei korrekte Zeitpunkte - den zum Einschalten und den zum Abschalten. Einen von beiden liefert Dir der Interrupt des Timers (mit dem Hallsensor synchronisiert), der andere ist ja eigentlich nur um eine feste Zeit "verschoben". Wenn man da jetzt wartet, bremst man das anze unnötig aus, 'n (ggf zweiten) Timer drauf zu verbraten wäre unnötig aufwändig.
Mein Vorschlag war, zB die Anoden der LEDs über einen Port anzusteuern, und da das jeweilige Muster (aus dem Display-Speicher) draufzulegen, und die Kathoden aller Dioden gemeinsam (über einen Transistor etc). Timergesteuert durchschalten zu lassen. Mit PWM. Wenn OCR1A bereits die Überlauffrequenz des Timers festlegt, bleibt dafür OCR1B.
Läuf der Timer über, schaltet der OC1B-Pin auf Hi, der daran hängende Transistor durch, welcher somit die Kathoden aller LEDs auf Gnd legt. LEDs, deren Anode von den Controller-Ports Hi liegen, leuchten. Erreicht der Timer den OCR1B-Wert, kippt OC1B auf Lo, damit sind LEDs aus. An diesen Compare-Match wird der Interrupt genagelt, in dem der Positionszähler die 12 Zustände durchzählt, und den Eintrag für den nächsten Überlauf aus dem Speicher (an der Position des Zählers) auf die Anoden lädt.
Die Kathoden zappeln dann mittels Hardware-PWM vollig Software-unabhängig (abgesehen von der Synchronisation mit dem Sensor) selbständig im Hintergrund. Das Umschalten auf der Anoden auf die nächste Rotationsposition erfolgt sehr schnell im Interrupt des Output Compare Matches (1B), ist selbst bei nur kurzem geforderten aufblitzen auch nicht so zeitkritisch. Hat ja mehr 900µs Zeit.
Der Rest steht dann dem Hauptprogramm zur Verfügung.

Was muß nun ins Display RAM geschrieben werden?
Jeder Eintrag steht für eine Rotationsposition. Jede LED hat ein festes Bit (eben die des Port-Bits) in allen Einträgen.
Soll also ein bestimmtes Zeichen durch die erste LED dargestellt werden, ist das erste Bit in einem der Einträge zu setzen (und in allen anderen zu löschen). Bei der 2ten LED das 2te Bit usw. Und wie kommt man auf den Eintrag, den Index in der Speichertabelle? Erstens wird das durch die Position des Zeichens auf dem Rad festgelegt (sinnig angeordnet wäre eins die eins, zwei die zwei usw.) dazu ist dann die Stelle an der es angezeigt werden soll zu addieren ('ne 5 an der dritten Stelle war 2 Rotationsschritte vorher an der ersten gewesen (Also Zeichen Numer 4 an Position 2 wäre Bit 2 in Tabelleneintrag 6, klar (Wenn ich mit der "0" bei "LED0" beginne)). Das Ganze wiederholt sich alle 12 Schritte. Eigentlich müßte man das Ergebnis also Modulo12 rechnen. Bei 16 Positionen wäre das ganz einfach - man müßte lediglich das Low-Nibble der Zahl verwenden. Aber Du hast 12.
Beginnt man den Index mit 0 wären wegen der 12 Positionen (30°) auch nur 12 LEDs theotetisches Maximum. Also liegt die Summe (LED0..LED11, Position0..Position11) immer zwischen 0 und 22, folglich kann man auch 12 subtrahieren wenn die Summe größer als 11 war.
Inwiefern sich das nur mit Bascom effizient umsetzen läßt, weiß ich nicht - ich(!) würde solche Index-Rechnereien und Bitschubsereien in Assembler einbetten (wenn ich überhaupt unter Bascom programmieren würde).
 
Soo Leute

Vielen dank noch einmal für eure Hilfe. Hat mir und meinem Projektpartner super geholfen, auch wenn ich das Programm letztlich etwas anders realisiert habe.

Das mit den 12 Interrupts und dem Display RAM Arrays waren letztlich die Tipps, die zur Lösung verhalfen.
Für alle die es interessiert schreibe ich hier nochmal den 350 Zeiligen Code rein :)

Grüße
Kampfkartoffel :)



CodeBox BascomAVR
$regfile "m8adef.dat"                                       'ATmega8a auswählen
$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 12000000                                         'Prozessor auf 12Mhz setzten
$baud = 1200                                                'Datenrate Setzen

'Ports Deklarieren
Config Portb = Output                                       'LED Ports auf Ausgang
Config Portd.7 = Output                                     'Motor Port
Config Portc.0 = Input                                      'Taster
Config Portc.1 = Input                                      'taster

'Pullup für Taster aktivieren
Portc.0 = 1
Portc.1 = 1

'Aliase festlegen
Led0 Alias Portb.0
Led1 Alias Portb.1
Led2 Alias Portb.2
Led3 Alias Portb.3
Led4 Alias Portb.4
Led5 Alias Portb.5

Motor Alias Portd.7

Taster1 Alias Pinc.0
Taster2 Alias Pinc.1

'I²C Bus konfigurieren
Config Sda = Portc.4
Config Scl = Portc.5
Const Ds1307w = &HD0                                        ' Addresse der Ds1307 Uhr
Const Ds1307r = &HD1

'Interne Time/Date Routinen für Bascom konfigurieren
Config Clock = User
Config Date = Dmy , Separator = .

' Stellen der Uhr, muss nur einmal ausgeführt werden
'Time$ = "11:55:00"
'Date$ = "24.04.15"
Gosub Square_an                                             'Rechtecksignal des DS1307 einschalten

'Externer Interrupts aktivieren
Config Int0 = Falling                                       ' Configuriere Int0 (PortD.2) Auf Low Level
Enable Int0                                                 'einschalten Von Interrupt Int0
On Int0 Isr_hall_sensor                                     'Wenn Int0=0 dann Springe zu Interrupt

Config Int1 = Rising                                        ' Configuriere Int0 (PortD.2) Auf High Level
Enable Int1                                                 'einschalten Von Interrupt Int1
On Int1 Isr_squarein                                        'Wenn in1=1 dann Springe zu interrupt

'Timer1 definieren und einschalten
Ocr1a = 11532                                               '961us 11532
Config Timer1 = Timer , Prescale = 1 , Clear Timer = 1 , Compare A = Disconnect       'Timer Konfigurieren mit deaktivierten compare pin
Enable Timer1                                               'Timer starten
Enable Oc1a                                                 'Compare einschalten
On Oc1a Isr_timer1_compare                                  'Wenn Compare wert erreicht, in Interrupt springen

'Timer2 definieren und einschalten
Ocr2 = 47                                                   '47  für ca 250us
Config Timer2 = Timer , Prescale = 64 , Clear Timer = 1     'Timer2 Konfigurieren
Enable Oc2
On Oc2 Isr_timer2

'Arrays
Dim Stunde_a(3) As Byte
Dim Minute_a(3) As Byte
Dim Tag_a(3) As Byte
Dim Monat_a(3) As Byte
Dim Jahr_a(3) As Byte
Dim Drehzahl_a(5) As Byte

'Display Ram Arrays
Dim Led1_a(12) As Byte
Dim Led2_a(12) As Byte
Dim Led3_a(12) As Byte
Dim Led4_a(12) As Byte
Dim Led5_a(12) As Byte
'Display RAM mit vorher errechneten Werten füllen
Led1_a(1) = 3 : Led1_a(2) = 2 : Led1_a(3) = 1 : Led1_a(4) = 12 : Led1_a(5) = 11 : Led1_a(6) = 10 : Led1_a(7) = 9 : Led1_a(8) = 8 : Led1_a(9) = 7 : Led1_a(10) = 4 : Led1_a(11) = 5 : Led1_a(12) = 6
Led2_a(1) = 4 : Led2_a(2) = 3 : Led2_a(3) = 2 : Led2_a(4) = 1 : Led2_a(5) = 12 : Led2_a(6) = 11 : Led2_a(7) = 10 : Led2_a(8) = 9 : Led2_a(9) = 8 : Led2_a(10) = 5 : Led2_a(11) = 6 : Led2_a(12) = 7
Led3_a(1) = 5 : Led3_a(2) = 4 : Led3_a(3) = 3 : Led3_a(4) = 2 : Led3_a(5) = 1 : Led3_a(6) = 12 : Led3_a(7) = 11 : Led3_a(8) = 10 : Led3_a(9) = 9 : Led3_a(10) = 6 : Led3_a(11) = 7 : Led3_a(12) = 8
Led4_a(1) = 6 : Led4_a(2) = 5 : Led4_a(3) = 4 : Led4_a(4) = 3 : Led4_a(5) = 2 : Led4_a(6) = 1 : Led4_a(7) = 12 : Led4_a(8) = 11 : Led4_a(9) = 10 : Led4_a(10) = 7 : Led4_a(11) = 8 : Led4_a(12) = 9
Led5_a(1) = 7 : Led5_a(2) = 6 : Led5_a(3) = 5 : Led5_a(4) = 4 : Led5_a(5) = 3 : Led5_a(6) = 2 : Led5_a(7) = 1 : Led5_a(8) = 12 : Led5_a(9) = 11 : Led5_a(10) = 8 : Led5_a(11) = 9 : Led5_a(12) = 10

'Variablen
Dim Led1out As Byte
Dim Led2out As Byte
Dim Led3out As Byte
Dim Led4out As Byte
Dim Led5out As Byte

Dim L1 As Bit
Dim L2 As Bit
Dim L3 As Bit
Dim L4 As Bit
Dim L5 As Bit

Dim Weekday As Byte
Dim _min_old As Byte
Dim _mode As Byte
_mode = 1                                                   'Ausgabe bei Uhrzeit starten
Dim Sekundenpunkt As Bit
Sekundenpunkt = 1                                           'Sekundenpunkt einschalten
Dim Umschaltung As Bit
Dim Refresh As Byte
Umschaltung = 1                                             'Beim ersten durchlauf soll die Anzeige aktualisiert werden

Dim Zeichennr As Byte

'Strings deklarieren
Dim Stunde_s As String * 2
Dim Minute_s As String * 2
Dim Tag_s As String * 2
Dim Monat_s As String * 2
Dim Jahr_s As String * 2
Dim Drehzahl_s As String * 5


Enable Interrupts                                           'einschalten Der Interrupts

Motor = 1                                                   'Motor einschalten

Gosub Getdatetime                                           'Uhrzeit aktualisieren


Do                                                          'Hauptprogramm starten

If _min_old <> _min Or Umschaltung = 1 Then                 'Abfrage, ob sich der Modus oder die Uhrzeit geändert hat
   Umschaltung = 0                                          'Nach Umschaltung kann das Bit neu gesetzt werden
   _min_old = _min                                          'Alte Minute= neue minute
   Select Case _mode                                        'Frage nach dem Modus
      Case 1
            Gosub Uhr                                       'Hier wird die Uhrzeit dargestellt
      Case 2
            Gosub Datum                                     'Hier das Datum
      Case 3
            Gosub Jahr                                      'Hier das aktuelle Jahr
      Case 4
            Gosub Drehzahl                                  'und hier die Drehzahl des Motors
   End Select
End If

Debounce Taster1 , 0 , Modeswitch , Sub                     'Taster entprellen für Moduswechsel
Debounce Taster2 , 0 , Uhr_stellen_uart , Sub               'Taster entprellen für Uhr stellen via Uart

Gosub Led_ausgabe                                           'Zu sub Springen

Loop                                                        'Hauptprogramm Ende

'Unterprogramme

Isr_hall_sensor:
Zeichennr = 1                                               'Zeichennummer zurücksetzen
Timer1 = 1023                                               '1023 Timer zurücksetzen Feintuning durch Poti
'Ausgabe Bits wieder auf 1 Setzen, damit ausgabe in der nächsten Runde weitergeht
L1 = 1 : L2 = 1 : L3 = 1 : L4 = 1 : L5 = 1
Return

Isr_squarein:
If _mode = 1 Then Toggle Sekundenpunkt                      'Wenn Modus=Uhr dann soll der doppelpunkt im Sekundentakt blinken
Incr Refresh                                                'variable hochzählen
If Refresh = 10 Then
   Gosub Getdatetime                                        'Wenn Variable 10 ist soll zeit neu gelesen werden -> Alle 10 Sekunden wird die Zeit eingelesen
   Refresh = 0
End If
Return

Isr_timer1_compare:
Incr Zeichennr                                              'Position des Rades
Return

Isr_timer2:
Led1 = 0 : Led2 = 0 : Led3 = 0 : Led4 = 0 : Led5 = 0        'Alle LEDs ausschalten
Disable Timer2                                              'Timer wieder auschalten
Return

Modeswitch:
Incr _mode
Umschaltung = 1                                             'Damit Neue Werte eingelesen werden
If _mode = 5 Then _mode = 1                                 'Wenn Modus=5 soll wieder auf Uhr gesprungen werden
Return

Square_an:
I2cstart
I2cwbyte Ds1307w
I2cwbyte 7
I2cwbyte &B00010000                                         'RechteckSignal wird hier aktiviert
I2cstop
Return

Uhr:
Stunde_s = Str(_hour)                                       'Stunden variable in String umwandeln
Str2digits Stunde_s , Stunde_a(1)                           'Einzelne Zeichen des Strings in ein Array schreiben
Minute_s = Str(_min)                                        'dasselbe für Minute
Str2digits Minute_s , Minute_a(1)
If _hour < 10 Then Stunde_a(3) = 10                         'Wenn Stunde unter 10 ist soll an erster Stelle eine 0 (10 wurde als 0 festgelegt) angezeigt werden
If _min < 10 Then Minute_a(3) = 10                          'dasselbe für Minute
If Stunde_a(2) = 0 Then Stunde_a(2) = 10                    'wenn   die 2. Ziffer der Stunde =0 ist soll diese in eine 10 gewandelt werden, damit eine 0 dargestellt wird
If Minute_a(2) = 0 Then Minute_a(2) = 10                    'dasselbe für Minute
'Zuweisung für die LED ansteuerung
Led1out = Stunde_a(3)
Led2out = Stunde_a(2)
Led3out = 11                                                'Doppelpunkt
Led4out = Minute_a(3)
Led5out = Minute_a(2)
Return

Datum:
Tag_s = Str(_day)
Str2digits Tag_s , Tag_a(1)
Monat_s = Str(_month)
Str2digits Monat_s , Monat_a(1)
If _day < 10 Then Tag_a(3) = 10
If _month < 10 Then Monat_a(3) = 10
If Tag_a(2) = 0 Then Tag_a(2) = 10
If Monat_a(2) = 0 Then Tag_a(2) = 10
Sekundenpunkt = 1
Led1out = Tag_a(3)
Led2out = Tag_a(2)
Led3out = 12                                                'Punkt
Led4out = Monat_a(3)
Led5out = Monat_a(2)
Return

Jahr:
Jahr_s = Str(_year)
Str2digits Jahr_s , Jahr_a(1)
If Jahr_a(2) = 0 Then Jahr_a(2) = 10
Sekundenpunkt = 0
'Da der DS1307 nur bis zum Jahr 2099 funktioniert, müssen die ersten Ziffern nicht bestimmt werden
Led1out = 2
Led2out = 10
Led4out = Jahr_a(3)
Led5out = Jahr_a(2)
Return

Drehzahl:
'Die Drezahl der Festplatte ist konstant, weshalb hier keine unnötige Rechenleistung verschwendet werden muss um die Drehzahl darzustellen.
'Wenn man die Drezahl errechnen möchte wäre dies recht kompliziert und zu rechenintensiv hier jedoch ein Beispiel code zur errechnung der Drehzahl (müsste beim Hall Sensor interrupt stehen)
'Weiterhin müsste hier Die 4 Stellige Zahl noch einmal mit Str2digits in einzelne Ziffern umgewandelt werden.
' Periodendauer=Zeichennr*961µs+timer1*1/12000000
'Drehzahl=60/Periodendauer
'Diese Berechnungen sind einfach zu viel für den µC. er ist bereits jezt an seiner Leistungsgrenze!
Led1out = 5
Led2out = 2
Sekundenpunkt = 0
Led4out = 10
Led5out = 10
Return


Led_ausgabe:
'Ausgabe funktioniert überall gleich. Zunächst wird abgefragt ob die Postion des Rades mit dem gespeicherten Zeichen übereinstimmt und ob diese Runde schonmal geblitzt wurde
If Zeichennr = Led1_a(led1out) And L1 = 1 Then
   L1 = 0                                                   'Bit setzen, dass schon einmal geblitzt wurde
   Led1 = 1                                                 'Led einschalten
   Enable Timer2                                            'Timer starten. Wenn Timer überläuft, dann werden alle LEDs ausgeschaltet
End If
If Zeichennr = Led2_a(led2out) And L2 = 1 Then
   L2 = 0
   Led2 = 1
   Enable Timer2
End If
If Zeichennr = Led3_a(led3out) And L3 = 1 And Sekundenpunkt = 1 Then
   L3 = 0
   Led3 = 1
   Enable Timer2
End If
If Zeichennr = Led4_a(led4out) And L4 = 1 Then
   L4 = 0
   Led4 = 1
   Enable Timer2
End If
If Zeichennr = Led5_a(led5out) And L5 = 1 Then
   L5 = 0
   Led5 = 1
   Enable Timer2
End If

Return

Uhr_stellen_uart:
Disable Interrupts                                          'Interrupts für die Dauer des stellens abschalten
'Zeichen zum PC senden und auf Antwort warten
Do
Print "1"
Loop Until Inkey() <> 0

'Eingabe der Uhrzeit
Input "Jahr: " , _year
Input "Monat: " , _month
Input "Tag: " , _day
Input "Stunde: " , _hour
Input "Minute: " , _min
Input "Sekunde: " , _sec

'Uhrzeit in DS1307 schreiben
Gosub Setdate
Gosub Settime

Enable Interrupts                                           'Interrupts wieder einschalten

Return


' Unterprogramme für die Bascom Date/Time-Funktionen
Getdatetime:
  I2cstart
  I2cwbyte Ds1307w
  I2cwbyte 0
  I2cstart
  I2cwbyte Ds1307r
  I2crbyte _sec , Ack
  I2crbyte _min , Ack
  I2crbyte _hour , Ack
  I2crbyte Weekday , Ack
  I2crbyte _day , Ack
  I2crbyte _month , Ack
  I2crbyte _year , Nack
  I2cstop
  _sec = Makedec(_sec) : _min = Makedec(_min) : _hour = Makedec(_hour)
  _day = Makedec(_day) : _month = Makedec(_month) : _year = Makedec(_year)
  Gosub Square_an
Return

Setdate:
  _day = Makebcd(_day) : _month = Makebcd(_month) : _year = Makebcd(_year)       'Aus Dec Zahlen Binäre Zahlen für Ds1307 erstellen
  I2cstart
  I2cwbyte Ds1307w
  I2cwbyte 4
  I2cwbyte _day
  I2cwbyte _month
  I2cwbyte _year
  I2cstop
Return

Settime:
  _sec = Makebcd(_sec) : _min = Makebcd(_min) : _hour = Makebcd(_hour)
  I2cstart
  I2cwbyte Ds1307w
  I2cwbyte 0
  I2cwbyte _sec
  I2cwbyte _min
  I2cwbyte _hour
  I2cstop
Return
 
Ohje...
...Wenn man die Drezahl errechnen möchte wäre dies recht kompliziert und zu rechenintensiv hier jedoch ein Beispiel code zur errechnung der Drehzahl (müsste beim Hall Sensor interrupt stehen)
'Weiterhin müsste hier Die 4 Stellige Zahl noch einmal mit Str2digits in einzelne Ziffern umgewandelt werden.
' Periodendauer=Zeichennr*961µs+timer1*1/12000000
'Drehzahl=60/Periodendauer
'Diese Berechnungen sind einfach zu viel für den µC. er ist bereits jezt an seiner Leistungsgrenze!...
Das ist aber selbstgemacht. Selbst wenn man bei Eurem Weg bleibt, bietet dieser viel Optomierungspotential...

Zum Beispiel ist mir vollkommen schleierhaft, warum ihr diese Wandlung der Zeit-Variablen macht:
Die RTC liefert die Daten in Binary Coded Digits (gepackte BCD, wenn man "CH", "AM/PM" und "12/24" ignoriert). Du läßt die erstmal in eine Dezimalzahl wandeln.
Vor der Ausgabe läßt Du aus der Decimal 'n String machen, dessen einzelne Character dann quasi wieder in Digits umgewandelt werden (binär abgelegt, also ungepackte BCD).
gepackte BCD->Dezimal->String->Character->ungepackte BCD (das geht mit gaaaaanz wenig Bitschubserei viiiieeeel schneller/einfacher
Außerdem wird jede Sekunde (die die RTC leifert) die RTC via TWI ausgelesen. Was hat sich denn da geändert? Das kannst Du doch genauso einfach selbst machen, und den Config Clock-Kram rauslassen.
Die ganzen dezimalen Werte braucht Ihr doch gar nicht - Euch interessieren doch die gelieferten Digits. Dann kannst Du die Soft-Clock darauf aufbauen.

Sekunden-Einer -> Sekunden-Zehner -> Minuten-Einer -> Minuten-Zehner -> Stunden-Einer -> Stunden-Zehner -> ...
Wegen Schaltjahren und so dann halt einmal am Tag (und nach dem Reset) die RTC auslesen lassen - ansonsten machst Du das selbst in der "Square-ISR" Ein "Zahnrad" nach dem anderen inkrementieren, wenn das vorherige "übergelaufen" ist.

In der RTC-Lese-Routine müssen dann nur die empfangenen Bytes (quasi gepackte BCD) auf die Variablen verteilt werden. Also einmal den Zehnern und einmal den Einern zuweisen, je die anderen Bits mittels AND wegmaskieren, und bei den Zehnern die Nibbles SWAPpen (also das Hi-Nibble zum Lo-Nibble machen - effektiv dasselbe wie viermal rechtsschieben (da das Lo-Nibble 0b0000 war) mit nur einem Takt).
Wenn ich Deinen Weg in etwa richtig verstanden habe, machst Du das so:
Der Hall-Sensor liefert Dir , daß 'ne neue Runde angefangen hat, und korrigiert den Timer
Der Timer liefert "alle 30°" die Info, daß das Rad 'ne Stelle weiter ist.

Dein Hauptprogramm prüft ununterbrochen ob sich der (tastengetriggerte) Anzeigemodus oder die Zeit geändert hat, verzweigt dann ggf auf 'ne Routine die "Zündwinkel" für die 5 LEDs ermittelt.

Danach wird immer für jede LED geprüft, ob der aktuelle Winkel deren Zündwinkel ist, wenn ja wird die LED gezündet, und ein zweiter Timer zum Interruptgesteuerten abschalten aller LEDs gestartet.

Dein Programm ist also ununterbrochen dabei, für die Darstellung irgendwelche Sachen abzufragen/zuzuweisen. Auch wenn sich nichts geändert hat, wird in der Ausgabe-Routine ununterbrochen geprüft, ob der Winkel einer jeden LED erreicht wurde, und diese noch nicht "geblitzt" hat.

Mein Vorschlag hingegen war mit nur einem Timer ausgekommen, das "blitzen" wäre mit FastPWM selbständig durch den Timer generiert worden, welche LEDs dabei blitzen, würde alle 30° einmal aus der Tabelle auszulesen sein - ich schätze den Zeitbedarf der ISR auf wenige Mikrosekunden.
Im Hauptprogramm müßten dann ähnlich deinen Zündwinkeln der LEDs die Einträge in der Tabelle geändert werden - wenn sich was geändert hat...
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)