Hallo,
ich habe folgendes Testprogramm eingespielt, das die LED eigentlich mit
488 Hz und paar Zerquetschten flackern lassen sollte. Leider sind meine
Zerquetschten viel zu klein und ich messe um die 487 Hz.
Mal die Periodenzeiten gemessen und statt der 2,048 ms messe ich 2,0507
ms.
Kann der Quarz echt über 1300 ppm daneben liegen?
Hardware-Plattform ist ein Sainsmar Arduino Uno R2 mit winzigem Quarz im
6-poligen Gehäuse.
Das Programm arbeitet interruptgesteuert und sollte eigentlich richtig
sein.
Beste Grüße, Marek
P.S. Gemessen mit ELV FC7008
1
/*
2
Experimente mit Timern
3
Timer0 im Normal Mode und Port-Toggle per Interrupt
4
DB1BMN
5
2013-03-25
6
*/
7
8
#include<avr/io.h>
9
#include<avr/interrupt.h>
10
11
#define LEDPORT PORTB
12
#define LEDPORT_ddr DDRB
13
#define LEDPORT_in PINB
14
#define LED PB5
15
16
17
ISR(TIMER0_OVF_vect)
18
{
19
/* Interrupt Aktion alle
20
(16MHz/64)/256 Hz = 976,5625 Hz
21
22
1/976,5625 s = 1,024 ms
23
*/
24
25
LEDPORT_in|=(1<<LED);// Toggle LED
26
}
27
28
29
intmain(void)
30
{
31
32
// Port für LED konfigurieren
33
LEDPORT_ddr|=(1<<LED);
34
35
// Timer0 Normal Mode (Mode 0; default)
36
// (WGM02 WGM01 WGM00) = 000
37
TCCR0A&=~(1<<WGM01)
38
&~(1<<WGM00);
39
TCCR0B&=~(1<<WGM02);
40
41
42
// Timer0 Prescaler 64
43
TCCR0B|=(1<<CS01)
44
|(1<<CS00);
45
// Ab hier läuft der Timer mit 16 MHz / 64 = 250 kHz (Ticks)
Marek N. schrieb:> Hallo,>> ich habe folgendes Testprogramm eingespielt, das die LED eigentlich mit> 488 Hz und paar Zerquetschten flackern lassen sollte. Leider sind meine> Zerquetschten viel zu klein und ich messe um die 487 Hz.> Mal die Periodenzeiten gemessen und statt der 2,048 ms messe ich 2,0507> ms.>> Kann der Quarz echt über 1300 ppm daneben liegen?
Normal nicht, bei schlechter Beschaltung von Quarzen und den verkehrten
Typen ist aber ALLES möglich! 1300ppm ist aber unwahrscheinlich.
Aber auch die besten Scopes (hier bei usn Agilent) haben eine Abweichung
von bis zu 30ppm und mehr. Um Dein Messgerät zu kalibrieren benötigts Du
einen genauen VCTCXO, damit weisst Du dann wie Dein Scope/Messgerät
abweicht. Bei den meisten Messgeräten ist halt auch nur ein Quarz
drinnen.
rgds
Marek N. schrieb:> Kann der Quarz echt über 1300 ppm daneben liegen?
Nimm einen Radioempfänger auf der Quarzfrequenz oder einer ungeraden
Oberwelle und hör es dir an. Die Rundfunksender halten (bis auf
Ausnahmen) ihre Frequenz beinahe mit Atomuhrgenauigkeit.
Marek N. schrieb:> Kann der Quarz echt über 1300 ppm daneben liegen?
Offensichtlich ja, es soll ja alles billig sein.
Der FC7008 hat einen 25MHz OCXO und liefert für diesen Vergleich
durchaus 'richtige' Ergebnisse.
Darüber hinaus kann er sogar 0 Hz messen :-)
Bei sechspoligem Gehäuse tippe ich auf Keramik-Resonator.
Auf meinem Arduino-board läuft z.B. der atmega8 (USB-RS232-Umsetzer) mit
16 MHz Quarz und die CPU (atmega2560) mit einem 6poligen
Keramikschwinger.
Die Frequenzablage passt auch zu einem Keramikschwinger.
Jörg Wunsch schrieb:> Ansonsten toggeln auch alle die Ausgänge, deren Eingänge gerade> eine 1 zurücklesen.
HÄÄ????
Was wird denn da zurückgelesen?
Daraus: PINB |= (1 << 2);
wird das: sbi 0x16, 2
und dann toggelt PB2 und nichts anderes.
Oder wer ist hier auf dem Holzweg?
mfg.
Marek N. schrieb:> Wundere mich eh, warum die für den USB-ATmega> so einen verwendet haben, offenbar ist das Timing dort strenger.
Ja, das USB-Timing ist ziemlich strikt. Für ein lowspeed-Device
genügt die Toleranz eines Keramikschwingers noch, für ein
fullspeed-Device aber nicht mehr.
Thomas Eckmann schrieb:> HÄÄ????
Du solltest vorsichtiger in deinen Äußerungen werden …
> Was wird denn da zurückgelesen?
PINB
> Daraus: PINB |= (1 << 2);> wird das: sbi 0x16, 2> und dann toggelt PB2 und nichts anderes.
Nein. Es toggelt auch alle die Pins, die beim Rücklesen von PINB eine
1 haben.
Hinweis: SBI ist eine read-modify-write-Operation …
@ Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
>Hinweis: SBI ist eine read-modify-write-Operation …
Mag sein, aber diese bezieht sich nur auf EIN Bit. Da bleibt die
Quizzfrage, was der Compiler aus
PINB |= (1 << 2);
macht?
sbi PINB, 2
oder
in r16, PINB
ORI r16, 0x04
out PINB, r16
Hmmm?
Jörg Wunsch schrieb:> Nein. Es toggelt auch alle die Pins, die beim Rücklesen von PINB eine> 1 haben.> Hinweis: SBI ist eine read-modify-write-Operation …
Also konkret:
Wenn PD7 1 ist und PD6 mit sbi (PIND|=(1<<6) toggelt, toggelt PD7 auch
und wird 0. Danach toggelt er dann nicht mehr, weil er ja 0 ist?
Ich hoffe jetzt, daß ich das falsch verstanden habe, sonst kann ich
meine Controller alle wegschmeissen, weil die kaputt sind.
mfg.
Falk Brunner schrieb:> Da bleibt die> Quizzfrage, was der Compiler aus>> PINB |= (1 << 2);>> macht?>> sbi PINB, 2>> oder>> in r16, PINB> ORI r16, 0x04> out PINB, r16>> Hmmm?
Das bleibt bezüglich der Wirkung jedoch gleich.
Darauf, dass SBI ein read-modify-write ist, welches sich stets auf das
ganze Register bezieht (wie sonst sollte man es auch implementieren?),
wird an anderer Stelle in den Datenblättern teilweise hingewiesen: wo
es um das Löschen von Interruptflags geht. Wimre beim ADC, bei dem
das Interruptflag ja in einem normalen Steuerregister steht.
Thomas Eckmann schrieb:> Wenn PD7 1 ist und PD6 mit sbi (PIND|=(1<<6) toggelt, toggelt PD7 auch> und wird 0. Danach toggelt er dann nicht mehr, weil er ja 0 ist?
Ja, aber selbst das Zurückschalten auf 0 dürfte ja nicht beabsichtigt
gewesen sein.
@ Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
>Darauf, dass SBI ein read-modify-write ist,
OK.
> welches sich stets auf das>ganze Register bezieht (wie sonst sollte man es auch implementieren?),
Einspruch! Das KANN man mittels Hardware-Bitmaske machen, die sowieso
gebraucht wird, um das einzelne Bit anzusprechen!
Wie es REAL aufgebaut ist, weiß nur Atmels Hardwareabteilung.
Jörg Wunsch schrieb:> Ja, aber selbst das Zurückschalten auf 0 dürfte ja nicht beabsichtigt> gewesen sein.
Aber PD7 wird nicht 0.
Wo kriege ich denn jetzt 644p her, die diesen Bug nicht haben?
mfg.
Thomas Eckmann schrieb:> Aber PD7 wird nicht 0.
OK, dann ist SBI auf PINx offenbar anders implementiert als auf anderen
Registern (schön, wenn alles so konsistent ist ;-).
Trotzdem ist ein |= auf PINx gefährlich: ob es den gewünschten Zweck
erfüllt oder nicht, hängt nun davon ab, ob der Compiler es als SBI
umsetzt oder nicht, und damit beispielsweise von den Optimierungs-
einstellungen. Die explizite Zuweisung nur des zu toggelnden Bits
ist dagegen sicher, dass sie genau das tut.
Jörg Wunsch schrieb:> Trotzdem ist ein |= auf PINx gefährlich: ob es den gewünschten Zweck> erfüllt oder nicht, hängt nun davon ab, ob der Compiler es als SBI> umsetzt oder nicht,
Ach komm. Daß der Compiler das bei -0s richtig auf sbi umsetzt und es
ohne Optimierung nicht tut, weisst du besser als ich.
Und solange man das weiss, kann man das auch bedenkenlos einsetzten.
Wenn man allerdings Zweifel daran hat, ist die Lösung nicht, es mit "="
sondern sbi mit Inline-Assembler zu implementieren.
Sonst würde das nämlich bedeuten, daß man diese performantere Variante
des Toggelns in C gar nicht nutzen kann.
mfg.
Thomas Eckmann schrieb:> Sonst würde das nämlich bedeuten, daß man diese performantere Variante> des Toggelns in C gar nicht nutzen kann.
Jetzt muss ich mal fragen: häh?
Warum kann man diese denn nicht benutzen?
Ein simples
PINB = 1;
toggelt völlig problemlos PB0, egal ob mit oder ohne Optimierungen.
(Ohne Optimierung allerdings kaum wirklich performanter, als wenn
man gleich PORTB ^= 1; schreibt.)
@ Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
>Jörg Wunsch schrieb:>> Trotzdem ist ein |= auf PINx gefährlich: ob es den gewünschten Zweck>> erfüllt oder nicht, hängt nun davon ab, ob der Compiler es als SBI>> umsetzt oder nicht,
Sehe ich auch so. Es ist syntaktisch ein-eindeutig.
>Ach komm. Daß der Compiler das bei -0s richtig auf sbi umsetzt und es>ohne Optimierung nicht tut, weisst du besser als ich.
Jetzt wissen wir es alle.
>Und solange man das weiss, kann man das auch bedenkenlos einsetzten.
Nö. Das ist eine schöne Stolperfalle, hier ausnahmsweise mal umgekehrt.
Ohne Optimierung läuft sie NICHT, nur mit Optimierung. Sowas STINKT nach
Schuß ins Knie und unsauberen Methoden.
>Wenn man allerdings Zweifel daran hat, ist die Lösung nicht, es mit "=">sondern sbi mit Inline-Assembler zu implementieren.
Quark.
>Sonst würde das nämlich bedeuten, daß man diese performantere Variante>des Toggelns in C gar nicht nutzen kann.
Quark die IIte. Siehe oben!
Jörg Wunsch schrieb:> PINB = 1;
ergibt aber
PINB = 1;
3c: 81 e0 ldi r24, 0x01 ; 1
3e: 86 bb out 0x16, r24 ; 22
Aber das will ich nicht haben.
Ich will das:
PINB |= 1;
3c: b0 9a sbi 0x16, 0 ; 22
weil es kürzer ist.
Ein simples PORTB ^= 1; tut es übrigends auch.
Falk Brunner schrieb:> Quark.
Ja ne is klar.
Mit Quark scheinst du dich auszukennen:
> Nö. Das ist eine schöne Stolperfalle, hier ausnahmsweise mal umgekehrt.> Ohne Optimierung läuft sie NICHT, nur mit Optimierung. Sowas STINKT nach> Schuß ins Knie und unsauberen Methoden.> Ohne Optimierung läuft sie NICHT, nur mit Optimierung.
Wo ist das Problem, solange ich das weiss?
mfg.
@ Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
>> PINB = 1;>ergibt aber> PINB = 1;> 3c: 81 e0 ldi r24, 0x01 ; 1> 3e: 86 bb out 0x16, r24 ; 22
Ohne Optimierung!
>Aber das will ich nicht haben.>Ich will das:>PINB |= 1;> 3c: b0 9a sbi 0x16, 0 ; 22
MIT Optimierung!
>weil es kürzer ist.
2 Byte mehr im Flash, gleich Anzahl Takte ;-)
>> Ohne Optimierung läuft sie NICHT, nur mit Optimierung.>Wo ist das Problem, solange ich das weiss?
Wenn du das nicht als Problem erkennst ist das dein Problem ;-)
Und das alles wegen einem einzigen | Zeichen.
Das wird ein neuer Sparklassiker, gleich nach den LED-Vorwiderständen .
. .
Scheinbar greift das neue Sparpaket der Bundesregierung selbst hier im
Forum schon!
Thomas Eckmann schrieb:> Ich will das:> PINB |= 1;> 3c: b0 9a sbi 0x16, 0 ; 22>> weil es kürzer ist.
Erbsenzähler. ;-)
> Ein simples PORTB ^= 1; tut es übrigends auch.
Allerdings noch länger.
Habe gerade gesehen, dass das Datenblatt die SBI-Variante in der Tat
sanktioniert:
1
Note that the SBI instruction can be used to toggle one single
2
bit in a port.
Damit ist es zumindest sicher, dass es sich immer so benimmt.
Hier das Gegenstück beim ADIF-Bit:
1
· Bit 4 ADIF: ADC Interrupt Flag
2
3
[...] Beware that if doing a Read-Modify-Write on ADCSRA,
4
a pending interrupt can be disabled. This also applies if the SBI
Falk Brunner schrieb:> Das wird ein neuer Sparklassiker, gleich nach den LED-Vorwiderständen
Ach, LED-Vorwiderstände habe ich auch schon eingespart. :-) War mir
allerdings sicher, dass die Kanalwiderstände der Ausgangsstufen
dann problemlos deren Funktion übernehmen konnten. Letztlich ist
es ja egal, an welcher Stelle die Energie verheizt wird.
Jörg Wunsch schrieb:> Allerdings noch länger.
Deswegen nimmt man ja auch PIN.
Falk Brunner schrieb:> Wenn du das nicht als Problem erkennst ist das dein Problem ;-)
Es ist eben nicht mein "Problem".
Dann musst du auch den Takt auf einen festen Wert zementieren. Denn wenn
man vergisst F_CPU zu definieren oder ggf. zu ändern, kann das noch viel
schlimmere Auswirkungen haben, als festzustellen, daß sich plötzlich der
Pullup von einem Taster in Wohlgefallen aufgelöst hat. Dann muss man
natürlich wissen, woran es liegen kann. Aber das ist bei einer falschen
Baudrate auch nicht anders.
Falk Brunner schrieb:> Das wird ein neuer Sparklassiker, gleich nach den LED-Vorwiderständen .
Das ist ja nun wirklich Quark. Aber trotzdem nicht schlecht. Immerhin
nicht vor den Vorwiderständen.
Jörg Wunsch schrieb:> Damit ist es zumindest sicher, dass es sich immer so benimmt.
Siehste. Die Stelle wollte ich auch gerade rauskopieren.
mfg.
@ Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
>[...] Beware that if doing a Read-Modify-Write on ADCSRA,>a pending interrupt can be disabled. This also applies if the SBI>and CBI instructions are used.
MOMENT! Heißt dass, wenn ich per SBI/CBI auf ein ANDERES Bit als ADIF
zugreife, dass ADIF gelöscht wird wenn es aktiv (=1) ist, weil die
Maskierung der Bits in dem Befehl buggy ist? Also die Hardware die Daten
des Registers liest, nur das eine Bit manipuliert und alles
zurückschreibt, auch das schon gesetzte ADIF, was zu seiner Löschung
führt? Hmm, Bug oder Feature? Ok, jetzt verstehe ich deinen Einwand.
Hmm, für normale Register ist das ja kein Problem, für Spezialregister
mit "clear on 1" schon. Da für die einzelnen, unterschiedlichen
Spezialregister extra Dekoder einzubauen wäre wahrscheinlich zu
aufwändig, wenn gleich möglich.
Ist aber ein zusätzliches Argument FÜR
PINB = 1;
!!!
Falk Brunner schrieb:> MOMENT! Heißt dass, wenn ich per SBI/CBI auf ein ANDERES Bit als ADIF> zugreife, dass ADIF gelöscht wird wenn es aktiv (=1) ist,
Ja.
> weil die> Maskierung der Bits in dem Befehl buggy ist?
Nein. Die ist nicht buggy. Ein Bug wäre es, wenn das Verhalten
nicht so (oder gar anders) dokumentiert wäre. Es ist aber so
dokumentiert, damit ist es per se kein Bug, sondern bestenfalls
unschön. ;-)
Immer dran denken: "An undocumented feature is called a bug."
Falk Brunner schrieb:> Quizzfrage, was der Compiler aus>> PINB |= (1 << 2);>> macht?>> sbi PINB, 2>> oder>> in r16, PINB> ORI r16, 0x04> out PINB, r16
beides ist möglich, und sogar indirekter Zugriff ist denkbar.