Hallo,
ich habe meinen Code jetzt so runtergestrickt, dass er nur noch aus dem
besteht, was NICHT funktioniert...
Ich nutze für eine Fast PWM einen Timer0 und der löst mir (warum auch
immer) einen PCINT1 Interrupt aus (zumindest in der AVR-Studio
Simulation2)
AVRSTudio 4.19
ATTINY 85
Bitte schaut Euch mal die Datei im Anhang an und erklärt mir woher
dieser ungewünschte Reset kommt, wenn der Timer0 von 255 auf 0 springt.
Ich schnalls echt nicht warum es eine Verbindung zwischen den beiden
Größen gibt...
Vielen Dank.
dost0011 schrieb:> Ich nutze für eine Fast PWM einen Timer0 und der löst mir (warum auch> immer) einen PCINT1 Interrupt aus (zumindest in der AVR-Studio> Simulation2)
Ich hab' den Simulator noch nie benutzt. Aber hardwaremässig ist das
natürlich Unsinn.
Du setzt aber PB1:
>PORTB = (1<<PIN_Trittfrequenz)|(
Und das ist ein Pinchange. Denn vorher war der 0. Und das Interrupt-Flag
wird unabhängig vom Interrupt-Enable gesetzt. Sonst könnte man das ja
nicht pollen.
Einfach das PCIF im GFIR vor sei() löschen. 1 reinschreiben!
mfg.
Thomas Eckmann schrieb:> Und das Interrupt-Flag> wird unabhängig vom Interrupt-Enable gesetzt. Sonst könnte man das ja> nicht pollen
Das stimmt so nicht. Ist auch bischen unlogisch, weil die Maske noch
nicht gesetzt ist.
Gesetzt wird das Interrupt-Flag, wenn PCIEx gesetzt wird(ist). Je
nachdem wann man den Pullup schaltet. Klar, wenn er zuletzt gesetzt
wird, ist es auch nicht anders zu erwarten.
//Taste, Pin Change Interrupt PCINT8
PORTC |= (1 << 0);
PCMSK1 |= (1 << PCINT8);
PCICR = (1 << PCIE1);
egal in welcher Reihenfolge.
Setzt man den Pullup, nimmt ihn wieder weg und dann PCIEx passiert gar
nichts.
Also das ist auf jeden Fall zu machen:
>Einfach das PCIF im GFIR vor sei() löschen. 1 reinschreiben!
So ist das beim Atmega48pa. Beim 644p tritt dieses Phänomen nicht auf.
Also mal so mal so. Beim Tiny85 ist es scheinbar so wie beim 48.
mfg.
Natürlich muss dass PCINT1_vect heissen. Man bin ich ein Trottel. Habe
die Hardware umbesinnend und vergessen den Interrupt mit anzupassen.
Das mit dem PinChange war mir nicht bewusst, dass ich bereits ein
IntFlag bekomme, auch wenn SEI noch nicht freigegeben ist.
Das das setzen eines Pullup Widerstandes zu einem PINCHANGE führt, war
mir auch nicht klar.
Vielen Dank!!!
Shit jetzt komme ich doch durcheinander.
Wenn es einen PCINT1 Pin gibt, aber keinen dazugehörigen Interrupt - wie
nutze ich dann diese PIN Funktion überhaupt?
Ich benötige
- einen ext. Int
- einen PINChange Int
- 2 AD Eingänge
- 1 PWM Ausgang.
Ich dachte das haut genau hin mit dem ATTINY 85...
Könnt ihr das nochmal besrätigen bzw. verneinen?
Danke.
dost0011 schrieb:> Shit jetzt komme ich doch durcheinander.> Wenn es einen PCINT1 Pin gibt, aber keinen dazugehörigen Interrupt
Doch, den gibt es. Du musst nur zwischen PCINT-Portpins und
PCINT-Interrupt-Vektoren unterscheiden. Das (für Dich noch)
Unübersichtliche dabei ist, dass die Pins bitweise nummeriert sind, die
PC-Interrupts aber byteweise bzw. Portweise (ein Port (und damit ein
PCI-Handler) kann bis zu 8 Bits bzw. Pins haben). Alle Pins des ATTiny85
liegen auf PortB, also gibt es nur einen PCI-Handler für alle Portpins,
und das ist PCINT0.
> - wie> nutze ich dann diese PIN Funktion überhaupt?
Indem Du in der PC-Interrupt-Maske nur den benötigten Portpin (also sein
Bit, in Deinem Falle Bit 1 für PCINT1, da dieser auf PB1 liegt)
aktivierst. Somit wirkt nur ein Pegelwechsel an PB1 auf den
PCINT0-Interrupt, alle anderen Portpins werden ja (von Dir) per
Maskierung als Interrupt-Quelle deaktiviert.
>> Ich benötige>> - einen ext. Int PB2, Pin 7, INT0> - einen PINChange Int PB1, Pin 6, PCINT1> - 2 AD Eingänge PB3, Pin2, ADC 3 und PB4, Pin 3, ADC2> - 1 PWM Ausgang. PB0, Pin 5, OC0A
Solltest Du die schnellere PWM über die PLL des Timer1 brauchen, dann
ginge es so:
> - einen ext. Int PB2, Pin 7, INT0> - einen PINChange Int PB0, Pin 5, PCINT0> - 2 AD Eingänge PB3, Pin 2, ADC3 und PB4, Pin 3, ADC2> - 1 PWM Ausgang. PB1, Pin 6, OC1A
Der PCINT0-Handler (als ISR) bleibt derselbe (es gibt ja nur diesen), es
ist lediglich ein anderes Bit (Bit 0 statt Bit 1) zu maskieren.
>> Ich dachte das haut genau hin mit dem ATTINY 85...
Ja sicher haut das hin, sogar in mehreren Varianten. Du solltest aber
die PWM-Endstufe so gestalten, dass der daran angeschlossene Verbraucher
während des ISP nicht Amok läuft.
>> Könnt ihr das nochmal besrätigen bzw. verneinen?>> Danke.
...
Ich traue es mich ja kaum zu fragen, aber könntet ihr das angehängte
Programm so modifizieren, dass es funzt?
Sonst befürchte ich, dass dieser Thread nie enden wird :-)
Ein PCINTx_vect ist immer für bis zu 8 Pins zuständig, also:
PCINT0_vect: PCINT0..7
PCINT1_vect: PCINT8..15 usw.
Zu jedem Interrupt gibt es noch ein Maskenregister für die Auswahl der 8
Portpins.
Wählt man mehr als einen Pin aus, muß man im Handler noch rauskriegen,
welcher Pin den Interrupt ausgelöst hat. Das kann sehr tricky sein, da
es leider kein dazugehöriges Flagregister gibt.
Peter
dost0011 schrieb:> aber könntet ihr das angehängte> Programm so modifizieren, dass es funzt?
Ich nicht, von C habe ich keine Ahnung. Ich werkele in Assembler und
beziehe die benötigten Infos (trotz sehr schlechter Englisch-Kenntnisse)
aus dem jeweiligen Datenblatt.
...
Peter Dannegger schrieb:> Wählt man mehr als einen Pin aus, muß man im Handler noch rauskriegen,> welcher Pin den Interrupt ausgelöst hat.
Ich vermute mal, Atmel hat den PCI vorrangig für Tastenabfragen (auch
Matrix) zum Aufwecken aus dem Tiefschlaf (nicht zum Entprellen)
vorgesehen. Der Testballon dafür war der ATTiny28, der ja speziell für
IR-Fernbedienungen konzipiert war.
> Das kann sehr tricky sein, da> es leider kein dazugehöriges Flagregister gibt.
Das würde ich auch begrüßen, und wenn nur zum Zeitpunkt des Interrupts
der Port (wie bei ICP der Timerstand) in ein Zwischenregister eingelesen
würde. Man kann aber leider nicht alles haben...
...
dost0011 schrieb:> Ich traue es mich ja kaum zu fragen, aber könntet ihr das angehängte> Programm so modifizieren, dass es funzt?
Dazu müßte man erstmal wissen, was das Programm machen soll.
Ich weiß, es ist schwer, eine logisch aufgebaute und eindeutige
Funktionsbeschreibung zu erstellen, aber Hellsehen ist noch viel
schwerer.
Versuche mal so heranzugehen, daß mit Deiner Beschreibung jemand völlig
fremdes das Programm erstellen kann, ohne nochmal nachfragen zu müssen.
Du wirst lachen, aber selbst wenn man ein Projekt selber programmiert,
ist eine vollständige Beschreibung sehr hilfreich. Sie ist quasi der
rote Faden in einem Labyrinth.
Peter
Jetzt wollte ich gerade anfangen alles zu erklären, aber erstens geht es
mir ja um die Architektur - und die ist in meinem Programm mit
Kommentaren erklärt - und außerdem traue ich mir das doch selber zu :-)
Aber dazu muss ich das Problem verstehen und das habe ich noch nicht.
Die Ausgansfrage war ja, wer löst mir eigentlich den Interrupt von
PCINT0 aus? Antwort: der Timer0 von der PWM. Doch warum macht der das?
Ich sehe da gar keinen Zusammenhang - auch nicht, wenn ich ins
Datenblatt schaue.
So und dann Zielen eure Antworten darauf ab, dass ich nur einen
PCINT_vec für die PCINT Pins habe. Antwort: mir doch egal, weil ich nur
einen benötige.
Der andere soll ja der INT0 Interrupt sein. Und der hat doch hoffentlich
seinen eigenen Vector, oder?
Vielen Dank für eure Geduld. Bin mir aber sicher, dass hierbei viel
gelernt wird...
dost0011 schrieb:> Jetzt wollte ich gerade anfangen alles zu erklären, aber erstens geht es> mir ja um die Architektur - und die ist in meinem Programm mit> Kommentaren erklärt
Naja, das ist äußerst spartanisch. Es ist z.B. nicht zu erkennen, wie
die Signale für Trittfrequenz und Geschwindigkeit generiert sind, also
ob diese prellen können, welche Frequenzen da zu erwarten sind oder
wasauchimmer. Ein externer Interrupt ist nämlich nicht immer die beste
Wahl beim Einlesen von externen Pegelwechseln.
> - und außerdem traue ich mir das doch selber zu :-)
Achso? - Und warum fragst Du?
> Aber dazu muss ich das Problem verstehen und das habe ich noch nicht.>> Die Ausgansfrage war ja, wer löst mir eigentlich den Interrupt von> PCINT0 aus? Antwort: der Timer0 von der PWM. Doch warum macht der das?
Na weil in PCMSK alle Bits gesetzt sind und somit alle Portpins den PCI
triggern können.
> Ich sehe da gar keinen Zusammenhang - auch nicht, wenn ich ins> Datenblatt schaue.
Dann hast Du nur halb ins Datenblatt geschaut. Denn in der
Registerbeschreibung zu PCMSK steht unter Initial Value, dass alle
relevanten Bits nach der Initialisierung gesetzt sind. Und wenn Du per
Programm mit
/* PIN Change Mask Register -> Trittfrequenz */
sbi(PCMSK,PCINT1);
ein bereits gesetztes Bit nochmal setzt, dann werden die restlichen Bits
davon noch lange nicht zurückgesetzt...
Schreib:
PCMSK = 1<<PCINT1
Dann funktioniert das auch.
>> So und dann Zielen eure Antworten darauf ab, dass ich nur einen> PCINT_vec für die PCINT Pins habe.
So ist es...
> Antwort: mir doch egal, weil ich nur> einen benötige.
Naja, manchmal ist es aber ganz nützlich, wenn man versteht was man tut.
> Der andere soll ja der INT0 Interrupt sein. Und der hat doch hoffentlich> seinen eigenen Vector, oder?
Ein Blick ins Datenblatt, Kapitel Interrupt, hätte Dir die Liste der
Interrupt-Handler gezeigt...
>> Vielen Dank für eure Geduld. Bin mir aber sicher, dass hierbei viel> gelernt wird...
Bist Du sicher?
...
Hallo Hannes,
so es läuft. Und ich bin dir dankbar.
Aber jetzt mal unter uns:
Ich habe 2 Fehler gemacht:
- Beim setzen des Pullup Widerstandes versehentlich einen Interrupt
ausgelöst
- Davon ausgegangen, dass PCMSK mit 0 initialisiert ist
Fehler zu machen ist nie toll, aber ich finde, das hier hält sich noch
im Rahmen, wenn man das erste Mal ein größeres Projekt mit mehreren
Interrupts angeht.
Danke an alle, auch wenn es etwas länger gedauert hat, bis die 2
eigentlichen Probleme "erkannt" wurden. Alles umzuschmeissen (PWM von
KanalA auf KanalB usw) ist hier gar nicht nötig...
Anmerkungen wie:
<Naja, das ist äußerst spartanisch. Es ist z.B. nicht zu erkennen, wie
die Signale für Trittfrequenz und Geschwindigkeit generiert sind, also
ob diese prellen können, welche Frequenzen da zu erwarten sind oder
wasauchimmer. Ein externer Interrupt ist nämlich nicht immer die beste
Wahl beim Einlesen von externen Pegelwechseln.>
... bringen mir doch gar nichts.
Ich habe extra nicht den ganzen Code geschickt, und die ISRs leer
gelassen, damit die Fehlersuche einfach wird.
Es bringt doch nichts, dann eine neues Fass aufzumachen mit:
- ext. Interrupts nicht immer geeignet
- Prellen?
- Frequenz der Signale
Hätte ich nicht immer wieder so "dämlich" nachgehakt, dann wäre jetzt
alles umgestellt, aber funktionieren würde es immer noch nicht, weil die
entscheidende Antwort erst gestern abend kam...
Und ja, ich lerne was daraus (und nicht nur ich...)
dost0011 schrieb:> Es bringt doch nichts, dann eine neues Fass aufzumachen mit:
Na unter "ein Fass aufmachen" verstehe ich was Anderes, da brennt die
Luft...
;-)
> - ext. Interrupts nicht immer geeignet
Ist aber so, es gibt mehr Leute als Du denkst, die prellende mechanische
Kontakte an Interrupts anschließen.
> - Prellen?
Ja sicher, mechanische Kontakte prellen nunmal, was Gift für Interrupts
ist. Ebenso ist es bei optischer Erfassung (Lichtschranken), wenn
Vibration im Spiel ist.
> - Frequenz der Signale
Ereignisse unter 1 kHz fragt man besser durch Pollen im Timer-Interrupt
ab.
>> Hätte ich nicht immer wieder so "dämlich" nachgehakt, dann wäre jetzt> alles umgestellt,
Hätte ich Enten gekauft, dann wären die Hühner nicht ersoffen...
Aber Du hast schon recht, ich hätte ohne Deine Nachfragen Deinen
Quälcode nie gelesen. Denn ich mag kein C, ich programmiere AVRs in
Assembler, auch den ATTiny85 (z.B. Soundmodul für Modellbahn, Diesel mit
Anlasser, Glocke und Horn, sowie Dampf mit Glocke und Pfeife). Erst
Deine Behauptung, alles wissenswerte stünde im Quälcode, brachte mich
dazu, da mal reinzusehen.
> aber funktionieren würde es immer noch nicht,
Der Hinweis betreffs Timer1 hatte schon seinen Sinn. Timer1 hat eine PLL
im Vorteiler, damit lassen sich 16-fach höhere PWM-Frequenzen erzeugen.
> weil die> entscheidende Antwort erst gestern abend kam...
Die hättest Du aber selbst durch aufmerksameres Lesen des Datenblattes
finden können.
...
Wenn man immer wüsste, wo man schauen soll...
Aber nix für ungut.
Bin ja so froh, dass es Euch Experten gibt, auch wenn man dann ab und zu
was aufs Dach kriegt (wenn man dämlich nachfragt...)
Aber vielleicht muss das so sein :-)
Habe gerade was im Simulator gefunden, was nicht astrein ist:
Rebuild -> Debug ON -> Reset Cycle Counter -> Stimuli File geladen ->
Run
--> alles funzt (Stoppmarke bei #2000000 wird ausgeführt)
Nun das gleiche, aber statt einem Rebuild ein Build und dann gestartet.
--> Stoppmarke bei #2000000 wird scheinbar übersprungen, Programm hält
bei #4000000, obwohl es hier gar kein Stoppereigniss gibt...
Das ist mir schon mal aufgefallen.
Nur wenn man einen kompletten Rebuild macht, scheint alles zu funzen.
Lästig, auch, weil man jedes mal wieder neu das Stimuli File einbinden
muss...
dost0011 schrieb:> auch wenn man dann ab und zu> was aufs Dach kriegt
Das siehst Du wohl etwas überempfindlich...
Ich meine nicht, dass mein Tonfall Deinem gegenüber unangemessen war:
dost0011 schrieb:> und außerdem traue ich mir das doch selber zu
Den Rest kommentiere ich nicht, ich habe keine Ahnung von C und will auf
meine alten Tage damit auch nicht mehr beginnen.
...
Hannes schrieb:
> Na unter "ein Fass aufmachen" verstehe ich was Anderes, da brennt die> Luft... ;-)
So was?
Having a Barrel of Fun - YouTube
http://www.youtube.com/watch?v=ANoKOmGOong