Light to frequency

wer

Neues Mitglied
02. Juli 2012
485
0
0
Sprachen
  1. Assembler
Hallo,

ich möchte einen TSL235R Sensor auslesen. Der Sensor liefert Frequenzen. In meinem Fall an der oberen Kante seines Vermögens, sagen wir zwischen 200 KHz und 1 MHz.

Welche Strategie ist dabei die beste?

Interruptgesteuert:

Ich dachte ich könnte entweder in einem Interrupt die steigenden Flanken zählen und im Hauptprogramm den Int einschalten, auf Ablauf einer Sekunde pollen und dann wieder abschalten.

Oder den Flankenwechsel manuell zählen und die Zählerei von einem Timer (+Zähler) begrenzen (1 Sekunde) lassen.

Oder einen Timer auf einen geigneten Startwert (2^16) setzen und bis zu dessen Ablauf zählen (ist wohl nicht so genau und benötigt noch eine Umrechnung.

Oder wie könnte das noch gehen?

Gleich noch eine zweite Frage:

Falls die zu messende Frequenz zu hoch ist, wie könnte ich sie hardwaremäßig auf einfache Weise halbieren, dritteln oder vierteln?
 
Hallo,

ich möchte einen TSL235R Sensor auslesen. Der Sensor liefert Frequenzen. In meinem Fall an der oberen Kante seines Vermögens, sagen wir zwischen 200 KHz und 1 MHz.

Welche Strategie ist dabei die beste?
Also das würde ich möglichst weit in Hardware laufen lassen.

Nimm dir 2 Timer. Einen 16Bit Timer als Zähler für den Takt des Sensors und einen 8Bit als Zeitliferant.

Der 16Bit nimmt also an seinem Takteingang (kann man auf nen Pin legen) den Takt des Sensors als Zähltakt entgegen.
Für den 16Bit würde ich zusätzlich eine Variable als Überlaufzähler (TOVFL-Interrupt) verwenden. Mit ner 8Bit-Variable kommst du dann insgesamt auf nen 24Bit-Zähler (16Bit über Hardware-Timer plus 8Bit über TOVFL-Int und Software)

Der 8Bit erzeugt dir über den Systemquarz des Atmels ein Zeitraster von zB 100ms als Meßfenster.

Wenn der 8Bit-Timer einen Interrupt auslöst, sicherst du den Zählerstand des 16Bit-Timers und der 8Bit-Überlaufsvariable in anderen Variablen. Dann stellst du den Timer und die 8Bit-Variable für die nächste Messung wieder auf Null.

Über die Zeit des Meßfensters vom 8Bit-Timer hast du dann ...

(16Bit-Timer + 65536 * 8Bit-Überlaufsvariable) / Zeit_des_Meßfensters_vom_8Bit-Timer = Impulse pro Sekunde

Also einen einfachen Frequenzzähler :cool:

Könnte man jetzt noch ein wenig verbessern. Das Prinzip sollte aber soweit klar sein ;)

Über einen Software-Interrupt die Impulse zählen kannst du bei den hohen Frequenzen absolut vergessen. Das wird nix. Die Arbeit und Fehlversuche kannst du dir sparen.

Gruß
Dino
 
Ich fange mal hinten an: Es gibt Zählerbausteine, die (vereinfacht gesagt) am Eingang Takte erhalten, und diese als Byte am Ausgang darstellen. Dessen Ausgänge toggeln dann halt in den 2erpotenzender Eingangsperiodenzeit.
Brauchst Du aber nicht.
Die üblichen AVR schaffen bis zu 20MHz - demnach hättest Du bei 1MHz max 20 Takte, bei 200kHz max 100 Takte für irgendwelche Verarbeitungen Zeit. Wenn Du dazwischen Zeiten messen lassen willst, hat der Prozessor viel zu tun. Selbst wenn Du innerhalb einer Timergenerierten Periode Takte Zählen lassen willst, bleibt nicht viel Rechenkapazität. Es gibt aber einen einfacheren Weg.
Du kannst einen Timer zum zählen der Flanken (im Hintergrund) verwenden (indem Du dessen Clock nicht aus dem Systemtakt ableitest, sondern aus einer Flanke an T0/T1). Allerdings mußt Du dann die Zeit mit einem 2ten Timer messen lassen. Wenn Dein Frequenzbaustein soundsooft pro s 'ne steigende(fallende) Flanke an T0 erzeugt, läuft Timer0 halt alle 256 Flanken über (8-bit-Timer). Alle 256 Flanken kann er also (bisher noch im Hintergrund) einen IRQ auslösen. In dieser ISR wertest Du jetzt den 2ten Timer aus, erhälst also den "Zeitverbrauch" für 256 Perioden des Frequenzbausteines.
Allerdings mußt Du Dir darüber im klaren sein, daß diese Methode den Mittelwert der letzten 256 Perioden abbildet, und Du (bei 200kHz) nur noch eine Aktualisierungsfrequenz von ca. 780Hz hast.

Edit: Dino war schneller, und hat die Timer andersrum genommen - und einen Timer gestreckt... aber im wesentlichen dasselbe.
Edit2: sicher ist es besser, fixe Zeitintervalle zu wählen (Überlauf des Zeitzählers), und die darin erfolgten Perioden zu zählen, insofern ist Dinos Weg bezüglich der weiteren Verarbeitung der Ergebnisse besser/eleganter.
 
Vielen Dank, Euch beiden!

Ich hatte halt auch die folgende Überlegung: Wenn ich meinen Controller mit 20MHz (oder 19,6608 MHz wegen USART) takte und wenn sehr viele Interrupts im Spiel sind, sagen wir bei einer Signalfrequenz von 1MHz und dann noch die, die durch die Zeit-Interrupts anfallen, dann habe ich ja mit jedem Interrupt einen Verwaltungsoverhead (Rückkehradresse pushen, reti, Register retten, Flags retten) und das läppert sich. Und ich hab' nur <20 Takt pro Int. Deshalb dachte ich, daß ich eventuell weiter komme mit pollen, zumal es so aussieht, als ob ich in dieser Zeit eh nichts anderes mehr machen kann.

Wahrscheinlich ist es aber eh nicht schlau, den Controller so an der Kapazitätsgrenze zu fahren, dehalb interessiert mich auch, wie ich mit wenig zusätzlichem Aufwand die anliegende Frequenz teilen kann.

Ich werde zunächst mal Dino's Variante umsetzen und schauen, wie weit ich komme.

Ah, noch eine Frage: Wenn die Signalfrequenz zu hoch wird was genau geschieht dann? Gehen mir dann Interrupts durch die Lappen oder werden die nachgeholt (wann?)? Wie kann ich das softwäremäßig registrieren? Das Verhalten wird ja auch sehr verschieden aussehen, je nachdem welcher Int verloren geht.
 
Ich fürchte, ich komme mit einem 8 Bit Timer ohne zusätzlichen Zähler nicht auf ein Zeitfenster von 100ms. Ist doch richtig,oder?
 
Ich fürchte, ich komme mit einem 8 Bit Timer ohne zusätzlichen Zähler nicht auf ein Zeitfenster von 100ms. Ist doch richtig,oder?
ist doch egal. Wenn du ein Zeitfenster von 95,7ms hast mußt du eben durch den Wert teilen. Das was zählt ist doch das Endergebnis. Wenn du dein Zeitfenster kleiner machst, dann hast du bei gleicher Sensorfrequenz auch weniger Takte in dem Zeitfenster gezählt. Der Quotient aus beiden bleibt auf jeden Fall gleich. Also versteif dich nicht so auf ein Zeitfenster von 100ms oder 200ms oder 50ms.

Takte pro Zeitfenster / Zeitfensterlänge = Sensorfrequenz

Und wenn ich mich recht entsinne dann kannst du bei ca 20MHz Systemtakt den Eingangstakt des Timers (also an T0 oder T1) auf die Hälfte oder ein Viertel des Systemtaktes hochjagen. Also kannst du etwa 5MHz problemlos an den Timereingang legen.

Dafür ist doch die ganze Hardwareunterstützung im Controller vorhanden. Was die Software nicht schaft macht die Hardware :cool:

Gruß
Dino
 
ist doch egal. Wenn du ein Zeitfenster von 95,7ms hast

Mir ist schon klar, daß es nicht auf die konkrete Zahl ankommt. Aber bei einem 19,6608 MHz Quarz komme ich bestenfalls auf 13 ms (exakt 1/75s). Das ist sehr wenig, hätte aber den Vorteil, daß ich bei meinem 16 Bit Timer keinen Überlauf befürchten muß.
 
Gib mal bitte ein paar mehr Fakten an:
1.: welcher Controller?
2.: Du willst den UART verwenden.
2a.: Als Sender und Empfänger?
2b.: Standard-Einstellung? (8Datenbits, kein Paritätsbit, je 1 Start und Stopbit)?
2c.: Welche Baudrate ist nötig (mit 20MHz sind problemlos 57.6kBaud drin, laut Datenblatt des Mega88 auch alles andere (Siehe Tabellen 20-12 und 20-3).
3.: Was soll sonst noch so an Interrupts/Hardware laufen können?
4.: In welcher Sprache soll programmiert werden?

bei 20MHz wären es 13,1072ms, aber egal - da liegen jedenfalls immer 256Takte*1024Prescaler=262144 CPU-Takte zwischen den TOV-ISR. In Dieser mußt Du ja lediglich die beiden 16bit-Zähler laden und ggf ins SRAM schreiben (Achtung, Reihenfolge!), und danach überschreiben (Achtung, Reihenfolge!). Dabei sollte nicht mal das SREG betroffen sein - Du brauchst eigentlich nur ein Register Retten/Wiederherstellen (wenn Du willst, noch ein Pointer-Doppelregister, aber eigentlich ist das nicht nötig).
Eventuell willst Du noch ein "neues Messergebnis"-Flag setzen lassen - beim Mega88 & co bietet sich für sowas immer das GPIOR0 an (wegen direktem Bit-Zugriff mit SBI/CBI bzw SBIS/SBIC...
 
Gib mal bitte ein paar mehr Fakten an:
1.: welcher Controller?
2.: Du willst den UART verwenden.
2a.: Als Sender und Empfänger?
2b.: Standard-Einstellung? (8Datenbits, kein Paritätsbit, je 1 Start und Stopbit)?
2c.: Welche Baudrate ist nötig (mit 20MHz sind problemlos 57.6kBaud drin, laut Datenblatt des Mega88 auch alles andere (Siehe Tabellen 20-12 und 20-3).
3.: Was soll sonst noch so an Interrupts/Hardware laufen können?
4.: In welcher Sprache soll programmiert werden?

1: ATmega168
2: Senden und Empfangen, Baudrate ist unkritisch, aber 57,6 KBaud wäre ok.
3: Usart Empfänger
4: Assembler

bei 20MHz wären es 13,1072ms, aber egal - da liegen jedenfalls immer 256Takte*1024Prescaler=262144 CPU-Takte zwischen den TOV-ISR. In Dieser mußt Du ja lediglich die beiden 16bit-Zähler laden und ggf ins SRAM schreiben (Achtung, Reihenfolge!), und danach überschreiben (Achtung, Reihenfolge!). Dabei sollte nicht mal das SREG betroffen sein - Du brauchst eigentlich nur ein Register Retten/Wiederherstellen (wenn Du willst, noch ein Pointer-Doppelregister, aber eigentlich ist das nicht nötig).
Eventuell willst Du noch ein "neues Messergebnis"-Flag setzen lassen - beim Mega88 & co bietet sich für sowas immer das GPIOR0 an (wegen direktem Bit-Zugriff mit SBI/CBI bzw SBIS/SBIC...
Was ist mit CLT und SET? Welche Befehle beeinflußen diese Flags sonst noch?
 
Meinst Du jetzt nur das T-Flag?
BST/BLD
BCLR/BSET
und natürlich ein direkter/indirekter Schreibbefehl auf die SRAM-Adresse von SREG
 
Meinst Du jetzt nur das T-Flag?
BST/BLD
BCLR/BSET
und natürlich ein direkter/indirekter Schreibbefehl auf die SRAM-Adresse von SREG
Ich denke, es gibt doch keinen Befehl, der das T-Flag nebenbei setzt oder löscht, wie z.B. ADD das C-Flag setzen kann, wenn ein Übertrag zu addieren ist. D.h. daß dieses Flag auch gut geeignet ist für den oben genannten Zweck:
Code:
     SET
     ;Timer starten
Wait:
     BRTS   Wait

Und im Timeroverflow-Int dann nur ein

Code:
     CLT
     RETI
 
Ich poste hier mal einen ersten Entwurf:

Code:
.INCLUDE "m168def.inc"

.EQU	Fcpu		= 19660800    

.DEF	Temp		= R16
.DEF	T1ovflCounter	= R15
.DEF	SregSave	= R14

.CSEG
.ORG	0

	jmp	Reset	; External pin, power-on reset, brown-out reset and watchdog system reset
	reti	;jmp	Int0	; External interrupt request 0
	reti	;jmp	Int1	; External interrupt request 1
	reti	;jmp	PCInt0	; Pin change interrupt request 0
	reti	;jmp	PCInt1	; Pin change interrupt request 1
	reti	;jmp	PCInt1	; Pin change interrupt request 2
	reti	;jmp	Wdt	; Watchdog time-out interrupt
	reti	;jmp	T2cmpA	; Timer/Counter2 compare match A
	reti	;jmp	T2cmpB	; Timer/Counter2 compare match B
	jmp	T2ovfl	; Timer/Counter2 overflow
	reti	;jmp	T1capt	; Timer/Counter1 capture event
	reti	;jmp	T1cmpA	; Timer/Counter1 compare match A
	reti	;jmp	T1cmpB	; Timer/Counter1 compare match B
	jmp	T1ovfl	; Timer/Counter1 overflow
	reti	;jmp	T0cmpA	; Timer/Counter0 compare match A
	reti	;jmp	T0cmpB	; Timer/Counter0 compare match B
	reti	;jmp	T0ovfl	; Timer/Counter0 overflow
	reti	;jmp	SPI	; serial transfer complete
	reti	;jmp	RxUsart	; USART, Rx complete
	reti	;jmp	UdreUsart	; USART, data register empty
	reti	;jmp	TxUsart	; USART, Tx complete
	reti	;jmp	Adc	; ADC conversion complete
	reti	;jmp	Eeprom	; EEPROM ready
	reti	;jmp	Acomp	; Analog comparator
	reti	;jmp	TWI	; 2-wire serial interface
	reti	;jmp	SPM	; Store program memory ready

Reset:
    	ldi	Temp, HIGH(RAMEND)	; Stack initialisieren
	out	SPH, Temp
	ldi	Temp, LOW(RAMEND)
	out	SPL, Temp

; DDRD PD5 auf Input
; Pullups?

	ldi	Temp, 1<<TOIE1			; enable timer1 interrupts
	sts	TIMSK1, Temp
	ldi	Temp, 1<<TOIE2			; enable timer2 interrupt
	sts	TIMSK2, Temp
	sei

	rcall	GetLightFreq

; Ergenis steht jetzt in: T1ovflCounter:TCNT1H:TCNT1L
; Solange Timer2 nur 1/75s läuft ist T1ovflCounter leer

Doit:
	jmp	Doit

GetLightFreq:
	clr	Temp					; Timer 1 löschen
	sts	TCNT1L, Temp
	sts	TCNT1H, Temp
	sts	TCNT2, Temp				; Timer 2 löschen
	ldi	Temp, 1<<CS12 | 1<<CS11 | 1<<CS10	; T1=PD5 steigende Flanke
	sts	TCCR1B, Temp
	ldi	Temp, 1<<CS22 | 1<<CS20		; Vorteiler 1024
	sts	TCCR2B, Temp
	set
WaitTSL:
	brts	WaitTSL
	clr	Temp
	sts	TCCR1B, Temp
	sts	TCCR2B, Temp
	ret

T1ovfl:
	in	SregSave,SREG ; Statusregister sichern
	inc	T1ovflCounter
	out	SREG, SregSave
	reti

T2ovfl:
	clt
	reti

Die folgenden Fragen habe ich noch:
- Was ist mit den Pullups von PD5? Auslassen, oder?
- Müssen die Timerregister gelöscht werden, wie oben getan, oder werden die automatisch gelöscht? Wo?
- In welchen Situationen muß man den Vorteiler reseten?

Ich hoffe, ich habe keine all zu großen Böcke geschossen. :eek:
 
Wie gesagt, Befehle die ein Byte ins SREG schreiben können (also als Adresse das SREG (0x3F) akzeptieren - ST, ST+/-, STS, OUT), können natürlich auch das darin enthaltene T-Flag beeinflussen. Dann natürlich CLT und SET, klar, sind ja dazu da. BitLoad (BLD) und BitStore (BST) sind Befehle, die ein Rigisterbit in das T-Flag kopieren, oder umgekehrt - insofern verändert BST also auch das T-Flag.
Dann gibts noch Bit-Clear-in-SREG (BCLR) bzw Bit-Set-in-SREG (BSET), welche jedes einzelne Bit in SREG setzen/löschen können, also logischerweise auch Bit6.
Speicherzugriffe mit dem Ramp-Register analog zu ST.

Aber warum willst Du da jetzt (schon wieder?) so'ne Warteschreife anbinden?
Warum
"Tue nichts bis T=0"?
"mach irgendwas"
"zurück nach oben"
Warum nicht
"Wenn T=0 -> (tue lauter lustige Sachen)"
"mache mit was anderem weiter"
"zurück nach oben"

Edit: den letzten Beitrag hab ich noch nicht gelesen... später
 
Aber warum willst Du da jetzt (schon wieder?) so'ne Warteschreife anbinden?
Warum
"Tue nichts bis T=0"?
"mach irgendwas"
"zurück nach oben"
Warum nicht
"Wenn T=0 -> (tue lauter lustige Sachen)"
"mache mit was anderem weiter"
"zurück nach oben"

Na letztlich will ich ein Unterprogramm haben, das mir die Frequenz liefert. Wenn die Timer fertig gezählt haben, dann multipliziere ich noch mit 75 und liefere das Ergebnis (3 Bytes) per RS232 an den PC. Mach mal ein simples Beispiel (Pseudocode) wie Du Dir das denkst.
 
bei 20MHz wären es 13,1072ms, aber egal - da liegen jedenfalls immer 256Takte*1024Prescaler=262144 CPU-Takte zwischen den TOV-ISR. In Dieser mußt Du ja lediglich die beiden 16bit-Zähler laden und ggf ins SRAM schreiben (Achtung, Reihenfolge!), und danach überschreiben (Achtung, Reihenfolge!).

Ich denke die ganze Zeit noch über das nach, was Du hier geschrieben hast!

Offensichtlich würdest Du die Timer nach erfolgter Zählung gar nicht abschalten, deshalb Dein Hinweis (Achtung, Reihenfolge!). Du speicherst also die aktiven Zähler und hast dann immer im SRAM den letzten gemessenen Wert. Das hat was für sich, wenn man den Wert nicht nur ab und zu benötigt UND wenn es problemlos klappt.

Zur Reihenfolge: Probleme kann es doch eigentlich nur geben, wenn das niederwertige Byte gerade überläuft. Speichert man in der Reihenfolge H/L, dann kann
folgendes passieren:

Zählerstand: 0x00FF -> SRAM: 0x00??
Zählerstand: 0x0100 -> SRAM: 0x0000 ; Fehler 256

Andererseits, wenn man in der Reihenfolge L/H speichert:

Zählerstand: 0x00FF -> SRAM: 0x??FF
Zählerstand: 0x0100 -> SRAM: 0x01FF ; Fehler 255 (auch nicht viel besser!)

Das heißt doch aber, daß man den Zähler zum Speichern ausschalten muß, oder?
 
Was hältst Du davon:
Man speichert 3 Bytes: H1/L/H2 (also das High-Byte zweimal).
Wenn der Meßwert dann weiter gereicht wird, kann in aller Ruhe der Abstand zwischen H2/L und H1/L geprüft werden und entweder H2/L oder H1/L geliefert werden.

Also so

((H2/L - H1/L) < 2) ? H2/L : H1/L

PS Wird natürlich bei einem 24-Bit Wert noch ein wenig komplexer!
 
...Offensichtlich würdest Du die Timer nach erfolgter Zählung gar nicht abschalten, deshalb Dein Hinweis (Achtung, Reihenfolge!). Du speicherst also die aktiven Zähler und hast dann immer im SRAM den letzten gemessenen Wert. Das hat was für sich, wenn man den Wert nicht nur ab und zu benötigt UND wenn es problemlos klappt.
den 8bit-Zeit-Timer würde ich durchlaufen lassen - der erzeugt Dir die äquitemporalen Perioden (von eventuellen Verzögerungen durch noch nicht beendete andere Interrupts mal abgesehen, diese sollten also auch möglichst kurz sein). Der 16bit-Frequenz-Zähler sollte eigentlich gar nicht überlaufen können, da er ja immer zurückgesetzt wird (Überlauf eben erst ab ca. 5MHz)
Zur Reihenfolge: Probleme kann es doch eigentlich nur geben, wenn das niederwertige Byte gerade überläuft. Speichert man in der Reihenfolge H/L, dann kann
folgendes passieren:

Zählerstand: 0x00FF -> SRAM: 0x00??
Zählerstand: 0x0100 -> SRAM: 0x0000 ; Fehler 256

Andererseits, wenn man in der Reihenfolge L/H speichert:

Zählerstand: 0x00FF -> SRAM: 0x??FF
Zählerstand: 0x0100 -> SRAM: 0x01FF ; Fehler 255 (auch nicht viel besser!)
Das heißt doch aber, daß man den Zähler zum Speichern ausschalten muß, oder?
Deswegen ja die Reihenfolge, Aus dem Datenblatt des Mega88/...:
16.3Accessing 16-bit registers The TCNT1, OCR1A/B, and ICR1 are 16-bit registers that can be accessed by the AVR CPU via the 8-bit data bus. The 16-bit register must be byte accessed using two read or write operations. Each 16-bit timer has a single 8-bit register for temporary storing of the high byte of the 16-bit access. The same temporary register is shared between all 16-bit registers within each 16-bit timer. Accessing the low byte triggers the 16-bit read or write operation. When the low byte of a 16-bit register is written by the CPU, the high byte stored in the temporary register, and the low byte written are both copied into the 16-bit register in the same clock cycle. When the low byte of a 16-bit register is read by the CPU, the high byte of the 16-bit register is copied into the temporary register in the same clock cycle as the low byte is read . Not all 16-bit accesses uses the temporary register for the high byte. Reading the OCR1A/B 16bit registers does not involve using the temporary register. To do a 16-bit write, the high byte must be written before the low byte. For a 16-bit read, the low byte must be read before the high byte.
Das geschieht automatisch im Hintergrund. Wenn Du auf das High-Byte zugreifst, wird in der Hardware in Wirklichkeit das temporary Register angesprochen; die Aktualisierung des HByte<->temporary Register wird über den Zugriff auf das Lowbyte getriggert. So'ne ähnliche Sache gibt es bei'm UART Data Register (UDR). Das sind in Wirklichkeit 2 - eins zum Senden, eins zum Empfangen. Wenn Du das UDR liest, wird das Empfangsregister adressiert, wenn Du schreibst das Senderegister. Für Dich heissen die aber beide UDR.

Allerdings spukt mir noch'ne ganz elegante Geschichte im Kopf rum:
-Man lasse den Zeit-Zähler seinen Output-Compare-Pin toggeln (bzwim PWM setzen/löschen), und verbinde diesen Pin mit dem IC-Pin von Timer1.
-Timer1 zählt wie gehabt die Frequenz (also die Perioden).
-die entsprechende Flanke am IC-Pin bewirkt automatisch, daß TCNT1 ins ICR kopiert wird. (Da steht dann also die Anzahl der Perioden pro 8bit-Timerüberlauf - bisher alles in Hardware im Hintergrund)
-das IC-Event kann einen IRQ triggern, in dessen ISR muß möglichst schnell TCNT1 zurückgesetzt werden (Reihenfolge!), und dann das ICR ausgelesen werden (was allerdings Zeit bis zum nächsten 8bit-Timerüberlauf hat). (Oder kann man Timer1 mit CTC mit ICR als TOP UND ICR durch den entsprechenden Pin gleichzeitig ... hmm... grübel)
Edit:
Das Kauderwelsch da oben soll heissen: Kann ich einen Flankenwechsel/steigende/fallende Flanke am InputCapturePin GLEICHZEITIG zum :
-Clear Timer (CTC)
-(vorheriges) abspeichern des TCNT im ICR
-Generierung eines IRQ
verwenden, bis auf die ISR alles in Hardware, versteht sich?

Und noch'n Edit: erstelle erstmal einen Programmablaufplan (und schreibe den hier).
Trotzdem ein paar Sachen:
-Den Stackpointer mußt Du nicht reinitialisieren (stört aber auch nicht weiter, nur ein paar Takte und Words)
-bei unbenutzten Interruptvektoren ist Schnurz, was drinnsteht, da dieser Code in einem korrekten Programm nie ausgeführt wird, es sei denn man bringt da sinnigen Code unter - ja, ich weiß - da scheiden sich die Geister... (in einer Offiziellen AppNote von Atmel wird übrigens eine ISR direkt an den Interruptvektor geschrieben - ohne Sprungbefehl und über die anderen Vektoren hinweg. geht natürlich nur, wenn man diese nicht braucht. Hab ich auch schon so gemacht...
-zumindest innerhalb der ISRs/Prozeduren kannst Du statt JMP RJMP nehmen.
 
Hallo,

also das mit dem "Reihenfolge" scheint mir noch nicht ganz klar geworden zu sein. Ist aber beim 16Bit-Timer sehr wichtig.

Das Timing der gesamten Schreib/Leseoperation auf den Zählerstand des Timers geschieht über das unterste Byte des Timers (also das Low-Byte). Das wird gemacht weil der Zählerstand sich ja theoretisch zwischen dem Zugriff auf das Low-Byte und dem Zugriff auf das High-Byte ändern könnte. Im schlimmsten Fall ein Überlauf von FFFF auf 0000. Dann würdest du evtl 00FF oder FF00 lesen aber nicht den wirklichen Stand. Darum wird das über ein Zwischenregister für das High-Byte und dem Zugriff auf das Low-Byte synchronisiert. Wenn man es nicht macht dann nennt man sowas auch Race Condition.

Also beim LESEN wird zuerst das Low-Byte gelesen. Damit wird auch automatisch das High-Byte in den Zwischenpuffer befördert. Nun kann nichts mehr dazwischenkommen. Beim Lesen des High-Bytes liest man dann in Wirklichkeit nur noch den Wert aus dem Zwischenpuffer. Damit kann sich ab dem Lesen des Low-Bytes also auch am Zustand des High-Bytes (ist ja nun im Puffer) auch nichts mehr ändern. Egal was der Timer da weiter veranstaltet.

Beim SCHREIBEN geht es genau andersrum. Man schreibt zuerst das High-Byte in den Puffer. Mit dem Schreiben des Low-Bytes wird gleichzeitig der Puffer in das High-Byte des Timers transportiert. Es kann also auch nichts dazwischenkommen wenn der Zähler noch am laufen wäre.

Die Reihenfolgen sind dabei äußerst wichtig und unbedingt einzuhalten.

Gruß
Dino
 
Hi und guten Morgen
Ich hoffe, ich kann was beitragen, denn wenn ich die Augen schon richtig auf hab, sehe ich einen kleinen. aber gravierenden Fehler...
Ich hoffe, ich habe keine all zu großen Böcke geschossen.
Programmablauf wie folgt:
Überspringen der IVT.... Ist ok
Initialisieren und Interrupt freigeben... auch ok
aber dann folgt ein RCALL in ein Unterprogramm..... warum nicht
doch nach dem Rücksprung sehe ich nur
Code:
Doit:
JMP Doit

Ist nicht viel, was dann getan wird. In der ISR kann ich auch nicht erkennen, das dort was passiert, was den neugierigen User vor der Kiste interessieren könnte.
Vielleicht ist es ja auch Absicht, den Programmcode zu verbergen.
Es ist noch so verdammt früh.....
Gruß oldmax
 
Deswegen ja die Reihenfolge, Aus dem Datenblatt des Mega88/...:

Das geschieht automatisch im Hintergrund. Wenn Du auf das High-Byte zugreifst, wird in der Hardware in Wirklichkeit das temporary Register angesprochen; die Aktualisierung des HByte<->temporary Register wird über den Zugriff auf das Lowbyte getriggert. So'ne ähnliche Sache gibt es bei'm UART Data Register (UDR). Das sind in Wirklichkeit 2 - eins zum Senden, eins zum Empfangen. Wenn Du das UDR liest, wird das Empfangsregister adressiert, wenn Du schreibst das Senderegister. Für Dich heissen die aber beide UDR.

Na, da hab ich wohl nicht gründlich genug studiert! Mit diesem Service habe ich nicht gerechnet.

Dino03: Danke! Ich denke es ist klar. Also genau genommen hab ich dann den Timer1 falsch rum gelöscht. Aber da läuft er ja noch nicht.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)