Ich habe einen Tiny13A den ich wie folgt eingestellt habe:
Fuse=
L: 0x3A
H: 0xFF
E:
LB: 0x3F
Heist, der ist auf 9,6MHz eingestellt und behält den EEPROM bei.
Diesen Kaliriere ich via Buttons mit diesem Code:
;-----------------------------------
;- Interrupts -
;-----------------------------------
rjmp RESET ; Reset Handler
RETI ; IRQ0 Handler
RETI ; PCINT0 Handler
RETI ; Timer0 Overflow Handler
RETI ; EEPROM Ready Handler
RETI ; Analog Comparator Handler
RETI ; Timer0 CompareA Handler
RETI ; Timer0 CompareB Handler
RETI ; Watchdog Interrupt Handler
RETI ; ADC Conversion Handler
;-----------------------------------
;- Reset Interrupts -
;-----------------------------------
RESET:
SBIC EECR,EEPE ; Prüfe Zugriff auf EEPROM
RJMP RESET ; Versuh nochmal, wenn nicht bereit
LDI R24, 0x00 ; Definiere Adresse
OUT EEARL,R24 ; Setze Adresse
SBI EECR,EERE ; Definiere Leden
IN R16,EEDR ; Lese Adresse in Register
CPI R16, 0xFF
BREQ JumpOSCCAL
OUT OSCCAL, R16 ; Setze Calibrierung
rjmp JumpSave
JumpOSCCAL:
SBIC EECR,EEPE ; Ist EEPROM bereit
RJMP JumpOSCCAL ; Wenn nein, dann wiederholen
LDI R24, 0x00 ; Definiere Adresse 0
OUT EEARL, R24 ; Setzte Adresse
IN R16, OSCCAL ; Lese ASCCAL
OUT EEDR, R16 ; Übergebe Wert
SBI EECR,EEMPE ; Aktiviere Schreiben
SBI EECR,EEPE ; Schreibe
JumpSave:
LDI r16, low (RAMEND)
OUT SPL, r16 ; Setzt den StackPointer auf Anfang
LDI r16, 0b00001000
OUT DDRB, r16 ; Setzt PB3->Output
LDI R16, 0b00000000
OUT PORTB, R16 ; PullUp
LDI XH, 0x00
LDI XL, 0x00
LDI YL, 0xC0
LDI YH, 0x03
LDI ZL, 0x00
;-----------------------------------
;- Main-Loop -
;-----------------------------------
Aus:
CBI PORTB, 0x03 ; Löschen des Ausgangs
in R19, PINB ; Lese Pins in R19
andi R19, 0b00000001; Isoliere PB0
CPI R19, 0x00 ; Vergleiche ob Signal anliegt
BREQ CheckDown ; Wenn kein UpSignal dan check Down
CPI R20, 0x01 ; Prüfen, ob Signal bereits behandelt
BREQ CheckDown ; Wenn behandelt, dann check Down
LDI R20, 0x01 ; Wenn noch nicht behandelt, dann behandeln
IN R21, OSCCAL ; Lese OSCCAL
INC R21 ; Incrementiere R21
OUT OSCCAL, R21 ; Schreibe neuen Wert in OSCCAL
CheckDown:
IN R19, PINB ; Lese Pins in R19
ANDI R19, 0b00000010; Isoliere PB1
CPI R19, 0x00 ; Vergleiche ob Signal anliegt
BREQ CheckNone ; Wenn kein DownSignal dan check None
CPI R20, 0x01 ; Prüfe ob Signal bereits behandelt
BREQ CheckNone ; Wenn behandelt, danncheck None
LDI R20, 0x01 ; Wenn noch nicht behandelt, dann behandeln
IN R21, OSCCAL ; Lese OSCCAL
DEC R21 ; Decrementiere R21
OUT OSCCAL, R21 ; Schreibe neuen Wert in OSCCAL
CheckNone:
IN R19, PINB ; Lese Pins in R19
ANDI R19, 0b00000011; Isoliere PB0 & PB1
CPI R19, 0x00 ; Vergleiche ob Signal anliegt
BRNE JumpWrite ; Wenn Signal anliegt, Überspringe Schreiben
CPI R20, 0x01 ; Vergleiche, ob vorher ein Signal anlag
BREQ TryWrite ; Wenn Signal anlag, Schreibe
rjmp JumpWrite ; Wenn Signal nicht anlag, überspringe Schreiben
TryWrite:
SBIC EECR,EEPE ; Ist EEPROM bereit
RJMP TryWrite ; Wenn nein, dann wiederholen
LDI R24, 0x00 ; Definiere Adresse 0
OUT EEARL, R24 ; Setzte Adresse
IN R21, OSCCAL
OUT EEDR, R21 ; Übergebe Wert
SBI EECR,EEMPE ; Aktiviere Schreiben
SBI EECR,EEPE ; Schreibe
LDI R20, 0x00 ; Resette den Fläg ob schon behandelt wurde
JumpWrite:
ADIW XL, 1 ; Addiere
CP XL, YL ; Vergleiche Wert
CPC XH, YH ;
BREQ An ; Wenn JA, dann an!
rjmp Aus ; Wenn NEIN, dann weiter!
An:
SBI PORTB, 0x03 ; (2) Schalte Ausgang
NOP ; (1)
SBIW XL, 1 ; (2) Subtrahiere
CP XL, ZL ; (1) Vergleiche Wert
CPC XH, ZL ; (1)
BREQ Aus ; (1/2) Wenn JA, dann aus!
rjmp An ; (2) Wenn NEIN, dass weiter!
Hier wird zuerst das X-Register auf 0x03C0 gezählt. Während dessen ist
Signal = 0
Danach wird das X-Register bis auf 0x00 runtergesetzt und in der Zeit
gibt er Das Signal 1 aus.
Er braucht für ein mal X runter zu zählen 10 Opperationen heist, we
sollte exact 1ms Signal = 1 geben. (Wenn er richtig kalibriert ist)
Das habe ich auch so durchgeführt. Heist er braucht jetzt:
960 mal 10 Opperationen. Sind gesammt 9600 Op./ms.
sollten demnach 9,6MHz sein.
Die Calibrierung (OSCCAL) schreibe ich ins EEPROM.
In einem anderen Programm lese ich dieses aus und schreibe es in das
OSCCAL-Register.
Dort wird ein PWM-Signall ausgewertet, was genau 1ms Signal = 1 liefert.
Dies passiert in diesem Stück:
WaitForDown:
ADIW XL,1 ; (2) Increment von X Pointer Register
in R19, PINB ; (1) Lese Pins in R19
andi R19, 0b00000010 ; (1) Isoliere Pin6 (PB1)
CPI R19, 0x00 ; (1) Vergleiche ob Signal anliegt
BREQ Finish ; (1/2) Wenn Signal weg, dann Fertig
rjmp WaitForDown ; (2) Wenn weiterhin Signal anliegt, weiter zählen.
Diese Schleife benötigt 8 Opperationen. Wenn ich das laufen lasse, bis
das Signal wieder auf 0 fällt (also 1ms) zählt das X-Register 0x05D9
(1497).
Heist der benötigt 1497 * 8 = 11976 Op./ms
Heist 11976000Hz = 11,976MHz.
Ich hätte jetzt erwartet, dass er 1200 (0x04B0) im X-Register stehen
hat.
Was mache ich falsch?
Armin A. schrieb:> Dort wird ein PWM-Signall ausgewertet, was genau 1ms Signal = 1 liefert.
Und das hast du womit ausgemessen ?
> Was mache ich falsch?
Kalibrierung.
Armin A. schrieb:> Mit einem oscyluskop.
So ein Messgerät kenne ich zwar nicht, aber ein Screenshot von 1ms
Impuls wäre nicht schlecht.
> Was genau mache ich den bei der kalibrierung falsch?
Das sage ich dir wenn ein Screenshot von "oscyluskop" vorliegt.
Armin A. schrieb:> Was genau mache ich den bei der kalibrierung falsch?
Irgendetwas wird schon falsch sein.
Atmel sagt folgendes:
1
To ensure stable operation of the MCU the calibration value should be changed in small steps. A
2
variation in frequency of more than 2% from one cycle to the next can lead to unpredicatble
3
behavior. Changes in OSCCAL should not exceed 0x20 for each calibration. It is required to
4
ensure that the MCU is kept in Reset during such changes in the clock frequency
Vergleiche mal den Wert, der nach dem Reset ins OSCCAL geladen wird
(Factory Value) mit dem Wert welches du aus dem Eeprom reinschreibst.
Selbstverständlich kann man nicht gleich von 0x30 auf 0x70 gehen.
Messe mal hiermit, es ist schneller und somit genauer:
Sind 6 Takte, bei 1ms und 9.6MHz sollte XH:XL genau bis 1600 zählen.
Natürlich lässt man vor dem Messvorgang die Tiny einen (oder mehrere)
Impulse von 1600*6 Takten ausgeben, misst die Dauer mit "oscyluskop"
und ist etwas schlauer danach...
P.S.
Natürlich kann Eeprom write (gerade beim kalibrieren) fehlschlagen,
deswegen prüft man normallerweise ob auch der richtige Wert
reingeschrieben wurde - du machst das aber nicht.
Hallo,
Ok, ich werde das mal probieren.
Diesen impuls lasse ich ja permanent ausgeben.
Demnach sollten da ja ausreichend takte zwischen liegen. Der OSCCAL
wurde auch immer nur um 1 verändert.
Armin A. schrieb:> Demnach sollten da ja ausreichend takte zwischen liegen. Der OSCCAL> wurde auch immer nur um 1 verändert.
Ja, beim schreiben aber wahrscheinlich nicht beim lesen, deswegen
macht man folgendes beim Neustart:
Marc V. schrieb:Vergleiche mal den Wert, der nach dem Reset ins OSCCAL geladen wird
(Factory Value) mit dem Wert welches du aus dem Eeprom reinschreibst.
Und dann laaaaangsam (um 1, höchstens um 2) rauf- oder runterschrauben,
bis OSCCAL den gewünschten Wert hat.
Marc V. schrieb:> Selbstverständlich kann man nicht gleich von 0x30 auf 0x70 gehen.
Marc V. schrieb:> WaitForDown:> adiw XL,1 ; (2) Increment von X Pointer Register> in R19, PINB ; (1) Lese Pins in R19> andi R19, 0b00000010 ; (1) Isoliere Pin6 (PB1)> brne WaitForDown ; (2) Wenn weiterhin Signal anliegt, weiter> zählen.
Wenn ich das mache, steht im X-Register immer 0x0001. Demnach würde ich
sagen, dass das CPI eigentlich dahin gehört.
Der alte Wert im OSCCAL ist 0x4F der direkt auf 0x5A gesetzt wird.
Verstehe ich euch richtig, dass ich den dann auch langsam hochzählen
muss? Dache der Pendelt sich dann schon ein.
Armin A. schrieb:> Wenn ich das mache, steht im X-Register immer 0x0001. Demnach würde ich> sagen, dass das CPI eigentlich dahin gehört.
Demnach würde ich sagen, dass an PinB.1 eine Log.0 anliegt.
Und woher weisst du, dass in X-Reg 0x0001 steht ?
Armin A. schrieb:> Der alte Wert im OSCCAL ist 0x4F der direkt auf 0x5A gesetzt wird.
Das geht normalerweise (muss aber nicht unbedingt) in die Hose.
> Verstehe ich euch richtig, dass ich den dann auch langsam hochzählen> muss? Dache der Pendelt sich dann schon ein.
Ja, du verstehst richtig.
Übrigens, wer ist "euch" ?
Marc V. schrieb:> Demnach würde ich sagen, dass an PinB.1 eine Log.0 anliegt.> Und woher weisst du, dass in X-Reg 0x0001 steht ?
Das wird in INT0 Interrupt bei steigender Flanke ausgeführt. Demnach
sollte da ein Signal sein. Mit dem CPI hat es ja funktioniert.
Ich weis das, da ich bei einer falenden Flanke XH & XL ins EEPROM
schreibe. und da steht (0x)0001 an entsprechender Stelle.
Was glaubst du wie und wann dein Programm aus dem loop rauskommt ?
> Das wird in INT0 Interrupt bei steigender Flanke ausgeführt. Demnach> sollte da ein Signal sein.
Tja.
Steigende Flanke ist etwas anderes als Signalpegel.
a) INT0 und PinB.1 haben (vielleicht) verschiedene Schaltschwellen.
Mit cpi hast du das (vielleicht) ausgeglichen.
b) Dein Signal hat unsaubere Flanken.
c) Du hast am falschen Pin gemessen. :-)
Marc V. schrieb:> Was glaubst du wie und wann dein Programm aus dem loop rauskommt ?
Wenn kein Signal mehr anliegt, wird die Schleife verlassen.
> Tja.> Steigende Flanke ist etwas anderes als Signalpegel.>> a) INT0 und PinB.1 haben (vielleicht) verschiedene Schaltschwellen.> Mit cpi hast du das (vielleicht) ausgeglichen.
An PinB.1 liegt ein PWM-Signal an. Dort liegt mindestens 1ms ein Signal
an.
>> b) Dein Signal hat unsaubere Flanken.
Mein Oszilloskop zeigt eine saubere Flanke.
>> c) Du hast am falschen Pin gemessen. :-)
Was bei einem vorhandenen CPI aber auch nicht funktionieren sollte.
Armin A. schrieb:>> Was glaubst du wie und wann dein Programm aus dem loop rauskommt ?> Wenn kein Signal mehr anliegt, wird die Schleife verlassen.
Na also, war doch nicht so schwer...
Nur wird in dem obigem Beispiel die Schleife niemals verlassen.
>> b) Dein Signal hat unsaubere Flanken.> Mein Oszilloskop zeigt eine saubere Flanke.
a) Das ist kein richtiges Osziloskop.
b) Mit 200KHz Bandbreite kannst du keine Flanken schneller als
200/10 = 20 = 50us anständig messen - in diesem Fall bedeutet
es, dass überhaupt keine Flanken gemessen werden können.
>> a) INT0 und PinB.1 haben (vielleicht) verschiedene Schaltschwellen.>> Mit cpi hast du das (vielleicht) ausgeglichen.> An PinB.1 liegt ein PWM-Signal an. Dort liegt mindestens 1ms ein Signal> an.
Manomanoman...
Es geht nicht um die Dauer, sondern um Flanken.
Du kannst es auch folgendermassen probieren:
Es wird ein Signal mit 1ms Low und 1ms High angelegt.
Mit 64 Byt RAM und 64Byt EEP kann man nicht viel anfangen, aber es
reicht bestimmt, um z.B. 24 Zustände festzuhalten.
Wenn man bei der Adresse 0x60 (RAM) anfängt zu schreiben, kann bei
jedem Zustandswechsel mit:
1
stY+,xl
2
stY+,xh
3
clrxl
4
clrxh
die Dauer festgehalten werden, wobei es ziemlich uninteressant ist,
welche Adressen Low- und welche Highzustände enthalten.
Wichtig ist nur, dass die Low- und Highdauer in etwa gleich bleibt.
Nach 24 Flanken wird der RAM ins EEP kopiert und das wars dann.
Wenn Werte kleiner als 100 auftauchen, sind das unsaubere Flanken.
Wenn nicht, hast du irgendeinen anderen Fehler gemacht.
Aber dabei bedenken, dass mit mehr als 100ns Taktdauer nicht viel
erreicht werden kann.
P.S.
Vielleicht reicht es, wenn du beim PB.3 die Pullups einschaltest...
Marc V. schrieb:> Und warum soll es mit andi nicht funktionieren ?> Probieren: clr xl> clr xh> ldi r19,2> WaitForDown:> adiw XL,1 ; (2) Increment von X Pointer Register> andi R19, 0b00000010 ; (1) Isoliere Pin6 (PB1)> brne WaitForDown ; (2) Wenn weiterhin Signal anliegt, weiter> zählen.> Was glaubst du wie und wann dein Programm aus dem loop rauskommt ?
R19 ist aber gleich 0b00000010. Sollte er dann nicht eigentlich die
schleife verlassen?
Hm... Ich hab das noch nicht ganz verstanden.
Du meinst ich habe vielleicht unsaubere Flanken. Wenn ich doch den
Interrupt auf eine Steigende Flanke eingestellt habe, dann sollte der
doch wenn er ausgelöst wird (wobei es doch egal sein sollte ob die
Flanke sauber ist) auf PB1 eine logische 1 erkennen. Selbst wenn die
Flanke etwas Zeit benötigt, greift der Interrupt doch erst, Wenn die
logische 1 da ist, oder?
Was macht das CPI den anders, dass es damit funktioniert? Der CPI
Vergleicht doch nur ein Register mit einer Konstante!
Ich weis nicht, was du mit PB3 meinst.
Dein code springt raus, mein code springt wieder zum Anfang.
> Du meinst ich habe vielleicht unsaubere Flanken. Wenn ich doch den> Interrupt auf eine Steigende Flanke eingestellt habe, dann sollte der> doch wenn er ausgelöst wird (wobei es doch egal sein sollte ob die> Flanke sauber ist) auf PB1 eine logische 1 erkennen. Selbst wenn die> Flanke etwas Zeit benötigt, greift der Interrupt doch erst, Wenn die> logische 1 da ist, oder?
Ja.
Aber dann prüfst du doch auf logisches High und wenn die Flanke
unsauber ist, kann das eine Logische 0 ergeben.
Beispiel:
_______________ ---------- Abtasten PB.1
/---------------------------- Abtasten PB.1
/----------------------------- Abtasten PB.1
/\---------- Interrupt
/ \/------------------------------- Abtasten PB.1
__/
EDIT:
> Ich weis nicht, was du mit PB3 meinst.
Ja, jetzt weiss ich es auch nicht mehr.
Mal sind es PB.1 und PB.0, mal ist es nur PB.1 - war ein Tippfehler.
Aber in etwa so:
1
LDIR16,0b00000010
2
OUTPORTB,R16;PullUp
Und schon hast du definierte Zustände und einigermassen saubere
Flanken.
Marc V. schrieb:> Aber in etwa so: LDI R16, 0b00000010> OUT PORTB, R16 ; PullUp
Das ist in dem Programm bereits Bestandteil.
> Dein code springt raus, mein code springt wieder zum Anfang.
Das habe ich probiert. Dein Code springt raus! Genau dass ist es ja, was
mich wundert.
Hier was in meinem Programm ist
1
clr xl
2
clr xh
3
ldi r19,2
4
WaitForDown:
5
adiw XL,1 ; (2) Increment von X Pointer Register
6
andi R19, 0b00000010 ; (1) Isoliere Pin6 (PB1)
7
brne WaitForDown ; (2) Wenn weiterhin Signal anliegt, weiter zählen.
8
inc R18
9
rjmp WaitForDown
die Zeile "brne WaitForDown" springt nach WaitForDown. Ich hätte
erwartet, dass "inc R18" ausgehführt wird.
Armin A. schrieb:> die Zeile "brne WaitForDown" springt nach WaitForDown.
Natürlich, so soll es auch sein.
> Ich hätte erwartet, dass "inc R18" ausgehführt wird.
Wie soll das überhaupt gehen und warum hast du es erwartet ?
>> Dein code springt raus, mein code springt wieder zum Anfang.> Das habe ich probiert. Dein Code springt raus! Genau dass ist es ja, was> mich wundert.
Ja, was ist denn nun wahr ?
Springt raus oder springt nach WaitForDown ?
hm... BRNE heist ja "Branch if Not Equal". Würde für mich bedeuten, wenn
der Vergleich nicht gleich ist, springt er.
Konkret schaut der BRNE nur ob im Zero-Flag eine 0 oder 1 steht? Wenn
ja, sollte der derjenige, der die Bezeichnung BRNE gesetzt hat KEINE
weiteren Namen vergeben.
Mir fällt es halt noch schwer in der Beschreibung der Befehle heraus zu
lesen, was die genau machen.
Meinen Ansatz hatte ich aus Google.
Armin A. schrieb:> Konkret schaut der BRNE nur ob im Zero-Flag eine 0 oder 1 steht?
Ja.
> Wenn> ja, sollte der derjenige, der die Bezeichnung BRNE gesetzt hat KEINE> weiteren Namen vergeben.
Warum ?
Was ist daran unlogisch ?
Hi
>Meinen Ansatz hatte ich aus Google.
Also aus dritter Hand.
Warum verwendest du nicht das offizielle Dukument:
www.atmel.com/images/Atmel-0856-AVR-Instruction-Set-Manual.pdf
MfG Spess
Ich habe eine Vermutung, was meine Ursache ist.
Meine Buttons, um die Kalibrierung zu ändern hab ich auf PB0 & PB1
gelegt.
Mein Phänomen tritt erst auf, wenn ich den Tiny an meinem Programmer
hänge.
Werden die beiden Ports vom Programmer zum Lesen/Schreiben benutzt?
Hi
>Werden die beiden Ports vom Programmer zum Lesen/Schreiben benutzt?
Abgesehen von VCC und GND benutzt SPI MISO, MOSI, SCK und RESET. Was ist
an PIN0 und PIN1?
Der ATTiny13 ist zwar ganz schucklig, aber ein etwas größerer, bei dem
man die SPI-Pins exklusiv für diesen Zweck benutzt ist wesentlich
stressfreier.
MfG Spess