Hallo, ich habe mit meinem Mega8 und dem STK500 eine Uhr programmiert, die ich jedoch nicht auf das Display ausgebe, sondern sekündlich auf UART. Die CPU-Frequenz ist auf extern gefused und durch den STK500 Frequenzgeber gegeben. AVR-Studio sagt 3868400 Hz. Weiß jemand, wie genau diese Frequenz wirklich ist? Das "Datenblatt" des STK500 schweigt diesbezüglich. Der Fehler der Uhr ist ca. -1% Also nach 100sek. geht sie schon eine sek. falsch (nach) Könnte das der Taktgenauigkeit des STK500 entsprechen? Anmerkung: Um Interruptzeiten möglichst kurz zu halten, setze ich ein Flag. Durch Vorteiler von 1024 und Interrupt nach 3600 zählungen macht das genau einen Interrupt pro sekunde ---> Ich bin ziemlich sicher, dass keine Interrupts verschluckt werden. Ich war erstaunt, als ich gesehen habe, dass die Ausgabe von 10 Zeichen auf UART ca. 60.000 Takte braucht. Das sind wenn man großzügig rechnet bei 9600 Baud ca. 10ms ---> Die Übertragung sollte lange fertig sein, bis zum nächsten Interrupt. Gruß, fiete
Hallo, Friedrich Kpunkt schrieb: > Hallo, > > ich habe mit meinem Mega8 und dem STK500 eine Uhr programmiert, die ich > jedoch nicht auf das Display ausgebe, sondern sekündlich auf UART. > > Die CPU-Frequenz ist auf extern gefused und durch den STK500 > Frequenzgeber gegeben. AVR-Studio sagt 3868400 Hz. Weiß jemand, wie > genau diese Frequenz wirklich ist? Das "Datenblatt" des STK500 schweigt > diesbezüglich. Den Takt erzeugt wohl ein Timer des AVR auf dem STK, sollte also eigentlich Quarzgenau sein. > > Der Fehler der Uhr ist ca. -1% Also nach 100sek. geht sie schon eine > sek. falsch (nach) Könnte das der Taktgenauigkeit des STK500 > entsprechen? Ohne Sourcecode ist es schwer einen Softwarefehler auszuschlißen... > > Anmerkung: > Ich war erstaunt, als ich gesehen habe, dass die Ausgabe von 10 Zeichen > auf UART ca. 60.000 Takte braucht. Das sind wenn man großzügig rechnet > bei 9600 Baud ca. 10ms ---> Die Übertragung sollte lange fertig sein, > bis zum nächsten Interrupt. Warum? 9600Baud sind 960 Byte/s bei einem Stopbit und ohne zusätzliche Pause. 1000ms/960*10 sind also minimal 10,41ms für 10 Byte. Die UART-Ausgabe braucht nur ca. 8 Takte pro Byte, der Rest ist Warten darauf, daß das Byte endlich mit den lahmen 9600 Baud rausgetaktet ist. Es sei denn, man legt es in einen Buffer und sendet per UART-TXE-Interrupt. Gruß aus Berlin Michael Gruß aus Berlin Michael
Klar, gern zeige ich den Assembler-Code: Warum ich so erstaunt war, über die 10ms UART-Sendezeit ist nur aus der Tatsache begründet, dass ich mich erst nen paar tage mit sowas beschäftige...
1 | .include "m8def.inc" |
2 | |
3 | .equ F_CPU = 3686400 |
4 | .equ BAUD = 9600 |
5 | |
6 | |
7 | .def temp1=r16 |
8 | .def temp2=r17 |
9 | .def stunden=r18 |
10 | .def minuten=r19 |
11 | .def sekunden=r20 |
12 | .def flag=r21 |
13 | .def flag2=r25 |
14 | .def subcount=r22 |
15 | .def einer=r23 |
16 | .def zehner=r24 |
17 | |
18 | .dseg |
19 | |
20 | |
21 | .cseg |
22 | |
23 | .org 0x0000 |
24 | rjmp boot |
25 | |
26 | .org OC1Aaddr |
27 | rjmp CTC_OverFlow |
28 | |
29 | ;################################################################################# |
30 | ;# AUTOMATIC BAUDRATE CALCULATION -- AUTOMATIC BAUDRATE CALCULATION -- AUTOMA # |
31 | ;################################################################################# |
32 | |
33 | .equ UBRR_VAL = ((F_CPU+BAUD*8)/(BAUD*16)-1) ; clever runden |
34 | .equ BAUD_REAL = (F_CPU/(16*(UBRR_VAL+1))) ; Reale Baudrate |
35 | .equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000) ; Fehler in Promille |
36 | |
37 | .if ((BAUD_ERROR>10) || (BAUD_ERROR<-10)) ; max. +/-10 Promille Fehler |
38 | .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!" |
39 | .endif |
40 | ;################################################################################# |
41 | |
42 | |
43 | boot: |
44 | |
45 | ;Stackpointer Init |
46 | ldi temp1,HIGH(RAMEND) |
47 | out SPH,temp1 |
48 | ldi temp1,LOW(RAMEND) |
49 | out SPL,temp1 |
50 | ;Set Baudrate |
51 | ldi temp1,HIGH(UBRR_VAL) |
52 | out UBRRH,temp1 |
53 | ldi temp1,LOW(UBRR_VAL) |
54 | out UBRRL,temp1 |
55 | ;Set framerate 8 to 8 Bit |
56 | ldi temp1,(1<<URSEL)|(3<<UCSZ0) |
57 | out UCSRC,temp1 |
58 | ;Start USART |
59 | sbi UCSRB,TXEN |
60 | |
61 | ;set CTC |
62 | |
63 | ;set OverFlow value |
64 | ldi temp1,HIGH(3600-1) |
65 | out OCR1AH,temp1 |
66 | ldi temp1,LOW(3600-1) |
67 | out OCR1AL,temp1 |
68 | ;init CTC |
69 | ldi temp1,(1<<WGM12)|(5<<CS10) |
70 | out TCCR1B,temp1 |
71 | ;init CTC |
72 | ldi temp1,1<<OCIE1A |
73 | out TIMSK,temp1 |
74 | ;set prescaler |
75 | ldi temp1, 0b00000101 |
76 | out TCCR0, temp1 |
77 | |
78 | ;clear all: |
79 | clr temp1 |
80 | clr minuten |
81 | clr stunden |
82 | clr flag |
83 | |
84 | |
85 | ;interrupts aktiviren |
86 | |
87 | sei |
88 | |
89 | loop: in temp1,SREG |
90 | cpi flag,1 |
91 | breq Ausgabe |
92 | out SREG,temp1 |
93 | rjmp loop |
94 | |
95 | |
96 | Ausgabe: |
97 | |
98 | mov einer,stunden |
99 | rcall Ascii_Umrechner |
100 | |
101 | mov zehner,einer |
102 | rcall send |
103 | |
104 | ldi zehner,':' |
105 | rcall send |
106 | |
107 | mov einer,minuten |
108 | rcall Ascii_Umrechner |
109 | |
110 | mov zehner,einer |
111 | rcall send |
112 | |
113 | ldi zehner,':' |
114 | rcall send |
115 | |
116 | mov einer,sekunden |
117 | rcall Ascii_Umrechner |
118 | |
119 | mov zehner,einer |
120 | rcall send |
121 | ldi zehner,10 |
122 | rcall send |
123 | ldi zehner,13 |
124 | rcall send |
125 | |
126 | clr flag |
127 | out SREG,temp1 |
128 | rjmp loop |
129 | |
130 | send: |
131 | sbis UCSRA,UDRE |
132 | rjmp send |
133 | out UDR,zehner |
134 | nop |
135 | ret |
136 | |
137 | Ascii_Umrechner: |
138 | cpi einer,10 |
139 | brsh zehn |
140 | subi einer,(-'0') |
141 | ldi zehner,'0' |
142 | rjmp send |
143 | zehn: cpi einer,20 |
144 | brsh zwan |
145 | subi einer,(10-'0') |
146 | ldi zehner,'1' |
147 | rjmp send |
148 | zwan: cpi einer,30 |
149 | brsh dreisg |
150 | subi einer,(20-'0') |
151 | ldi zehner,'2' |
152 | rjmp send |
153 | dreisg: cpi einer,40 |
154 | brsh virsg |
155 | subi einer,(30-'0') |
156 | ldi zehner,'3' |
157 | rjmp send |
158 | virsg: cpi einer,50 |
159 | brsh funfz |
160 | subi einer,(40-'0') |
161 | ldi zehner,'4' |
162 | rjmp send |
163 | funfz: subi einer,(50-'0') |
164 | ldi zehner,'5' |
165 | rjmp send |
166 | |
167 | |
168 | |
169 | CTC_OverFlow: |
170 | in temp2,SREG |
171 | inc sekunden |
172 | cpi sekunden,60 |
173 | breq min |
174 | rjmp end_uhrwerk |
175 | min: clr sekunden |
176 | inc minuten |
177 | cpi minuten,60 |
178 | breq stun |
179 | rjmp end_uhrwerk |
180 | stun: clr minuten |
181 | inc stunden |
182 | cpi stunden,12 |
183 | brne end_uhrwerk |
184 | clr stunden |
185 | rjmp end_uhrwerk |
186 | |
187 | |
188 | end_uhrwerk: |
189 | |
190 | ldi flag,1 ;flag setzen |
191 | out SREG,temp2 |
192 | reti |
He Leute, Habe zwei weitere Nachmittage mit der Fehlersuche zugebracht und komme zu dem Schluss, dass die Taktfrequenz des STK500 nur ca. 1% Genauigkeit hat (bei mir -0.7). Leider kann ich das nicht direkt nachmessen, sondern nur durch meine selbstgebastelte Uhr. (alternative Vorschläge?) Im Debug-Modus des AVR-Studios zählt der code jedenfalls brav die genaue Taktfrequenz ab, bevor der nächste interrupt kommt. Programmierfehler hat ja hier auch keiner gefunden - zumindest keine groben ;-) Als nächsten Schritt organisiere ich mir mal einen Quarz und gucke mal, ob meine Uhr vielleicht genauer geht. Gruß, fiete
Mit Quarz ist die Taktfrequenz mindestens auf 0,1% genau, meistens um den Faktor 10 besser. Eine 1%-ige Abweichung kann also nur durch einen Softwarefehler bedingt sein, oder dass die Quarzfrequenz keine Baudratefrequenz ist, also eine etwas krumme Zahl hat. Dann lässt sich die exakte Baudrate nur mit einigen Prozent Abweichung erreichen. Bei der Übertragung mit RS232 machen Abweichungen bis 3 % üblicherweise nichts aus. Es gilt folgende Abschätzung: Wenn das Telegramm eines Byte 10 Bit umfasst, kann im letzten Bit eine Abweichung eines halben Bit toleriert werden, ohne ins Nachbarbit zu geraten, da ja beim ersten Bit immer neu synchronisiert wird. Dem entspricht eine Toleranz von 1/20 also 5%.
vielleicht auch der übliche fehler, dass man beispielsweise bei voller 60er sekunde erst resettet oder ähnliches? sowas hab ich schonmal gebracht.. schäm
@Peter: Die Übertragung läuft einwandfrei. Die Übertragung ist lange abgeschlossen, bevor der nächste Interrupt die neue Sekunde einläutet und das Flag setzt, welche dann die Übertragung triggert. @Henk: Reset hatte ich auch schon als Verursacher vermutet. Was allerdings dagegen spricht ist, dass bei einem Reset alle "Zähler" mit clr auf null gesetzt werden, sodass es auffallen würde, wenn er einen Reset bekommt. Oder nicht?
Ähm nee ich habe mich undeutlich ausgedrückt. Ich meinte nur bzgl. deiner Aussage "eine Uhr gebaut" dass vielleicht bei Übernahme von Sekunden in Minutenvariablen oder so Ddu etwas verdreht haben könntest. Ich hatte beispielsweise mal bei der falschen Sekunde hochgezählt und somit jede Minute eine Sekunde verloren. ;-)
Naja, der Zähler zählt von 0 bis 59. Wenn es bei 60 ist, wird er wieder auf null gesetzt. Also das stimmt auch.
Hm, auf meinem STK500 ist kein Quarz, sondern ein Keramikresonator. Gut und günstig für übliches (UART z.B.), nicht genau genug für ne Uhr. Ohne deine Software angeschaut zu haben - das liegt im Rahmen der Toleranz des Keramikresonators.
@Friedrich: Der 3.68MHz Takt wird durch den Timer des 8535 erzeugt, der mit einem 7.37MHz Resonator versorgt wird. Der Resonator ist natürlich etwas weniger genau als ein Quarz. Auf dem STK500 ist aber ein diskret aufgebauter Oszillator mit Quarzsockel vorhanden, den man auch benutzen kann. Näheres in der STK500 Help Datei (STK500.CHM). Da gibt es auch einen kompletten Schaltplan des STK500.
Die Tempertaturabhänigkeit dieses Keramikresonators scheint auch recht stark zu sein. Oder andere Umwelteinflüsse, jedenfalls hat auch eine Overflow-Korrektur ein besseres, aber kein konstantes Ergebnis geliefert... Mit meiner nächsten Bestellung wird mir auch ein hübscher Quarz frei haus geliefert werden, bin mal gespannt, wie es dann tickt.
"ein hübscher Quarz" - sei doch nicht so geizig, ein sortiment der gängigen größen hätte es doch auch getan?!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.