Hallo Forengemeinde,
Ich bin dabei mir eine CD-Uhr (besser als HDD-Uhr bekannt) aufzubauen.
Als Hardware habe ich momentan eine CD mit ausgefrästen Zahlen auf einem
Motor zu laufen.
An einer Stelle der CD ist ein Magnet aufgeklebt, der bei einer
Umdrehung der CD jeweils einen Hall-Sensor überfährt, der wiederrum das
Signal an den µc weitergiebt.
Unterhalb des Zahlenringes habe ich eine einzelne LED welche immer bei
einer bestimten Zahl aufleuchten soll.
Das Prinzip der Uhr sollte eigentlich klar sein.
Programierung auf einem attiny2313
Meine Überlegungen zur Ansteuerung
- Vorteiler der internen Clock ausgeschalten, um mit 8MHz hantieren zu
können.
- Den 8 Bit Timer des AVR nutze ich zusammen mit einem weiteren Zähler
um die Prozessortakte für eine Umdrehung der CD herauszubekommen.
- Mit etwas rechnen stelle ich den Preloader für den 16 bit Timer so
ein, das der aller 1 Grad Drehung der CD einen ISR auslöst.
- Die Gradzahl wird mit jedem ISR des 16 bit Timer hochgezählt und bei
360 zurückgesetzt.
- Im Hauptprogramm lasse ich nun die LED immer bei einer bestimmten
Gradzahl aufleuchten.
Mit den vg Überlegungen sollte eigentlich die Drehzahl der CD "relativ"
egal sein.
Nun der Grund meines Beitrages.
Die Zahlen der CD sind bereits gut sichtbar, bewegen sich jedoch, so
dass nicht immer die gleich von mir gewünschte Ziffer zu sehen ist.
Die Ziffern "rollen" mal langsamer mal schnelle je nach eingestellter
Drehzahl.
Bei der Berechnung der 1 Grad- Drehung habe ich einen Korrekturfaktor
eingefügt. Wenn ich diesen entsprechend einstelle kann ich zumindest bei
gleichbleibender Drehfrequenz der CD die gewählte Ziffer sehen.
Fragen:
- sind meine Überlegungen zur Ansterung richtig
- ist die Berechnung zur Ansteuerung richtig
- warum "rollen" die Ziffern
- ist eine andere Art der Ansteuerung zu bevorzugen
Nachstehende der Code:
1
2
#include<avr/io.h>
3
//#include <util/delay.h>
4
#include<stdlib.h>
5
#include<util/lcd.c>
6
#include<util/lcd.h>
7
#include<avr/interrupt.h>
8
//#include <avr/eeprom.h>
9
10
11
//Variablen definieren
12
unsignedlonga;//variable declarieren
13
unsignedinti;//variable declarieren
14
unsignedintj;//variable declarieren
15
unsignedintb;//variable declarieren
16
unsignedintgrad;//variable declarieren
17
unsignedlongz;//variable declarieren
18
unsignedlongx;//variable declarieren
19
chari_ausgabe[20];//variable wird zum umwandeln und ausgabe auf LCD benötigt (zahl ist die anzahl der stellen)
20
charz_ausgabe[20];//variable wird zum umwandeln und ausgabe auf LCD benötigt (zahl ist die anzahl der stellen)
21
22
23
//Routine bei externem Interrupt Signal vom Hall-Sensor
24
ISR(INT1_vect)
25
{
26
27
//Zählerstand 8 bit Timer auslesen und zurücksetzen
28
b=TCNT0;
29
TCNT0=1;
30
31
// Berechnung der 1 Grad Drehung 40L ist in diesem Fall der Korrekturwert
32
a=(i*256L);
33
a=65536L-(a+b)/360L+40L;
34
35
// Zähler zurücksetzen
36
i=0;
37
}
38
39
40
// Routine bei 8 bit Timmeroverflow
41
ISR(TIMER0_OVF_vect)
42
{
43
44
//Zähler für Berechnung
45
i=i+1;
46
}
47
48
49
// Routine bei 16 bit Timmeroverflow jeweils bei einer 1 Grad Drehung
50
ISR(TIMER1_OVF_vect)
51
{
52
grad=grad+1;
53
if(grad==360)
54
{grad=0;}
55
56
57
//Preloader für 16 bit Timer einstellen (Ansteuerung funktioniert erst nach dem 2. Durchlauf der ISR)
58
TCNT1=a;
59
}
60
61
62
63
intmain(void)//Hauptprogramm
64
{
65
66
//allgemeine Einstellungen
67
DDRA|=1<<0;//als Ausgang setzen
68
DDRD|=1<<5;// als Ausgang setzen hier hängt die LED dran
69
DDRD&=~1<<3;// als Eingang setzen hier häng der Hall-Sensor dran
70
PORTA|=(1<<0);// Bits setzen
71
PORTD|=(1<<3);// Bits setzen
72
73
lcd_init();// Initialisierung des LCD wurde in lcd.h auf Port B gesetzt
74
75
76
// internen clock vorteiler löschen
77
CLKPR=128;
78
CLKPR=0;// Wert darf nicht größer als 15 sein, sonst kann avr nicht mehr geflasht werden
79
CLKPR=0;
80
81
82
83
//Timer und Iterrupteinstellungen
84
85
GIMSK|=(1<<INT1);// Interrupt für int1 freischalten
86
MCUCR|=(1<<ISC11);//interrupt int1 bei fallender Flanke
87
88
TCCR1B|=(1<<CS10);//internen 16bit timer einschalten ohne vorteiler
89
TCCR0B|=(1<<CS00);//internen 8bit timer einschalten ohne vorteiler
90
TIMSK|=(1<<TOIE0);//Interrupt bei 8bit Timeroverflow einschalten
91
TIMSK|=(1<<TOIE1);//Interrupt bei 16bit Timeroverflow einschalten
92
93
sei();//interrupts einschalten bzw. zulassen
94
95
96
while(1)//endlosschleif
97
{
98
99
100
//Hier soll die LED bei 89 Grad eingeschalten werden
101
if(grad==89)
102
{
103
PORTD|=1<<5;//LED an
104
}
105
106
else
107
{
108
PORTD&=~1<<5;// LED aus
109
}
110
111
112
// Ausgabe von Werten zur Prüfung auf LCD, falls erforderlich
113
/*
114
115
lcd_setcursor( 0, 0 ); //Ausgabemarke Setzen
116
lcd_string("Zaehler i: ");
117
utoa( z, i_ausgabe, 10 ); //umwandeln von i für ausgabe 10 stellt das zehnersystem dar
118
lcd_string( i_ausgabe);
119
lcd_string(" "); //Ausgabe als String
120
121
lcd_setcursor( 0, 1 ); // Die Ausgabemarke in die 2te Zeile setzen
122
lcd_string("PT8bit: "); //Ausgabe als String
123
utoa( a, z_ausgabe,10); //umwandeln von i für ausgabe 10 stellt das zehnersystem dar
124
lcd_string( z_ausgabe);
125
lcd_string(" "); //Ausgabe als String
126
//_delay_ms(1000);
127
*/
128
129
130
}
131
return0;
132
}
Ich bin für konstruktive Kritiken und Anregungen dankbar.
Michael
Keine Synchronisation zwischen Drehzahl und Programm? Du mußt immer den
"Nullpunkt" bestimmen, bevor Du weißt wann die entsprechenden Gradzahlen
erreicht sind.
Michael schrieb:
Bevor ich mir das Programm ansehe, ein paar Gedanken vorab
> Unterhalb des Zahlenringes habe ich eine einzelne LED welche immer bei> einer bestimten Zahl aufleuchten soll.> Das Prinzip der Uhr sollte eigentlich klar sein.
Stroboskop
Frage in die Runde: Hat das von eich schon mal wer probiert? Ich hatte
mal einen kurzen Versuch in dieser Richtung unternommen, bin aber drauf
gekommen, dass das nicht gut funktioniert. Das Problem: Lässt man die
LED zu lang leuchten, wird alles unscharf. Lässt man die LED zu kurz
leuchten, fehlt die Helligkeit.
OK, zum Thema
> Meine Überlegungen zur Ansteuerung>> - Vorteiler der internen Clock ausgeschalten, um mit 8MHz hantieren zu> können.> - Den 8 Bit Timer des AVR nutze ich zusammen mit einem weiteren Zähler> um die Prozessortakte für eine Umdrehung der CD herauszubekommen.> - Mit etwas rechnen stelle ich den Preloader für den 16 bit Timer so> ein, das der aller 1 Grad Drehung der CD einen ISR auslöst.
Werd ich mir mal ansehen.
> - Die Gradzahl wird mit jedem ISR des 16 bit Timer hochgezählt und bei> 360 zurückgesetzt.
Keine gute Idee.
Deine vorherigen Rechnereien ergen mit Sicherheit kein ganzzahliges
Ergebnis. Wenn du nur mit dem Timer und einem fixen Versatz für 1 Grad
arbeitest, dann summierst du den Fehler auf, der sich aus der
Nichtberücksichtigung der Kommastellen ergibt. Und schon gar nicht, wird
die CD nach 360 Stück dieser Zeitmessungen auch 360° gedreht haben.
Du hast doch einen Magneten, der dir sagt wann eine Umdrehung zu Ende
ist. Das ist viel zuverlässiger, als das hochzählen auf 360.
> Nun der Grund meines Beitrages.> Die Zahlen der CD sind bereits gut sichtbar, bewegen sich jedoch, so> dass nicht immer die gleich von mir gewünschte Ziffer zu sehen ist.> Die Ziffern "rollen" mal langsamer mal schnelle je nach eingestellter> Drehzahl.
Dann stimmt irgendwas in deiner Berechnung nicht, bzw. du hast genau den
Effekt, dass die CD eben nicht 360° gedreht hat, wenn laut deiner
Zählung 360 Grade vergangen sein sollten.
So. Jetzt führ ich mir mal den Code zu Gemüte.
Jupp. Dein Problem dürfte tatsächlich auf diesen Summen-Fehler
zurückzuführen sein.
Schau. Wenn es blöd hergeht, dann rechnest du zb aus (jetzt rein
rechnerisch), dass du im Timer1 alle 876.9 Timertakte einen Interrupt
brauchen würdest. Tatsächlich kannst du aber nur 876 einstellen. D.h. du
lässt die 0.9 unter den Tisch fallen. Wenn du das 360 mal machst, dann
hat sich der Fehler zu 0.9 * 360 gleich 324 fehlenden Timerticks
aufsummiert. D.h. du timest jede einzelne Umdrehung der CD um 324
Timerticks zu kurz. Da 876 ein ganzes Grad waren, ist das schon fast ein
halbes Grad, um was du dich bei jeder CD-Umdrehung verhaust.
D.h. Aufsummieren ist oft keine so gute Idee.
Alleine das du da einen Korrekturwert brauchst, müsste schon die
Alarmglocken klingen lassen. Wenn alles richtig ist, braucht es den
nicht.
Deine Benutzung des Timer 1 ist .... eher schlecht. Ich würde das anders
machen.
erstens nicht auf den Overflow gehen. Diese ganzen Strategien mit Timer
vorladen sind meistens ein Zeichen dafür, dass man sich nicht damit
beschäftigt hat, welche Möglichkeiten der Timer bietet. Das ist CTC für
Arme. Dabei kann der Timer CTC ganz von alleine :-)
zweitens ist auch CTC keine gute Idee. Ich würde den Timer einfach
durchlaufen lassen und einen ganz normalen Compare Match benutzen. In
der ISR rechne ich mir aus, bei welchem Zählerstand der nächste Compare
Match erfolgen muss. Und zwar nicht durch aufsummieren, sondern durch
ganz klaaisische Berechnung aus der bekannten Gradzahl mittels 3-Satz
und den Messwerten vom Timer 0. (Allerdings würde ich mir vorher mal die
Zahlen ansehen um zu prüfen, ob ich nicht in einen arithmetischen
Überlauf laufe). Auf die Art ist der Summenfehler weg bzw. der
Nachkommafehler 'verschmiert' sich über die komplette CD-Umdrehung und
nicht nur auf 1 einzelnes Grad.
Michael schrieb:> das der aller 1 Grad Drehung der CD einen ISR auslöst.
Um das Problem besser in den Griff zu bekommen, könntest du auch
überlegen, ob nicht eine 6° Auflösung reicht, mit dann genau 60
Schritten pro Umdrehung.
Es reicht dann, die Umdrehungszeit durch 60 zu teilen, und nicht mehr in
Prozessortakten, sondern in Timerschritten zu arbeiten. Mit einem Mega48
würde ich dann einen gleichlaufenden 3.Timer so programmieren, das die
ISR für diesen Timer die LED zündet oder löscht. Gut, der Tiny2313 hat
nicht so viele Timer, aber du könntest ein OC Register benutzen.
Könnte übrigens eine gute Idee sein, deinen Indexpuls (Hallgenerator) an
ICP anzuschliessen, dann misst der Timer(1) quasi vollautomatisch.
Karl Heinz schrieb:> zweitens ist auch CTC keine gute Idee. Ich würde den Timer einfach> durchlaufen lassen und einen ganz normalen Compare Match benutzen. In> der ISR rechne ich mir aus, bei welchem Zählerstand der nächste Compare> Match erfolgen muss. Und zwar nicht durch aufsummieren, sondern durch> ganz klaaisische Berechnung aus der bekannten Gradzahl mittels 3-Satz> und den Messwerten vom Timer 0. (Allerdings würde ich mir vorher mal die> Zahlen ansehen um zu prüfen, ob ich nicht in einen arithmetischen> Überlauf laufe). Auf die Art ist der Summenfehler weg bzw. der> Nachkommafehler 'verschmiert' sich über die komplette CD-Umdrehung und> nicht nur auf 1 einzelnes Grad.
... und natürlich den 0-Punkt der Drehung nicht arithmetisch festlegen,
sondern durch den Durchgang des Magneten. Das sollte sowieso klar sein.
Matthias Sch. schrieb:> Michael schrieb:>> das der aller 1 Grad Drehung der CD einen ISR auslöst.>> Um das Problem besser in den Griff zu bekommen, könntest du auch> überlegen, ob nicht eine 6° Auflösung reicht, mit dann genau 60> Schritten pro Umdrehung.> Es reicht dann, die Umdrehungszeit durch 60 zu teilen, und nicht mehr in> Prozessortakten, sondern in Timerschritten zu arbeiten.
Wenn ich ihn richtig verstanden habe, dann kann er das nicht machen.
Die Ziffern sind aus der Scheibe ausgefräst. Sein Prinzip ist es, die
Ziffer (von hinten?) zu beleuchten, wenn sie an der richtigen Stelle in
der Umdrehung steht. D.h. er ist darauf angewiesen, dass sich die
Scheibe in der Zeit der Beleuchtung nicht 'wesentlich' weiter dreht,
sonst wird alles unscharf. Er muss zu sehen, dass sein Lichtblitz
möglichst kurz, und dabei aber möglichst intensiv, wird.
Hallo und vielen Dank für eure Antworten,
den Fehler beim Runden hatte ich auch schon in verdacht. Allerdings
hatte ich gehofft, das das durch das Neuberechnen bei jeder Umdrehung
nicht so sehr ins Gewicht fallen würde.
Das mit dem Compare Match höhrt sich nicht uninteressant an.
Da ich nicht täglich programmiere bin ich damit noch nicht so vertraut.
Giebt es n gutes TUT für die Anwendung des Compare Match?
Sobald ich weiterkomm oder ergänzend Hilfestellung benötige melde ich
mich wieder.
Danke nochmal für die Denkanstöße
Michael schrieb:> Das mit dem Compare Match höhrt sich nicht uninteressant an.> Da ich nicht täglich programmiere bin ich damit noch nicht so vertraut.> Giebt es n gutes TUT für die Anwendung des Compare Match?
Das ist recht einfach.
Du lässt den Timer einfach in Ruhe zählen.
Dann gibt es noch das Register OCR1A.
Immer wenn der Wert vom TCNT1 (also der aktuelle Zählerwert) mit dem
Inhalt von OCR1A identisch ist, wird ein Interrupt ausgelöst. In deinem
Fall kann man dann innerhalb der ISR den nächsten Wert ins OCR1A
schreiben, bei dem dann der nächste Interrupt kommt. Wie üblich muss der
Interrupt frei gegeben werde. Das ist also im Grunde recht ähnlich wie
beim Overflow Interrupt. Nur dass du selbst bestimmen kannst, bei
welchem Zählerwert der Interrupt ausgelöst werden soll. Und genau das
nutzt du aus, indem du diesen Wert bei jedem Interrupt Ereignis neu
berechnest.
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
ISR(TIMER1_COMPA_vect)
5
{
6
OCR1A+=200;
7
}
8
9
intmain()
10
{
11
TCCR1B|=(1<<CS10);
12
TIMSK|=(1<<OCIE1A);
13
14
sei();
15
16
while(1)
17
{
18
}
19
20
}
Alle 200 Timer-Takte wird ein Interrupt ausgelöst, weil OCR1A in der ISR
um jeweils 200 'weiter' gestellt wird.
Karl Heinz schrieb:>> Um das Problem besser in den Griff zu bekommen, könntest du auch>> überlegen, ob nicht eine 6° Auflösung reicht, mit dann genau 60>> Schritten pro Umdrehung.>> Es reicht dann, die Umdrehungszeit durch 60 zu teilen, und nicht mehr in>> Prozessortakten, sondern in Timerschritten zu arbeiten.>> Wenn ich ihn richtig verstanden habe, dann kann er das nicht machen.>> Die Ziffern sind aus der Scheibe ausgefräst. Sein Prinzip ist es, die> Ziffer (von hinten?) zu beleuchten, wenn sie an der richtigen Stelle in> der Umdrehung steht. D.h. er ist darauf angewiesen, dass sich die> Scheibe in der Zeit der Beleuchtung nicht 'wesentlich' weiter dreht,> sonst wird alles unscharf. Er muss zu sehen, dass sein Lichtblitz> möglichst kurz, und dabei aber möglichst intensiv, wird.
doch das tät schon gehen. ich hab auch schon mit einer 15tel
Unterteilung herumexperimentiert (es sind insgesamt 15 Ziffern auf der
Scheibe). Der Lichtblitz ist halt immer nur einen Takt lang. Allerdings
rollen auch hier die Ziffern.
und wie oben angefragt: ja die Helligkeit ist bei nur einem Takt
Lichtblitz recht gering und bei mehreren Takten verschwimmt die Ziffer.
Ich habe momentan eine SMD LED dahinter und mann kann die Ziffer
trotzdem gut erkennen. Bei einer Hochleistungsled wird es sicher auch
gut hell werden.
> Allerdings hatte ich gehofft, das das durch das Neuberechnen bei> jeder Umdrehung nicht so sehr ins Gewicht fallen würde.
Das Problem ist nicht die Neuberechnung, sondern dass du davon ausgehst,
dass die CD auch wirklich um exakt 360° gedreht hat, so wie du das
anhand deiner Zahlen berechnet hast. Dem ist aber nicht so.
Die CD muss dir selber sagen, wann sie wieder in der 0-Position ist.
Wann also tatsächlich die nächste Runde anfängt. Ist ja kein Problem.
Dafür hast du ja den Magneten.
Die Neuberechnung gleicht dir nur Drehzahlschwankungen aus, nicht jedoch
den Postionsfehler, der bei jeder einzelnen Umdrehung anfällt.
Karl Heinz schrieb:>> Das mit dem Compare Match höhrt sich nicht uninteressant an.>> Da ich nicht täglich programmiere bin ich damit noch nicht so vertraut.>> Giebt es n gutes TUT für die Anwendung des Compare Match?>> Das ist recht einfach.
Danke für deine Ausführungen. Ich denke das kann ich gut umsetzen.
Allerdings muss ich dann doch irgendwie die Takte bis zu der
entsprechendnen Gradzahl bei der meine Ziffer auf der CD steht
rechnerisch ermittelt. Hierbei wird es zwangsläufig Rundungsfehler
geben.
Mir ist noch nicht ganz klar wie ich das umgehen (bzw. marginal halten)
kann.
Karl Heinz schrieb:> Die CD muss dir selber sagen, wann sie wieder in der 0-Position ist.> Wann also tatsächlich die nächste Runde anfängt. Ist ja kein Problem.> Dafür hast du ja den Magneten.> Die Neuberechnung gleicht dir nur Drehzahlschwankungen aus, nicht jedoch> den Postionsfehler, der bei jeder einzelnen Umdrehung anfällt.
jetzt leuchten was bei mir (im Hinr)
ich werd mal schauen, wie ich das richtig machen kann.
Michael schrieb:> Allerdings muss ich dann doch irgendwie die Takte bis zu der> entsprechendnen Gradzahl bei der meine Ziffer auf der CD steht> rechnerisch ermittelt.
Na ja. der 3-Satz ist schon erfunden.
360 Äpfel kosten 87692 Euro. Wieviel kosten 89 Äpfel?
1
360 ..... 87692
2
89 ..... x
3
------------------
4
87692 * 89
5
x = ------------ = 21679
6
360
In deinem Fall dann eben: Wenn eine komplette Umdrehung 87692 Timerticks
dauert, dann vergehen vom Start der Umdrehung bis auf 89° 21679
Timerticks.
Den 3-Satz solltest du dir merken und sicher anwenden können. Über den
Daumen gepeilt sind mehr als 80% aller arithmetischen Probleme, auf die
man so beim µC stösst, nichts anderes als ein 3-Satz.
Michael schrieb:>> Die CD muss dir selber sagen, wann sie wieder in der 0-Position ist.>> Wann also tatsächlich die nächste Runde anfängt. Ist ja kein Problem.>> Dafür hast du ja den Magneten.>> Die Neuberechnung gleicht dir nur Drehzahlschwankungen aus, nicht jedoch>> den Postionsfehler, der bei jeder einzelnen Umdrehung anfällt.>> jetzt leuchten was bei mir (im Hinr)> ich werd mal schauen, wie ich das richtig machen kann.
möglicherweise recht es ja schon in der ISR(INT1_vect) die grad=0; zu
setzen.
Michael schrieb:> möglicherweise recht es ja schon in der ISR(INT1_vect) die grad=0; zu> setzen.
Es hat gereicht.
Genau da lag der Fehler! Die fehlende Nullpunktbestimmung bei jeder
Umrundung.
Nichts desto trotz werde ich versuchen das ganze mit dem CTC zu lösen.
vielen Dank nochmal
Karl Heinz schrieb:> Wenn ich ihn richtig verstanden habe, dann kann er das nicht machen.>> Die Ziffern sind aus der Scheibe ausgefräst. Sein Prinzip ist es, die> Ziffer (von hinten?) zu beleuchten, wenn sie an der richtigen Stelle in> der Umdrehung steht.
Ahh, das hatte ich missverstanden. Ich ging von rotierenden LEDs aus,
die dann die Zeiger darstellen (bisschen wie die Handpropeller mit LED
Grafik). Hier ist es gerade umgekehrt.