Forum: Mikrocontroller und Digitale Elektronik 2313A PIN Change Interrupt, zweiter Versuch


von Reinhard P. (reinhard_p)


Lesenswert?

Hallo zusammen,

die PIN Change Interrupts des 2313A bringen mich zur Verzweifelung. Hier 
mal ein Code mit dem ich:
a) den Interrupt INT0 getestet habe
b) mich mit der Sleep funktion auseinander gesetzt habe und....
c) der Pin Change Interrupt
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/sleep.h>
4
#include <util/delay.h>
5
#define F_CPU 8000000UL      // 8 MHz (fuer delay.h)
6
7
8
9
10
  ISR (INT0_vect)
11
   
12
   {
13
      PINB = 0x02;
14
      asm("nop"); 
15
    
16
    }
17
    
18
    
19
   ISR (PCINT_B_vect) // für PinChange an Port A in PCINT_A_vect ändern
20
   {
21
      PINB = 0x04;
22
    asm("nop");
23
   }    
24
25
int main(void)
26
27
{
28
  DDRA = 0x00;  // auch ein setzten auf Oxff ( Port auf Ausgang ) bringt nichts
29
  PINA = 0x03; 
30
  DDRB = 0xff;
31
  DDRD = 0x00;
32
  
33
  
34
  
35
  // Interrupt INT0 auf ansteigende Flanke, POwer-down und Sleep mode setzen
36
  MCUCR |= (1<<ISC01) | (1<<ISC00) | (1<<SM0) | (1<<SE) | (1<<SM1);   
37
  
38
  
39
  //externer Interrupt INT0 und Pin-change einschalten
40
  GIMSK  |= (1<<INT0) | (1<<PCIE0);  // hier müßte ich eigentlich lt Datenblatt PCIE1 eintragen
41
  
42
  
43
  // mit PCMSK und PCINT7 ist PB7 der Interruptauslöser  
44
  PCMSK |= (1<<PCINT7);  // hier müßte PMSK1 und PCINT8 stehen
45
46
  sei();
47
  sleep_mode();  // wird durch INT0 ==PD2 oder PCIE0==PB7 wieder geweckt
48
  
49
  
50
  
51
  
52
  while(1)
53
    {
54
     asm("nop");
55
  }
56
  
57
  
58
}

Im Code, so wie er dort steht, funktionieren die Pin Chnage Interrupts 
des kpl. PORTB Registers ( je nach Angabe in PCINT0..PCINT7).
Da ich diverse, fertig bestückte und funktionierende Platinen besitze, 
möchte ich gerne einen PIN Change Interrupt an PA0 und/oder PA1 haben. 
Dazu habe ich im Quellcode mal die Punkte als Kommentar getippelt, die 
geändert werden müßten.
Lt. Datenblatt:

--  Im GIMSK das Bit3 PCIE1 setzen
--  Im PCMSK1 das Bit0, Bit1 PCINT8, PCINT9 setzen

--  den ISR des PIN-Change-Interrupt in PCINT_A_vect ändern

Nun geht der Spuk weiter. PCIE1 und PCMSK1 sind dem Compiler unbekannt. 
Also hier Forum gesucht und gefunden: die Headerdatei iotn2313a.h mit 
Texteditor um die fehlenden Punkte erweitert(#Define XXXXXX ).

Immer noch nada....Der PIN Change Interrupt geht nicht. Der 2313A 
verhält sich so wie sein Vorgänger 2313, mit PCIE nur an PORTB.

Nun weiß ich gar nicht mehr weiter und hoffe auf eure Hilfe. Ich habe 
mich zwar ein wenig in die Materie eingelesen, bin aber noch gaaaanz 
weit am Anfang der CPU Programmierung, daher bitte nicht sofort 
erschlagen....

Glück auf

Reinhard Pfeiffer

von M. N. (Gast)


Lesenswert?

Reinhard P. schrieb:
> PINA = 0x03;

Was willst Du hiermit bezwecken?
Ich weiß aus dem Kopf nicht, ob der 2313A diesen Befehl richtig 
auswertet, wenn Du aber PORTA = 0x03 schreiben wolltest, solltest Du das 
auch so machen.

von tiny (Gast)


Lesenswert?

die Datei:  tn2313Adef.inc habe ich auch noch angepasst und zwar unter 
External Interrupt von PCIE nach PCIE1, PCIE2 und PCIE0 erweitert.

; ***** EXTERNAL_INTERRUPT ***********
; GIMSK - General Interrupt Mask Register
.equ  PCIE1  = 3  ;
.equ  PCIE2  = 4  ;
.equ  PCIE0  = 5  ;
.equ  INT0  = 6  ; External Interrupt Request 0 Enable
.equ  INT1  = 7  ; External Interrupt Request 1 Enable


Beitrag "Attiny2313A in AVR Toolchain (noch) nicht unterstützt?"

von Reinhard P. (reinhard_p)


Lesenswert?

Hallo tiny, hallo M.N.,

an tiny:

die Änderung/Ergänzung der Datei tn2313Adef.inc brachte leider bei mir 
nicht den gewünschten Erfolg. Hast du vielleicht einen funktionierenden 
Codeschnipsel für mich, oder weitere Ansatzpunkte zum forschen???

an M.N.

das PINA = 0x03 funktioniert beim 2313A wunderbar und stellt die 
logischen Werte der Hardware am Chip da ( PIN4 und PIN5 haben als 
Startwert H-Pegel ).

Glück auf

Reinhard Pfeiffer

von tiny (Gast)


Lesenswert?

Ich verwende z.B. einen Drehencoder am Port A des 2313A.
Encoderleitung A hängt an PA0 und Leitung B an PA1

Initialisiert habe ich dann beide Port A Pins als Eingang mit Pull-Up.

sowie den Pin-Change-Interrupt:


// Bit PCIE1 setzen (Pin Change Interrupt Enable 1 für PCINT an einem 
der Port A Pins)

GIMSK |= (1 << PCIE1);


// Maskenregister 1 für Pin Change Interrupt an Port A
// Bit PCINT8 setzen (Pin Change Interrupt an PA0 aktivieren) Encoder A

PCMSK1 |= (1 << PCINT8);



und die Interruptroutine sieht wie folgt aus:

// ISR für den Drehencoder Interrupt
ISR (PCINT_A_vect)
// Achtung !!!: PCINT0 -> PCINT_B_vect  PCINT1 -> PCINT_A_vect  PCINT2 
-> PCINT_D_vect
  {
    ***auszuführender Code***

    EIFR |= (1<< PCIF1); //  Flag löschen

  }

von spess53 (Gast)


Lesenswert?

Hi

>Ich verwende z.B. einen Drehencoder am Port A des 2313A.
>Encoderleitung A hängt an PA0 und Leitung B an PA1

Dazu nimmt man keinen Pin-Change-Interrupt:

http://www.mikrocontroller.net/articles/Drehgeber

MfG Spess

von Peter D. (peda)


Lesenswert?

Reinhard P. schrieb:
> Im Code, so wie er dort steht, funktionieren die Pin Chnage Interrupts
> des kpl. PORTB Registers

Und warum zeigst Du uns das?

Du mußt schon den exakten Code zeigen, mit dem Du Probleme hast. 
Hellsehen ist nicht unser Ding.
Und erstmal die fehlenden Defines direkt einfügen, also mit dem 
originalen *.h compiliert.

von M. N. (Gast)


Lesenswert?

spess53 schrieb:
> Dazu nimmt man keinen Pin-Change-Interrupt:

Bei optischen Drehgebern oder solchen mit Hallsensoren sind in der Tat 
die Eingänge INT0 und INT1 besser geeignet. Siehe hier ;-) 
Beitrag "4-fach Flankenauswertung per Interrupt mit ATmega48/88"

von M. N. (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Und erstmal die fehlenden Defines direkt einfügen, also mit dem
> originalen *.h compiliert.

... und insbesondere welche Adresse für PCMSK1 verwendet wurde.
0x04 oder 0x24?

von tiny (Gast)


Lesenswert?

spess53 schrieb:
> Dazu nimmt man keinen Pin-Change-Interrupt:


im Link über Drehgeber steht, dass die Methode nicht optimal ist, weil 
sie durch einen pendelnden/prellenden Encoder die CPU stark belastet.

Aber genau das fängt doch die Entrpellung auf oder sehe ich das falsch?

von Reinhard P. (reinhard_p)


Lesenswert?

Hallo tiny,


rechtz herzlichen Dank für die Codeschnipzel. Leider will weder der 
Debugger des Studio4 noch der des Studio6 den Pin-Change-Interrupt 
auslösen ( mit jeweils zur IDE passend geänderten Dateien ).

Ich werde morgen mal den Code in den Chip übertragen und sehen ob er 
dort seine Dienste verrichtet.

Ich melde mich morgen .....


Glück auf

Reinhard Pfeiffer

von M. N. (Gast)


Lesenswert?

tiny schrieb:
> Aber genau das fängt doch die Entrpellung auf oder sehe ich das falsch?

Sofern die Interrupts direkt als Auf-Ab-Impulse gewertet werden, findet 
keine Entprellung statt. Sofern man keine Drehgeber mit mechanischen 
Kontakten verwendet, prellt allerdings auch nichts.

Wichtig bei der Auswertung per ISR ist, dass diese sehr schnell 
ausgeführt wird und vom Drehgeber keine höhere Impulsfrequenz erzeugt 
wird, als die ISRs diese verarbeiten können.

Meine Erfahrung:
Für schnelle Drehgeber die nicht prellen, ist die direkte Auswertung per 
Interrupt sinnvoll. Der Prozessor wird diesbezüglich nur bei Bedarf 
aktiv.
Bei Drehgebern mit mechanischen Kontakten und relativ niedriger 
Impulsfrequenz (<10kHz) ist das Abtasten der Port-Pins im festen 
Zeitraster und anschließende Auswertung per Software sinnvoll. Die 
Ruhelast durch permantes Abtasten bleibt recht gering (geschätzt <3% bei 
10kHz).

von tiny (Gast)


Lesenswert?

M. N. schrieb:
> Bei Drehgebern mit mechanischen Kontakten und relativ niedriger
> Impulsfrequenz (<10kHz) ist das Abtasten der Port-Pins im festen
> Zeitraster und anschließende Auswertung per Software sinnvoll.

D.h. in meinem Fall (Drehencoder als Eingabegerät per Handbetrieb) 
müsste ich in regelmäßigen Abständen Leitung A abfragen und mit dem 
Ergebnis der vorherigen Abfrage vergleichen. Bei Unterschied dann 
Leitung B abfragen und auswerten. Das Ganze dann halt deutlich 
schneller, als man den Encoder per Hand verdrehen kann.

von M. N. (Gast)


Lesenswert?

tiny schrieb:
> D.h. in meinem Fall (Drehencoder als Eingabegerät per Handbetrieb)
> müsste ich in regelmäßigen Abständen Leitung A abfragen und mit dem
> Ergebnis der vorherigen Abfrage vergleichen.

Ich weiß jetzt nicht, welchen Drehgeber Du verwendest, aber es ist 
einfacher, Phase-A und Phase-B an einem Port zu betreiben, mit
"neuer_wert = PINx" einzulesen und auf Änderungen abzufragen:
wechsel = alter_wert ^ neuer_wert;
Sofern wechsel == 0, ist nichts passiert und nichts weiter auszuwerten.

Ein Beispielprogramm "Quadrat_CNT45.c" findest Du hier 
http://www.mino-elektronik.de/7-Segment-Variationen/LCD.htm#lcd4
Dort ist es die "ISR (TIMER1_OVF_vect)", die hinreichend schnell 
aufgerufen wird (mit 3,9 bzw. 31 kHz) und die Auswertung aller vier 
Flanken erledigt.

Allerdings weicht unser Gespräch schon deutlich vom eigentlichen Thema 
ab.

von tiny (Gast)


Lesenswert?

M. N. schrieb:
> Allerdings weicht unser Gespräch schon deutlich vom eigentlichen Thema
> ab.

Danke für die Tipps und ich klinke mich aus

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
Noch kein Account? Hier anmelden.