Hallo Freunde, Sieht euch mal dieses programm soll nach etwa 8sekunden
in den hauptprogramm zurück aber das tuts nicht, vielleicht ist die
Idee falsh. Wie kann ich den Assembler beibringen das er warten soll
bis der zähler überleuft. Das mit dem TIFR ist doch keine schlechte
Idee oder?
.include "m8def.inc"
.org 0x000
rjmp main
sub1:
ldi r16, 0b00000000
out TCCR1A, r16
ldi r16, 0b00000100
out TCCR1B, r16
ldi r16, 0b00000100
out TIMSK, r16
while:
ldi r17, 00000100
andi r17, TIFR
cpi r17, 00000100
breq endwhile
rjmp while
endwhile:
ret
main:
ldi r16, LOW(RAMEND)
out spl, r16
ldi r16, HIGH(RAMEND)
out sph, r16
ldi r16, 0b00001111
out DDRB, r16
ldi r16, 0xFF
out PORTB, r16
ldi r16, 0x00
out DDRD, r16
sei
rcall sub1
weiter:
; rcall sub2
ldi r17, 0b00010000
out PORTB, r17
rjmp main
Soweit ganz nett, aber Du solltest schon den TIFR Wert einlesen, also
sinngemäß:
while:
in r17, TIFR
andi r17, 00000100
cpi r17, 00000100
breq endwhile
rjmp while
endwhile:
Wenn der uC wirklich nur die 8 Sekunden gar nix machen soll, würde sich
noch ein Timerinterrupt anbieten, der das Teil dann nach einem sleep
wieder aufweckt.
Spart eventuell sogar Strom :-)
Gruß
Ingo
Deshalb hab ich ja auch geschrieben sinngemäß, mir war nur
aufgefallen, das Du den Wert des TIFR überhaupt nicht einlieste. Dann
kannst Du natürlich auch das Falg nicht auswerten.
Was da nun genau zu machen ist, kann ich so aus dem Hut auch nicht
sagen.
Gruß
Ingo
Hi!
Mag sein, das Du gleich ausrastest, aber ein paar Fehlerchen haben sich
schon eingeschlichen.
Du kannst nicht direkt eine AND-Verknüpfung mit dem Inhalt eines
Registers zur Aussenwelt machen:
ldi r17, 00000100
andi r17, TIFR
In Zahlen umgesetzt schaut das dann so aus:
ldi r17, 00000100
andi r17, 0x38 ($38 ist die Adresse von TIFR welche in der
m8def.inc mit .ecu definiert ist)
Mußt Du ändern in folgendes:
in r17,TIFR
andi r17, 0b00000100
Da fällt mir gerade auf, das Du 2 mal "0b" vor einer Binärzahl
vergessen hast.
Wenn Du willst, das Bit 2 nach dem Warten wieder zurückgesetzt wird muß
vor dem RET noch folgendes rein:
sbi TIFR,2
Dadurch wird das Flag TOV1 zurück auf 0 gesetzt.
Lies Dir dazu mal in aller Ruhe im PDF-File für den ATMega 8 ab Seite
101 alles durch.
Der Rest schadet natürlich auch nicht.
Gruß
Andi
Sorry, mein Fehler!
Mit SBI/CBI/IN/OUT kann man, dank der AVR-Entwickler (nich bös
gemeint), nur die I/O-Register 0 bis 31 ansteuern.
Das macht das ganze dann etwas komplexer ;-)
Statt SBI dann:
ldi r16,0b00000100
sts TIFR+0x20,r16 ;I/O-Register 0 ist in echt bei Adresse 0x20!
Gruß
Andi
Oben ist irgend was falscht egal was ich mach er springt nicht raus
obwohl TIFR die 2 bit gesetzt wird danke für deine vorschlag aber die
Daten Blätter hab ich ganz genau studiert
Ja, ja!
Hab erst nach her bemerkt, das IN/OUT von I/O-Reg. 0 bis 63 geht (0x00
bis 0x3F).
Also geht dann auch:
ldi r16,0b00000100
out TIFR,r16
Bei den ganzen verschiedenen Beschränkungen kommt man ein bißchen
durcheinander.
Gruß
Andi
Ja es sind schliesslich 303 Seiten man braucht einfach eine routine ich
wusste auch dass ich irgendwas mitt register Tifr und in gelessen zu
haben na ja Vielen dank es war sehr hilf reich vor allem ich hab nicht
gesehen wo ich irgend einzhal eingegben hab (anstaat 0b00000100 hab ich
eingegeben na ja Assembler in C wäre ja sowas kein Problem while
schleife)
Hi...
Irgendwie verstehe ich nicht, was Ihr mit TIFR wollt.
TIFR wird von der Hardware durch ein INT-auslösendes Ereignis gesetzt
und löst einen Int aus, sofern das zugehörige Bit in TIMSK auch gesetzt
ist (für TIMSK ist der Programmierer zuständig) und natürlich das I-Flag
in SREG gesetzt ist (mit SEI). TIFR wird durch den Interruptaufruf
automatisch gelöscht.
Mit TIFR hat (im Normalbetrieb ohne Tricksereien) der Programmierer
überhaupt nix zu tun.
Man stellt die gewünschten Timer-Parameter ein (Vorteiler usw.), dann
in TIMSK die gewünschten Interrupts, und gibt mit SEI global Interrupts
frei. Das wars eigentlich schon.
Natürlich müssen die Int-Vektoren in den ersten Zellen des Flash
korrekt eingetrage werden und die zugehörigen Int-Handler ordentlich
mit RETI abgeschlossen sein. Es ist auch darauf zu achten, das die ISRs
möglichst kurz sind...
@Andi: Das mit den Einschränkungen geht leider nicht anders, bei nur 16
Bit für die Befehle reichen die Bits nicht, um alle Befehle mit allen
Registern bzw. I/O-Registern zu implementieren. Ich hätte auch gerne
Bit-Transfer per T-Flag mit dem I/O-Bereich (wäre schön bequem...),
aber man kann nicht alles haben... ;-((
Gruß...
...HanneS...
Ja aber bei Overflow von Timer1 ist wird der in TIFR das 2 gesetzt so
kann der programmierer auch erkennen ob eine Interupt ausgelöst wurde.
Für den oberen Programm mach das natürlich kein sinn aber stell dir vo
du hättest mehrere unterprogramme wie Oben wie willst du es dann
machen? oder kennst du andre Möglichkeiten. Überleg dir wenn du wie du
oben behauptst einen Interrupt benutzen würdest dann konntest du nur
eine unterprogramm verwenden. Oder wenn du andre möglichkeiten kennst
dann hier damit.
Hi Airbag...
Vorschlag:
Lies dir mal die Sektion Timer eines Datenblattes zu einem alten
Classic-AVR durch. Dort sind die reinen (normalen) Timerfunktionen
erklärt, ohne dass immer auf die Spezielfunktionen der neuen Features
(PWM usw.) verwiesen wird. Da versteht man das besser.
Zu deinem Programm kann ich dir derzeit keinen Tip geben, da ich noch
nicht nachvollziehen kann, was du eigentlich willst. Da ist zwar von
einem "Unterprogramm" die Rede, das nach 8 Sekunden fertig sein soll.
Ich sehe da keinen Sinn drin. Wenn ich eine Pause von 8s brauche, dann
stelle ich den Timer so ein, dass er nach 8s einen Interrupt auslöst
und schicke den AVR in den Sleep-Mode. In der ISR wird dann ein Flag
gesetzt (in einem der Register r16...r31, das ich "flags" nenne), was
von der Hauptschleife überprüft und nach Abarbeitung gelöscht wird.
Aber dieses Verfahren nutze ich selten, meine Programme laufen meist
total Timer-gesteuert. Da erzeugt ein Timer (meist Timer0) einen
regelmäßigen Aufruf seiner ISR, in der dann Register (als Zähler)
in/decrementiert werden und Flags für den Programmablauf der
Hauptschleife gesetzt werden. Wenn keine weiteren Ints genutzt werden,
mach ich auch gleich mal die gesamte Arbeit in der Timer-ISR. Ist die
Arbeit getan, schicke ich den AVR in den Sleep-Mode, er wird dann vom
nächsten Int geweckt...
...HanneS...
Hi Airbag...
Mir ist da noch etwas aufgefallen.
In deinem Code (erstes Posting) endet die Routine "main" mit "rjmp
main". Damit beginnst du das Programm von vorn (mit allen
Initialisierungen). Vielleicht solltest du dir angewöhnen, einen
Anweisungsblock "reset" zu verwenden, in dem du alle
Initialisierungen erledigst. Darauf folgt dann "main" als
Hauptschleife, die mit "rjmp main" endet. Damit erreichst du, dass
die Initialisierungen nur beim Reset (Start, Watchdog) ausgeführt
werden. Wenn du nämlich mitten im Programm den Stackpointer neu
initialisierst, kann das böse Überraschungen bereiten.
Schau dir mal einige Programmbeispiele in anderen Threads an.
Gruß...
...HanneS...
Es geht hier nur drum um Portb Par sekunden lang in irgend eine zustand
zu halten. Das mit dem rjmp main hast du recht. Aber diese Programm
soll nur eine beispiel sein,