Guten Abend,
Es tut mir echt Leid euch schon wieder mit dem Thema Interrupts zu
nerven, aber ich komme irgendwie nicht weiter und vielleicht erkennt
jemand von euch ja auf Anhieb einen offensichtlichen Fehler. Also:
Dies ist mein Assembler Code um den ATtiny13A in den Power Down Modus zu
bringen und per Low Level an INT0 wieder "aufzuwecken":
Aber anstatt in den Power Down Modus zu kommen arbeitet der ATtiny das
Programm einfach weiter ab. Ich habe schon einen externen Pull Up
Widerstand an INT0 angeschlossen, aber das Ergebniss ist das Gleiche.
Vielleicht habe ich irgendwas bei der Initialisierung vergessen? Vielen
Dank schonmal
Hallo ,
Ja Fehler entdeckt du hast kein Hauptprogramm, und eine Interrupt
Routine hast du auch nicht.
Frage Dich bitte,0 warum es ein RET und ein RETI gibt.
Wo befindet sich das RETI?
Wo ist überhaupt der meiste Teil des Codes?
Wer soll sich an die Magic Numbers der Registerinhalte erinnern?
Gibt es so was wie Kommentare?
Danke für die schnellen Antworten, der Code ist eigentlich länger ich
dachte bloß ich erspare euch Sucharbeit wenn ich den kürze ^^
Aber ok, hier ist der ganze Code:
Achso, zu der Idee mit dem reti Befehl:
muss ich dann nicht auch den Stack Pointer am Anfang initialisieren?
Und geht das nicht mit einem einfachen rjmp, wenn das Programm sowieso
immer an der gleichen Stelle anfangen soll?
Außerdem war mein Problem doch das der Microcontroller gar nicht in den
Power Down Modus kommt, und nicht das er nicht aus der Interruptroutine
rauskommt.
@Ozvald K.:
Stimmt, danke für den Hinweis, habe den jetzt auf das Label "start:"
springen lassen.
Wackelkopf S. schrieb:> .org 0x000A> ldi r16, 0xF0> out DDRB, r16> ldi r16, 0x0F> out PORTB, r16>> ldi r16, 0b01000000> out GIMSK, r16> sei> ldi r16, 0b01110000> out MCUCR, r16> sleep
..und das wird nie ausgeführt
Wackelkopf S. schrieb:> Ozvald k. Wieso nicht? Es steht doch am Anfang des Programms
nöö,
der µC springt den Resetvektor an und Verweigt dann nach RESET.
Es war schon richtig, das ist kein korrektes Programm!
Schreibe es richtig, mit Stack und auch allen vorhandenen Vektoren.
Dann verstehst Du evtl. wie es zu funktionieren hat!
Du musst doch jede Menge Fehlermeldungen vom Assembler bekommen, weil es
die ganzen Interrupt Sprunziele nicht gibt - ausser EXT_INT0.
Die sollte man nicht einfach ignorieren und sich dann wundern, dass nix
geht.
Wackelkopf S. schrieb:> Achso, zu der Idee mit dem reti Befehl:> muss ich dann nicht auch den Stack Pointer am Anfang initialisieren?
In weißer Voraussicht initialisieren die AVR's die Stackpointer auf das
Ende des RAM. Es geht also ohne. Allerdings nur beim HW-Reset, nicht
wenn nur nach 0x0000 gesprungen wird.
Wackelkopf S. schrieb:> Es steht doch am Anfang des Programms
Dir fehlen offensichtlich Grundkenntnisse. Beim Einschalten führt der µC
den ersten Befehl an der Adresse 0 aus. Dort hast du jetzt "springe auf
Start Label". Einen Sprung auf deine Initialisierungsroutine ab 000A
hast du nirgendwo.
Ich muss dich enttäuschen, aber selbst im obrigen Code wird der
Microcontroller nicht in den Power Down Modus versetzt, obwohl alle
Interruptvektoren auf Reset zeigen...
(außer natürlich der INT0 ^^)
@Karl M. sorry, habe deine Antwort erst jetzt gesehen, ändert aber
nichts daran das es immer noch nicht funktioniert ^^
Habe inzwischen ein reti davorgesetzt, aber genau da liegt der Punkt: Es
geht mir nicht darum das der Microcontroller nicht aus der
Interruptroutine wieder rauskommt, es geht mir darum das er nicht in den
Power Save Modus reinwill und dabei hilft der reti Befehl gar nicht.
Warum bitte programmierst du in Assembler?
Wenn du das tust, MUSST du den Prozessor kennen und genau wissen wie er
funktioniert, d.h. dort musst du anfangen und nicht irgendwelche Befehle
aneinanderreihen...
Nimm Arduino, dann brauchst du dich um sowas nicht kümmern. Verstehst
dann zwar immer noch nicht wie es funktioniert, aber es funktioniert
halbwegs.
PS:
-eine Anreihung von vielen nops macht nur ganz selten Sinn
-label-Namen sollten was sinnvolles aussagen
@H.Joachim S. Genau deshalb programmiere ich Assembler: Es ist viel
präziser als Arduino und damit lernt man viel mehr über die
Microcontroller als mit jeder anderen Programmiersprache
PS: Warum Antwortest du nicht auf die ursprüngliche Frage, anstatt vom
Thema abzuweichen? Du scheinst dich ja recht gut auszukennen
Ich glaube der TO möchte den 13er einschlafen lassen, um auf den INT0 zu
warten. Dazu braucht es eigentlich nur ein RETI im IntVector, und der
13er würde nach der "minimal kurzen" ISR weiterlaufen in den
Zeitvernichtungsteil. Eine bestimmte Zeit (Stunden) warten könnte man
natürlich auch mit weniger Stromverbrauch hinbekommen. Aber davor steht
erst mal die Aufgabe den AVR-Grundlagenartikel bezüglich Interrupts und
Timer durchzuarbeiten.
Und auch du konntest mir die ursprüngliche Frage nicht beantworten...
Aber ja, tatsächlich stehe ich noch recht am Anfang und würde mich über
ein wenig Unterstützung sehr freuen...
Was ist denn für dich präziser? Dss du die Anzahl der nops selber
abzählen kannst?
Du kannst nicht blind drauflos programmieren, wenn du nicht nichtmal
weißt, wie und wo so ein leicht durchschaubares Kerlchen wie der AVR
startet, wie eine ISR auszusehen hat und wie der stack arbeitet.
Das alles musst du wissen, wenn du in Assembler programmieren willst.
Ohne dir zu nahe treten zu wollen - wo bitte hast du denn ein Problem
bei dem PillePalle mit Arduino gehabt?
Wackelkopf S. schrieb:> immer noch nicht funktioniert
Habe nicht gesagt dass der Rest deines Programms gut ist. :-)
Um mit Interrupts zu arbeiten muss man den Stack initialisieren. (aber
nicht nur deswegen, CALL, POP, PUSH...) In der Interrupt Routine selbst
muss man den Status Flag Register "retten" wenn man dort auch Befehle
ausführt die die Flags ändern können. Bevor man die Int. Routine
verlässt, muss man ihn wiederherstellen. (PUSH, POP)
Positioniere außerdem die Interrupt Routine ganz am Anfang oder ganz am
Ende des Codes, sie darf nicht Bestandteil des Hauptprogramms sein, und
beende sie mit RETI (Stack Pointer Initialisierung vorausgesetzt)
Wackelkopf S. schrieb:> Warum Antwortest du nicht auf die ursprüngliche Frage, anstatt vom> Thema abzuweichen?
Weil es keinen Sinn macht, dir zu erklären an der wievielten Ampel in
Berlin du abbiegen sollst, weil du im Moment nicht nach Berlin findest.
Will sagen: beiss dich nicht an Kleinigkeiten fest, bevor du das
Grundprinzip verstanden hast.
Nicht bös gemeint, wird schon. Fang aber an der richtigen STelle an.
Auch ich kann deine ursprüngliche Frage nicht beantworten...
Falls du willst, dass der Prozessor nach dem Interrupt noch weitermachen
soll, musst du auch noch das Statusregister sichern.
Ausserdem solltest du Interrupts auch zulassen.
Woher weisst du eigentlich, dass der Controller nicht in den Sleep geht?
Warum sperrst du die Pullup Widerstände und versuchst sie dann doch zu
setzen?
Herr M. schrieb:> Woher weisst du eigentlich, dass der Controller nicht in den Sleep geht?
Ich resette den Controller und messe Die Zeit bis die LED leuchtet. Das
sind genau 10 Sekunden. Würde der Controller in den Power Down gehen
dürfte die LED erst leuchten nachdem ich die Drahtbrücke an INT0 mit GND
verbunden habe und dann noch 10 Sekunden abgelaufen sind.
Wackelkopf S. schrieb:> @H.Joachim S. Ich mochte Arduino nicht weil man nur bestimmte> Interruptquellen nutzen kann und nicht genau weiß was der Controller> tut.
Tu dir aber bitte den Gefallen vorne anzufangen. Und arbeite erst mal
ein Tutorial durch, notfalls auch in Assembler. Da kannst du lernen, wie
Interrupts und Timer funktionieren. Erwäge auch statt den Tiny13
eventuell einen mega328 verbaut auf einem Arduino-Nano-Clone für ein
paar €, der hat einen ISP Stecker und hat trotzdem noch ein paar Pins
frei. Auch den kann man in Assembler programmieren. Der Sinn der Artikel
in diesem Forum ist übrigens, dies nicht jedem neu erklären zu müssen.
Bitte Versuch es mal. Wenn dann Fragen hochkommen und du dich auf
Übungen im Tutorial beziehen kannst, dann wird man dir das sicher
anrechnen.
@Carl D.
Ich verstehe es total wenn ihr davon genervt seid Anfängern alles
vorbuchstabieren zu müssen, aber ich möchte doch auch mal selbst
Programme schreiben. Man sollte doch eben
H.Joachim S. schrieb:> nicht irgendwelche Befehle aneinanderreihen.
Sondern selbst mitdenken und daraus eigene Ideen gewinnen.
Carl D. schrieb:> Erwäge auch statt den Tiny13 eventuell einen mega328 verbaut auf einem> Arduino-Nano-Clone für ein paar €
Reicht da nicht auch ein AVRISP Clon mit ISP Anschluss und einem
verbauten ATmega328? Wollte bloss auch mal andere Controller
programmieren ^^
Dadurch, dass du alle Pullup Widerstände gesperrt hast und den INT0
Interrupt auf low Level gesetzt hast, vermute ich, dass der immer
ausgelöst wird, vor allem, wenn der Eingang in der Luft hängt.
versuch es mal ohne Interrupt
1
.include "tn13def.inc"
2
3
rjmp RESET
4
reti ; Int0-Interrupt versehentliche Interrrupts
5
reti ; PcInt0-Interrupt werden mit reti sofort
6
reti ; Timer/Counter 0 Overflow beendet
7
reti ; EEprom ready
8
reti ; Analog Commarator
9
reti ; Timer/Counter Compare Match A
10
reti ; Timer/Counter Compare Match B
11
reti ; Watchdog Timeout
12
reti ; ADC Conversion complete
13
reti
14
15
Reset:
16
ldi R16,low(Ramend) ; Stackpointer initialisieren
17
out SPL,R16
18
19
ldi r16,0xF0 ; Bit 0-3 Eingang
20
out DDRB,r16
21
ldi r16,0x0F ; Pullup für 0-3 anschalten
22
out PORTB,r16
23
24
clr r16 ; oder in r16,MCUCR ; Control register holen
Also, ich habe jetzt noch mal ein bisschen mit dem Code rumgespielt, das
Ergebnis war immer das gleiche. Dann bin ich auf die Idee gekommen das
die Programmänderungen gar nicht am tiny ankommen, habe ein Programm
geschrieben welches nichts tut und siehe da: Nach 10 Sekunden leuchtete
die LED. Dann habe ich die Kommunikationsgeschwindigkeit auf 8kHz
runtergeschraubt und es noch einmal versucht. Ich bekam folgende
Fehlermeldung:
Verifying Flash...Failed! address=0x0000 expected=0x13 actual=0x00
Habe die ISP Clock wieder auf default gesetzt und nochmal programmiert:
Jetzt kommt wieder etwas am tiny an!
Das Programm funktioniert so wie ich es gerade habe, falls jemand
Interesse hat kann ich das aktuelle Programm posten, ansonsten ist das
Problem jetzt gelöst. Danke an alle die mir geholfen haben! Und an die
die sagen das mein Programm eine Kathastrophe ist: Keine Sorge, es ist
noch nicht fertig. Ich werde die nops auf jeden Fall durch einen
vernünftigen Counter ersetzen und noch einen Abbruchknopf dranbauen.
MFG,
dangleheadturtle
Carl D. schrieb:> Tu dir aber bitte den Gefallen vorne anzufangen.
Dem kann ich nur zustimmen. Bringe das Programm erstmal überhaupt zum
funktionieren. Das Stromsparen fügt man erst ganz zum Schluß hinzu.
Immer ein Schritt nach dem anderen und nicht viele Baustellen
gleichzeitig.
Ich würde sogar dazu raten, erstmal ohne Interrupts nur mit Polling die
Funktion zu erstellen. Und wenn das funktioniert, als 2. Schritt mit
Interrupts.
Und wenn Du willst, daß jemand Dein Programm versteht, dann benutze
keine magischen Zahlen, sondern die Interruptvektoren und Bitnamen aus
dem Datenblatt.
Hier mal das Grundprinzip:
1
.include "tn13adef.inc"
2
rjmp init
3
.org INT0addr
4
rjmp int0
5
int0:
6
; interrupt code
7
reti
8
.org INT_VECTORS_SIZE
9
init:
10
; init code
11
ldi r16, 1<<WGM00 | 1<<WGM01 | 1<<COM0A0
12
out TCCR0A, r16
13
main:
14
; main code
15
rjmp main
Gerade in Assembler braucht man noch viel mehr Disziplin und Sorgfalt,
als in Hochsprachen.
Wackelkopf S. schrieb:> falls jemand> Interesse hat kann ich das aktuelle Programm posten, ansonsten ist das> Problem jetzt gelöst.
Es sollte DEIN Interesse sein, das aktuelle Programm zu posten, damit DU
was lernst. Du tust nicht "uns" einen Gefallen, sondern DIR.
Deine Annahme, das dein Problem nun mit deinem nicht geposteten Code
gelöst ist, ist .. mutig. Vielleicht sind ja da Besonderheiten und
Nebeneffekte drin enthalten, die du gar nicht kennst und übersiehst?
Nicht alle Kommentare von Rückmeldungen mögen dir gefallen, und nicht
alle Kommentatoren werden für den diplomatischen Dienst befähigt sein.
Dennoch lernst eher DU was aus den Rückmeldungen, und nicht die
Rückmelder.
Wackelkopf S. schrieb:> @H.Joachim S. Ich mochte Arduino nicht weil man nur bestimmte> Interruptquellen nutzen kann und nicht genau weiß was der Controller> tut.
Ich verstehe, dass du einen Grund benötigst, um dich in den Assembler zu
stürzen.
Aber deine Begründung/Annahme ist irrational.
Zumindest für die AVR Arduinos gilt:
1. Es gibt keine unerreichbaren Interruptquellen. Alle sind nutzbar!
2. Der komplette Arduino Wust liegt öffentlich aus. Es gibt keine
Geheimnisse. Spätestens der mitgelieferte Disassembler zeigt dir das
"Eingemachte".
Bitte nicht falsch verstehen!
Ich möchte dich nicht zu Arduino bekehren, oder dich von deinem ASM
abbringen.
Das ist alles ok, nur eben nicht die Begründung, die ist sachlich
falsch.
Hi
Nun, nach wie vor ist Assembler kein totes Pferd, auch wenn sich
professionelle Programmierer auf C bzw. hochsprachen berufen. Alles hat
seine Berechtigung. Nebenbei sollte vielleicht mal gesagt werden, das in
industriellen Steuerungen auch Programmierungen in Anweisungslisten
befinden, die einer Assemblersprache ähnlich sind. Und nicht jeder, der
hier hobby- oder berufsbedingt eine Programmiersprache benutzt, will nur
C, sondern ist auch an anderen Sprachen interessiert. Also, nett, das es
immer wieder Missionare gibt, aber wenn jemand Hilfe in Assembler
möchte, dann gebt sie.
@Wackelkopf..
Vielleicht interessierst du dich hierfür
https://www.makerconnect.de/media/user/oldmax/PC%20und%20Mikrocontroller%20Teil%201%20und%202%20Stand%2026.07.2019.pdf
gruß oldmax
Martin V. schrieb:> Also, nett, das es> immer wieder Missionare gibt, aber wenn jemand Hilfe in Assembler> möchte, dann gebt sie.
Das kann man auch verbinden.
Also ASM-Hilfe und Arduino-Missionar
Wie vielen bekannt ist, ist die Arduino Welt eher eine C++ Welt.
Aber dennoch ist es durchaus möglich dort Assembler einzubinden.
Um mal zu zeigen wie "einfach" das ist hab ich 3 Dateien in den Anhang
gepackt.
Eine leere *.ino Datei.
Das möchte Arduino so, denn ohne *.ino geht nix.
Eine main.S Datei.
Diese bitte zu der leeren *.ino in den Ordner werfen.
Die *.S enthält den ganzen Assembler Stoff.
Es wird dort ein main Label erzeugt und global bekannt gemacht, damit
der Linker befriedigt wird.
Ebenso eine ISR
Im main, wird PB5 auf Output gesetzt und Timer1 initialisiert.
Die Timer ISR toggled PB5
Es wird ein ca. 0,5Hz Rechteck aus gegeben.
Die LED an dem Pin blinkt in dem Takt vor sich hin.
Und zum Schluss die dritte Datei eine *.asm.
Sie ist das disassemblierte Kompilat.
In ihr kann man schön sehen, was Assembler/Kompiler und Linker daraus
fabrizieren.
-----
Der Code ist rudimentär.
Und meine ASM Fähigkeiten im Grunde auch.
Es ist also sicher kein vorbildhafter Code.
Es soll nur zeigen, dass auch in Richtung ASM mit der Arduino IDE mehr
möglich ist, als so mancher vermuten wird.