Forum: Mikrocontroller und Digitale Elektronik avrasm I/O Pin in externen Interrupt toggeln ATmega8


von TheChemixInc (Gast)


Lesenswert?

Hallo

ich habe leider kaum Erfahrung in einer Hochsprache (weil mir nie 
eingefallen ist, was ich programmieren sollte, was es nicht schon gibt). 
Weil ich gerade sehr viel zeit an der Hand habe, habe ich mit Elektronik 
angefangen und mich zu Mikrocontrollern vorgearbeitet. Weil die 
Tutorialreihe, die ich dazu benutzte die Mikrocontroller in Assembler 
programmiert, möchte ich das auch tun. Sicher werde ich danach auf C 
wechseln, aber das erstmal in Assembler zu machen hilft mir sehr zum 
Verständnis der Hardware und wie diese arbeitet.

Das zur Einführung, hier mein Problem:

Zum Verständnis wie ich Taster per Interrupts einbinden kann habe ich 
einen einfachen Aufbau mit einem ATTiny13 zusammengesteckt:

|----Taster---- -ATTiny13 PortB1 (INT0) mit Pull-Up
Gnd

|----LED---Widerstand---- -ATTiny13 PortB0
Vcc

Dann habe ich dieses Programm geschrieben (wenn dieses gespame 
unerwünscht ist, kann ich die Listings auch in ein Pastebin kopieren und 
hier verlinken):
1
;
2
; ***************************************************
3
; * Taster mit INT0-Interrupt                 *
4
; *                          *
5
; *  Bei Tasterdruck (an PB1 = INT0) wird eine    *
6
; *  LED (an PB0) ein bzw. ausgeschalten        *
7
; *                          *
8
; *  Version 1.0      08.11.2016  *
9
; *                          *
10
; *  todo: Softwareenprellung!            *
11
; *  Hardwareentprellung: 100uF Kond. parallel zum  *
12
; *              Taster          *
13
; *                          *
14
; ***************************************************
15
;
16
.NOLIST
17
.INCLUDE "tn13def.inc"
18
.LIST
19
20
;------------------Register--------------------------
21
.def temp = R16
22
.def temp2 = R17
23
24
;------------------Ports-----------------------------
25
26
27
;------------------Reset und Interruptvariablen (fuer ATTiny13!)
28
29
.CSEG ; Assemblieren in den Flashspeicher (Code Segment)
30
.ORG 0 ; Adresse auf Null (Reset- und Interruptvektoren beginnen bei Null)
31
  rjmp main ; Reset Vektor, Sprung zur Initiierung
32
  rjmp int0_handler ; INT0-Int, aktiv
33
  reti ; PCINT-Int, nicht aktiv
34
  reti ; TIM0_OVF, nicht aktiv
35
  reti ; EE_RDY-Int, nicht aktiv
36
  reti ; ANA_COMP-Int, nicht aktiv
37
  reti ; TIM0_COMPA-Int, nicht aktiv
38
  reti ; TIM0_COMPB-Int, nicht aktiv
39
  reti ; WDT-Int, nicht aktiv
40
  reti ; ADC-Int, nicht aktiv
41
42
;------------------Interrupt Service Routinen--------
43
44
int0_handler:  ; bei Tastendruck:
45
46
  in temp, PORTB0 ; Auslesen von PB0
47
  cpi temp,0    ; ist PB0 = 0 (LED aus)?
48
  breq it_is    ; ja --> it_is 
49
  it_isnt:    ; PD0 = 1, LED ist schon an
50
    ldi temp2,(0<<DDB0)
51
    out DDRB, temp2  ; Schalte LED aus
52
  rjmp end
53
  it_is:      ; PB0 = 0, LED ist aus
54
    ldi temp2,(1<<DDB0)
55
    out DDRB, temp2  ; Schlate LED an
56
  end:
57
reti
58
  
59
;------------------Programmstart bei Reset-----------
60
61
62
main:
63
64
  ; Stapel-Init
65
  ldi temp,LOW(RAMEND)
66
  out SPL,temp;
67
68
  ldi temp,(0<<DDB0)|(0<<DDB1)
69
  out DDRB,temp
70
  ldi temp,(1<<PORTB1)
71
  out PORTB,temp
72
73
  ;Schlafen ermoeglichen, Ext. Int
74
  ldi temp,(1<<SE)|(1<<ISC01) ; Schlafen, fallende Flanke
75
    out MCUCR, temp
76
77
    ldi temp, 1<<INT0  ;INT0 und INT1 aktivieren
78
    out GIMSK, temp
79
80
    sei                   ;Interrupts allgemein aktivieren
81
82
loop:  ; Schleife zum schlafen
83
  sleep
84
  nop
85
  rjmp loop

Dieses Programm funktioniert: drückt man den Taster geht die LED an, 
drückt man ihn erneut geht sie aus. Ganz simpel.

Jetzt kommt mein Problem: aus Gründen bin ich auf einen ATmega8 
umgestiegen. Die Schaltung habe ich folgendermaßen umgebaut:

|----Taster---- -ATmega8 PortD2 (INT0) mit Pull-Up
Gnd

|----LED--Widerstand----- -ATmega8 PortD0
Vcc

Also praktisch das Gleiche wie beim ATTiny13. Dann habe ich das Programm 
entsprechend umgeschrieben (also die Registernamen geändert), die 
Vektorliste erweitert und auch die Bits für den Interrupt geändert, wie 
im Datenblatt das mega8 beschrieben.
Das Programm sieht nun so aus:
1
;
2
; ***************************************************
3
; * Taster mit INT0-Interrupt                 *
4
; *                          *
5
; *  Bei Tasterdruck (an PB1 = INT0) wird eine    *
6
; *  LED (an PB0) ein bzw. ausgeschalten        *
7
; *                          *
8
; *  Version 1.0    08.11.2016  *
9
; *                          *
10
; *  todo: Softwareenprellung!            *
11
; *  Hardwareentprellung: 100uF Kond. parallel zum  *
12
; *              Taster          *
13
; *                          *
14
; ***************************************************
15
;
16
.NOLIST
17
.INCLUDE "m8def.inc"
18
.LIST
19
20
;------------------Register--------------------------
21
.def temp = R16
22
.def temp2 = R17
23
.def SREG_temp = R18
24
25
;------------------Ports-----------------------------
26
27
28
;------------------Reset und Interruptvariablen (fuer ATmega8!)
29
30
;.CSEG ; Assemblieren in den Flashspeicher (Code Segment)
31
.ORG 0 ; Adresse auf Null (Reset- und Interruptvektoren beginnen bei Null)
32
  rjmp main ; Reset Vektor, Sprung zur Initiierung
33
  rjmp int0_handler ; INT0-Int, aktiv  Ext. int. request 0
34
  reti ; INT1-Int, nicht aktiv    Ext. int. request 1
35
  reti ; Timer2-COMP, nicht aktiv    Timer2 Compare Match
36
  reti ; Timer2-OCF, nicht aktiv    Timer2 Overflow
37
  reti ; Timer1-CAPT, nicht aktiv    Timer1 Capture Event
38
  reti ; Timer1-COMPA, nicht aktiv  Timer1 Compare Match A
39
  reti ; Timer1-COMPB, nicht aktiv  Timer1 Compare Match B
40
  reti ; Timer1-OVF, nicht aktiv    Timer1 Overflow
41
  reti ; Timer0-OVF, nicht aktiv    Timer0 Overflow
42
  reti ; SPI, STC, nicht aktiv    Serial transfer Complete
43
  reti ; USART, TXC, nicht aktiv    USART, Rx Complete
44
  reti ; USART, UDRE, nicht aktiv    USART, Data Register Empty
45
  reti ; USART, TXC, nicht aktiv    USART, Tx Complete
46
  reti ; ADC-Int, nicht aktiv      ADC Conversion Complete
47
  reti ; EE_RDY, nicht aktiv      EEPROM Ready
48
  reti ; ANA_COMP, nicht aktiv    Analog Comparator
49
  reti ; TWI, nicht aktiv        Two-wire Serial Interface
50
  reti ; SPM_RDY, nicht aktiv      Store program memory ready
51
52
;------------------Interrupt Service Routinen--------
53
54
int0_handler:  ; bei Tastendruck:
55
  push temp        ; Das SREG in temp sichern. Vorher
56
  in   SREG_temp, SREG  ; muss natürlich temp gesichert werden
57
58
  in temp, PORTD0 ; Auslesen von PD0
59
  cpi temp,0    ; ist PD0 = 0 (LED aus)?
60
  breq it_is    ; ja --> it_is 
61
  it_isnt:    ; PD0 = 1, LED ist schon an
62
    cbi DDRD,DDD0
63
  rjmp end
64
  it_is:      ; PD0 = 0, LED ist aus
65
    sbi DDRD,DDD0
66
  end:
67
68
  out SREG, SREG_temp  ; Die Register SREG und temp wieder
69
  pop temp      ; herstellen
70
reti
71
72
;------------------Programmstart bei Reset-----------
73
74
75
main:
76
77
  ldi temp, LOW(RAMEND)
78
  out SPL, temp
79
  ldi temp, HIGH(RAMEND)
80
  out SPH, temp
81
  
82
  ldi temp,(0<<DDD0)|(0<<DDD2)|(0<<DDD3)
83
  out DDRD, temp
84
  ldi temp,(1<<PD2)|(1<<PD3)
85
  out PORTD,temp
86
87
  ; Ext. Int0
88
  ldi temp,(1<<SE)|(1<<ISC01)|(1<<ISC11)  ; fallende Flanke und schlafen ein
89
    out MCUCR, temp
90
91
    ldi temp,(1<<INT0)|(1<<INT1)  ;INT0 aktivieren
92
    out GICR, temp
93
    sei  ;Interrupts allgemein aktivieren
94
95
 loop:   ; Schleife zum schlafen
96
  sleep
97
  nop
98
  rjmp loop

Das Problem: wenn ich auf den Taster drücke geht die LED an. Aber wenn 
ich noch mal drauf drücke geht sie nicht mehr aus!
Wenn ich das Programm erweitere und einen zweiten Taster an INT1 
anschließe kann ich die LED mit dem einen an- und dem anderen ausmachen, 
also müssen die Interruptroutinen funktionieren.

Das Problem muss im Auslesen des Pins stecken. Ich bekomme aber für mein 
Leben nicht heraus warum es auf dem Tiny geht und auf dem mega geht es 
nicht.

Könnte mir das bitte jemand erklären oder sagen wo mein Fehler liegt?

von Stefan F. (Gast)


Lesenswert?

Ich würde vorschlagen, das Programm zu debuggen - notfalls im Simulator.

von Helmar Z. (helmar1)


Lesenswert?

Hallo

 in temp, PORTD0 ; Auslesen von PD0        hier werden 8 Bits gelesen
  cpi temp,0    ; ist PD0 = 0 (LED aus)?   und verglichen
  breq it_is    ; ja --> it_is
  it_isnt:    ; PD0 = 1, LED ist schon an
    cbi DDRD,DDD0                          hier wird nur EIN Bit gesetzt
  rjmp end                                 oder geloscht
  it_is:      ; PD0 = 0, LED ist aus       Anwort geht nicht !!!!
    sbi DDRD,DDD0
  end:

  out SREG, SREG_temp  ; Die Register SREG und temp wieder
  pop temp      ; herstellen
reti


 gruß Helmar

von Paul B. (paul_baumann)


Lesenswert?

In dem esrten Programm hast Du 2 Temp-Register (Temp und Temp2) benutzt.
In dem Programm für den Mega 8 nur TEMP. Vielleicht steht dadurch 
irgendwelcher Mumpitz noch von der letzten Benutzung drin, der den 
Effekt bewikt.

MfG Paul

von Icke ®. (49636b65)


Lesenswert?

Tip:
Das Register DDRD ist das Datenrichtungsregister des Ports D. Es legt 
fest, ob der Pin als Ein- oder Ausgang benutzt wird. Zum Schalten der 
Zustände eines als Ausgang definierten Pins muß ins Register PORTD 
geschrieben werden ;-)

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.