2313A PIN Change Interrupt, zweiter Versuch

OP #3250625
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
Gast #3250714
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?"
OP #3250785
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
Gast #3251547
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

  }
OP #3251669
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
Gast #3251799
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).
Gast #3251985
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.
Gast #3252093
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren