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.
Mit einem oscyluskop. Was genau mache ich den bei der kalibrierung falsch?
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:
1 | WaitForDown:
|
2 | adiw XL,1 ; (2) Increment von X Pointer Register |
3 | in R19, PINB ; (1) Lese Pins in R19 |
4 | andi R19, 0b00000010 ; (1) Isoliere Pin6 (PB1) |
5 | brne WaitForDown ; (2) Wenn weiterhin Signal anliegt, weiter zählen. |
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.
:
Bearbeitet durch User
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.
Andi liefert auch ein ergebnis, das ich mit brne auswerten kann? Das war mir nicht bekannt. Danke
@ Wolfgang: Mit dem programm was ich oben angegeben hab. Dabei habe ich die signalläge mit den buttons laaaaangsam an 1ms angepasst.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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" ?
:
Bearbeitet durch User
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.
Armin A. schrieb: > Mit dem CPI hat es ja funktioniert. Und warum soll es mit andi nicht funktionieren ? Probieren:
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. |
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. :-)
:
Bearbeitet durch User
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 | st Y+, xl |
2 | st Y+, xh |
3 | clr xl |
4 | clr xh |
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...
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
Armin A. schrieb: > R19 ist aber gleich 0b00000010. Sollte er dann nicht eigentlich die > schleife verlassen? Nein. Bei mir:
1 | andi r19, 0b00000010 ;* Z = Set if the result is $00; cleared otherwise. |
2 | brne WaitForDown ;* Branches relatively to PC if Z is cleared |
Bei dir:
1 | andi r19, 0b00000010 ;* Z = Set if the result is $00; cleared otherwise. |
2 | CPI R19, 0x00 ;* Z = Set if the result is $00; cleared otherwise. |
3 | BREQ Finish ;* Branches relatively to PC if Z is set. |
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 | LDI R16, 0b00000010 |
2 | OUT PORTB, R16 ; PullUp |
Und schon hast du definierte Zustände und einigermassen saubere Flanken.
:
Bearbeitet durch User
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
Armin A. schrieb: > [...] > Mir fällt es halt noch schwer in der Beschreibung der Befehle heraus zu > lesen, was die genau machen. > [...] Vielleicht ist dieser Beitrag von mir für Dich noch hilfreich: Beitrag "Re: Zero Flag und Conditional Branches"
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?
Armin A. schrieb: > Was mache ich falsch? Du pruckelst mit Controllern herum und schwänzt den Deutschunterricht.
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
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.