Forum: Mikrocontroller und Digitale Elektronik AVR Studio - Programmlänge angeblich zu groß


von A. B. (developer_x)


Angehängte Dateien:

Lesenswert?

Sehr geehrtes Forum,
ich habe folgendes Problem :
Ich bin gerade am Lernen von Interrupts, habe mir da ein Programm
geschrieben, und was passiert jetzt? Mein AVR Studio sagt mir beim 
Debuggen, dass das Programm zu groß wäre, komischer Weise (Siehe Bild) :
4KB Flash Speicher, gerade ca. 360 Bytes benutzt, warum steht dann da 
over?

Mein Code im Folgenden:
1
.include "M48PAdef.inc"
2
3
; //////////////////////////////////////////////////////////////
4
;  ExternInterrupt
5
;  Kevin Riehl - 29.03.2013
6
;  
7
;  Dieses Programm lässt ein Hauptprogramm laufen
8
;  und wird, bei einem Tastendruck an C0 unterbrochen,
9
;  und startet damit eine Interruptsubroutine
10
;  
11
; //////////////////////////////////////////////////////////////
12
; /////// Defintionen
13
; //////////////////////////////////////////////////////////////
14
15
.DEF STACK_LOW = R16
16
.DEF STACK_HIG = R17
17
18
.DEF COUNTER = R25
19
; //////////////////////////////////////////////////////////////
20
; Stackpointerinitialisierung
21
  LDI STACK_LOW, LOW(RAMEND)    ;Stackpointer initialisieren
22
  OUT SPL, STACK_LOW
23
  LDI STACK_HIG, HIGH(RAMEND)   ;Stackpointer initialisieren
24
  OUT SPH, STACK_HIG
25
; //////////////////////////////////////////////////////////////
26
27
; LCD INITIALISIEREN
28
RCALL Wait1000MS
29
RCALL LCD_INIT
30
31
; INTERRUPTS INITIALISIEREN bei PCINT8
32
SEI
33
.ORG 0xC08
34
  RJMP interrupt
35
36
.CSEG
37
38
; HAUPTPROGRAMM
39
main:
40
LDI COUNTER,'0'
41
42
a :
43
  MOV INFO,COUNTER
44
  RCALL LCD_HOME
45
  RCALL LCD_DATA
46
  RCALL Wait1000ms
47
  CPI COUNTER,'9'+1
48
  BRNE a
49
50
rjmp main
51
52
53
interrupt:
54
CLI
55
LDI ZL,LOW (text*2)
56
LDI ZH,HIGH(text*2)
57
58
RCALL LCD_LINE2
59
60
loop:
61
  LPM
62
63
; Testen ob Ende
64
  TST R0
65
  BREQ b
66
67
; Zeichen ausgegeben
68
  MOV INFO,R0
69
  RCALL LCD_DATA
70
71
; Zeiger auf nächstes Byte setzen
72
  ADIW ZL,1
73
  RCALL Wait1000MS
74
  RJMP loop
75
76
b :
77
  RCALL LCD_LINE1
78
  SEI
79
  RETI
80
81
; //////////////////////////////////////////////////////////////
82
83
.include "LCD_Lib.asm"
84
85
text: .DB "NEBENROUTINE :-)",0

Ach und nebenbei :
Ich benutze den Atmega48pa, und will am PC0 einen Interrupt auslösen, so 
richtig oder nicht?

Danke für eure Hilfe!
m.f.G. Developer_X

von Stefan E. (sternst)


Lesenswert?

K. R. schrieb:
> Ich bin gerade am Lernen von Interrupts, habe mir da ein Programm
> geschrieben, und was passiert jetzt? Mein AVR Studio sagt mir beim
> Debuggen, dass das Programm zu groß wäre, komischer Weise (Siehe Bild) :
> 4KB Flash Speicher, gerade ca. 360 Bytes benutzt, warum steht dann da
> over?
1
.ORG 0xC08
Weil du Teile deines Programms außerhalb des existierenden Flash 
platziert hast.

von A. B. (developer_x)


Lesenswert?

Ich dachte das würde meinem Mikrocotnroller sagen, dass er ein Interrupt 
von Port CO bekommen soll, PCINT8.

Wie kann ich denn einen Interrupt von PCINT8 setzen, das heißt ihm 
sagen, wenn Port C0 an, durch button, also PCInt8 an, dann soll die 
Subroutine "interrupt" aufgerufen werden.

Wie kann ich das machen?

Danke,
m.f.G. Developer_X

von Dussel (Gast)


Lesenswert?

Entweder an den Anfang die ganze Interrupttabelle hinschreiben oder die 
richtige Adresse aus dem Datenblatt suchen. Beim ATMega8 wäre das zum 
Beispiel für externe Interrupts die Adressen 1 und 2.
Der Vorteil der Tabelle ist, dass aus Versehen aktivierte Interrupts das 
Programm nicht beeinflussen.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

1. Der Mega48/88/168/328 hat nur Interruptvektoren für die drei PCINT 
Gruppen , nicht für jeden Pin einen eigenen. Pin PCINT8 löst also 
Interrupt PCINT1 aus.
2. Deinem Programm fehlt die Vektortabelle ab ORG 0x00. Siehe das 
Datenblatt unter 'Interrupt Vectors in ATMega48P':
1
The most typical and general program setup for the Reset and Interrupt Vector Addresses in
2
ATmega48P is:
3
Address Labels Code Comments
4
0x000          rjmp  RESET          ; Reset Handler
5
0x001          rjmp  EXT_INT0       ; IRQ0 Handler
6
0x002          rjmp  EXT_INT1       ; IRQ1 Handler
7
0x003          rjmp  PCINT0         ; PCINT0 Handler
8
0x004          rjmp  PCINT1         ; PCINT1 Handler
9
0x005          rjmp  PCINT2         ; PCINT2 Handler
10
0x006          rjmp  WDT ; Watchdog Timer Handler
11
0x007          rjmp  TIM2_COMPA     ; Timer2 Compare A Handler
12
0x008          rjmp  TIM2_COMPB     ; Timer2 Compare B Handler
13
0x009          rjmp  TIM2_OVF       ; Timer2 Overflow Handler
14
0x00A          rjmp  TIM1_CAPT      ; Timer1 Capture Handler
15
0x00B          rjmp  TIM1_COMPA     ; Timer1 Compare A Handler
16
0x00C          rjmp  TIM1_COMPB     ; Timer1 Compare B Handler
17
0x00D          rjmp  TIM1_OVF       ; Timer1 Overflow Handler
18
0x00E          rjmp  TIM0_COMPA     ; Timer0 Compare A Handler
19
0x00F          rjmp  TIM0_COMPB     ; Timer0 Compare B Handler
20
0x010          rjmp  TIM0_OVF       ; Timer0 Overflow Handler
21
0x011          rjmp  SPI_STC        ; SPI Transfer Complete Handler
22
0x012          rjmp  USART_RXC      ; USART, RX Complete Handler
23
0x013          rjmp  USART_UDRE     ; USART, UDR Empty Handler
24
0x014          rjmp  USART_TXC      ; USART, TX Complete Handler
25
0x015          rjmp  ADC ; ADC Conversion Complete Handler
26
0x016          rjmp  EE_RDY         ; EEPROM Ready Handler
27
0x017          rjmp  ANA_COMP       ; Analog Comparator Handler
28
0x018          rjmp  TWI ; 2-wire Serial Interface Handler
29
0x019          rjmp  SPM_RDY        ; Store Program Memory Ready Handler
Da sind alle Vektoren drin, die Interrupts auslösen. Entweder machst du 
per
1
.ORG 0x004 
2
      rjmp meinPCINT1
den einzelnen Vektor oder du baust die komplette Tabelle nach und lässt 
unbenutzte IRQs auf ein RETI laufen. Der Reset Vektor bei ORG 0x000 ist 
aber zwingend notwendig, sonst startet dein Programm irgendwo.

von Dietrich L. (dietrichl)


Lesenswert?

K.R., da Deine Interrupt-Kenntnisse offensichlich noch erhebliche Lücken 
haben, schau mal hier:
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Interrupts

von c-hater (Gast)


Lesenswert?

K. R. schrieb:

> Ich dachte das würde meinem Mikrocotnroller sagen, dass er ein Interrupt
> von Port CO bekommen soll, PCINT8.

Oh Gott...

Wie wäre es, wenn du erstmal die verschissene Dokumentation lesen 
würdest, bevor du dich an's Programmieren machst?

> Wie kann ich denn einen Interrupt von PCINT8 setzen, das heißt ihm
> sagen, wenn Port C0 an, durch button, also PCInt8 an, dann soll die
> Subroutine "interrupt" aufgerufen werden.

Eigentlich garnicht.

Bestenfalls kannst du dafür sorgen, daß

1) überhaupt ein Interrupt ausgelöst wird, wenn es an diesem Portpin 
wackelt.

Dazu mußt du bei PCINT-Interrupts typischerweise das zuständige 
Maskenregister für den Portpin setzen und zusätzlich das 
Interruptmaskenregister für den zuständigen PCINT-Interrupt. Welche 
Register das jeweils genau sind, ist deviceabhängig und steht in dem 
verschissenen Datenblatt.

2) Der Interruptvektor der benutzten Vektortabelle den Code deiner ISR 
durchläuft.

Dazu mußt du erstmal festlegen, welche Vektortabelle benutzt wird (oder 
dich mit der standardmäßig aktiven ab Adresse 0 abfinden), dann dort im 
richtigen Vektor entweder einen Sprungbefehl zum Code deiner ISR 
platzieren oder direkt deine ISR (was allerdings nur geht, solange du 
die dadurch ggf. überschriebenen Vektoren nicht noch für andere Zwecke 
benötigst.

Welche Vektortabellen möglich sind, wie man sie auswählt, welche 
Vektoren existieren und wo genau sie in der Tabelle liegen, als das ist 
wieder deviceabhängig und steht deshalb im verschissenen Datenblatt, 
welches du verdammt nochmal einfach mal lesen solltest!

von A. B. (developer_x)


Lesenswert?

An Alle anderen außer den Vorredner :
Ich habe mir ja das Datenblatt vom Atmega48PA durchgelesen, da steht 
aber nichts davon, dass INT1 für PICINT8 bis 14 verantwortlich wäre, das 
ist nur bei den Flagveränderungen so.

Des Weiteren steht da ja, dass man einstellen kann, im Register :
EIMSK welche von den Interrupts (0 oder 1) abgefragt werden, aber das 
Register existiert in meinem Assembler Editor nicht, und wenn ich im 
Datenblatt die Registeraufteilung finde, und die entsprechende Adresse 
im Code anstatt EIMSK hinterlege, meint er es wäre ein invalides 
Register.

Was mich auch noch wundert ist, dass .ORG und Reset nur am Anfang des 
Codes geschrieben werden können, mein Code sieht wie folgt aus :
1
; INTERRUPTS INITIALISIEREN bei PCINT8
2
SEI
3
4
.ORG 0x004 
5
      rjmp interrupt
6
RESET:
7
8
.include "M48PAdef.inc"
9
10
; //////////////////////////////////////////////////////////////
11
;  ExternInterrupt
12
;  Kevin Riehl - 29.03.2013
13
;  
14
;  Dieses Programm lässt ein Hauptprogramm laufen
15
;  und wird, bei einem Tastendruck an C0 unterbrochen,
16
;  und startet damit eine Interruptsubroutine
17
;  
18
; //////////////////////////////////////////////////////////////
19
; /////// Defintionen
20
; //////////////////////////////////////////////////////////////
21
22
.DEF STACK_LOW = R16
23
.DEF STACK_HIG = R17
24
25
.DEF COUNTER = R25
26
; //////////////////////////////////////////////////////////////
27
; Stackpointerinitialisierung
28
  LDI STACK_LOW, LOW(RAMEND)    ;Stackpointer initialisieren
29
  OUT SPL, STACK_LOW
30
  LDI STACK_HIG, HIGH(RAMEND)   ;Stackpointer initialisieren
31
  OUT SPH, STACK_HIG
32
; //////////////////////////////////////////////////////////////
33
34
; LCD INITIALISIEREN
35
RCALL Wait1000MS
36
RCALL LCD_INIT
37
38
LDI 0x3D,0b00000010 ; DASS SEI EIMSK
39
40
; HAUPTPROGRAMM
41
main:
42
LDI COUNTER,'0'
43
44
a :
45
  MOV INFO,COUNTER
46
  RCALL LCD_HOME
47
  RCALL LCD_DATA
48
  RCALL Wait1000ms
49
  CPI COUNTER,'9'
50
  BRNE a
51
52
rjmp main
53
54
55
interrupt:
56
CLI
57
LDI ZL,LOW (text*2)
58
LDI ZH,HIGH(text*2)
59
60
RCALL LCD_LINE2
61
62
loop:
63
  LPM
64
65
; Testen ob Ende
66
  TST R0
67
  BREQ b
68
69
; Zeichen ausgegeben
70
  MOV INFO,R0
71
  RCALL LCD_DATA
72
73
; Zeiger auf nächstes Byte setzen
74
  ADIW ZL,1
75
  RCALL Wait1000MS
76
  RJMP loop
77
78
b :
79
  RCALL LCD_LINE1
80
  SEI
81
  RETI
82
83
; //////////////////////////////////////////////////////////////
84
85
.include "LCD_Lib.asm"
86
87
text: .DB "NEBENROUTINE :-)",0

Was genau muss ich jetzt machen, ich check es nicht, auch nach dem 
Tutorial im Forum, das mir bereitgestellt wurde nicht, wenn ich das 
ganze einfach am INT1 oder INT0 Pin mache, gehts ja einfach, wie kann 
ich aber gezielt den Interrupt auf nur einen PIN, nämlich PC0 setzen?

In meinem Buch wirds nicht erklärt!

von Spess53 (Gast)


Lesenswert?

Hi

>Was mich auch noch wundert ist, dass .ORG und Reset nur am Anfang des
>Codes geschrieben werden können, mein Code sieht wie folgt aus :

Stimmt nicht. Kann man überall benutzen, wenn man weiß was man macht.

>SEI

>.ORG 0x004
>      rjmp interrupt
>RESET:

Damit plazierst du das 'RESET' auf die Adresse 0x0005 und das ist 
falsch.

MfG Spess

von Peter D. (peda)


Lesenswert?

Datenblatt Abschnitt: 12. External Interrupts

"
The
pin change interrupt PCI2 will trigger if any enabled PCINT23...16 pin 
toggles. The pin change
interrupt PCI1 will trigger if any enabled PCINT14...8 pin toggles. The 
pin change interrupt PCI0
will trigger if any enabled PCINT7...0 pin toggles. The PCMSK2, PCMSK1 
and PCMSK0 Registers
control which pins contribute to the pin change interrupts.
"

von A. B. (developer_x)


Lesenswert?

Erstma danke, also ist INT1 für PCINT8 zuständig^^.

In dem Tutorial heißt es, dass man dann ganz einfach einem Interrupt 
eine ISR zuweisen kann indem man folgendes macht :
1
.include "m8def.inc"
2
 
3
.def temp = r16
4
 
5
.org 0x000
6
         rjmp main            ; Reset Handler
7
.org INT0addr
8
         rjmp int0_handler    ; IRQ0 Handler
9
.org INT1addr
10
         rjmp int1_handler    ; IRQ1 Handler
11
 
12
 
13
main:                         ; hier beginnt das Hauptprogramm
14
 
15
         ldi temp, LOW(RAMEND)
16
         out SPL, temp
17
         ldi temp, HIGH(RAMEND)
18
         out SPH, temp
19
 
20
         ldi temp, 0x00
21
         out DDRD, temp
22
 
23
         ldi temp, 0xFF
24
         out DDRB, temp
25
 
26
         ldi temp, (1<<ISC01) | (1<<ISC11) ; INT0 und INT1 auf fallende Flanke konfigurieren
27
         out MCUCR, temp
28
 
29
         ldi temp, (1<<INT0) | (1<<INT1) ; INT0 und INT1 aktivieren
30
         out GICR, temp
31
 
32
         sei                   ; Interrupts allgemein aktivieren
33
 
34
loop:    rjmp loop             ; eine leere Endlosschleife
35
 
36
int0_handler:
37
         sbi PORTB, 0
38
         reti
39
 
40
int1_handler:
41
         cbi PORTB, 0
42
         reti

Wenn ich das mache, kommen fehlermeldungen auf, weil mein Code dann 
irgendwie verschoben ist, komisch, im tutorial klappt es angeblich :
1
; INTERRUPTS INITIALISIEREN bei PCINT8
2
3
.org 0x000
4
         rjmp start            ; Reset Handler
5
.org INT0addr
6
     NOP
7
.org INT1addr
8
         rjmp interrupt    ; IRQ1 Handler
9
10
11
.include "M48PAdef.inc"
12
13
; //////////////////////////////////////////////////////////////
14
;  ExternInterrupt
15
;  Kevin Riehl - 29.03.2013
16
;  
17
;  Dieses Programm lässt ein Hauptprogramm laufen
18
;  und wird, bei einem Tastendruck an C0 unterbrochen,
19
;  und startet damit eine Interruptsubroutine
20
;  
21
; //////////////////////////////////////////////////////////////
22
; /////// Defintionen
23
; //////////////////////////////////////////////////////////////
24
25
start:
26
SEI
27
28
.DEF STACK_LOW = R16
29
.DEF STACK_HIG = R17
30
31
.DEF COUNTER = R25
32
;... hier gehts weiter wie vorher

Fehlermeldung :
1
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(5): error: Overlap in .cseg: addr=0x0 conflicts with 0x0:0x1
2
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(6): error: Use of undefined or forward referenced symbol 'INT0addr' in .org
3
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(7): error: Overlap in .cseg: addr=0x0 conflicts with 0x0:0x1
4
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(8): error: Use of undefined or forward referenced symbol 'INT1addr' in .org
5
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(9): error: Overlap in .cseg: addr=0x0 conflicts with 0x0:0x1

von DRJ (Gast)


Lesenswert?

.include "M48PAdef.inc"

Muss am Anfang stehen,vor INT0addr und INT1addr.
Darin sind sie erst definiert.

Und die Interrupts erst freigeben nachdem
der Stack initialisiert wurde.

von Reinhard R. (reirawb)


Lesenswert?

K. R. schrieb:
> Ich habe mir ja das Datenblatt vom Atmega48PA durchgelesen, da steht
> aber nichts davon, dass INT1 für PICINT8 bis 14 verantwortlich wäre...

Datenblatt:
13. External Interrupts
The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] 
pin toggles.

Was Du benutzen willst ist nicht INT1 (Vector 3) sondern PCINT1 (Vector 
5). Weiter steht dort:

The PCMSK2, PCMSK1 and PCMSK0 Registers control which pins contribute to 
the pin change interrupts.

Das heist für Dich, Du mußt im PCMSK1 noch die Maske einstellen, auf 
welchen PIN oder welche PINs der Interrupt reagieren soll.

K. R. schrieb:
> wie kann
> ich aber gezielt den Interrupt auf nur einen PIN, nämlich PC0 setzen?

Im PCICR das Bit PCIE1 setzen (Pin Change Interrupt Enable 1)
Im PCMSK1 das Bit PCINT8 setzen (Pin Change Enable Mask 8)
Interrupts generell erlauben
Auswerteroutine bei Interruptvektor PCINT1 starten (rjmp auf die 
Routine).

Die Routine wird bei jedem Pegelwechsel aufgerufen, ob Dein PIN auf L 
oder auf H gewechselt ist, mußt Du in der Routine selbst feststellen.

Reinhard

von Stefan E. (sternst)


Lesenswert?

K. R. schrieb:
> Wenn ich das mache, kommen fehlermeldungen auf, weil mein Code dann
> irgendwie verschoben ist, komisch, im tutorial klappt es angeblich

Und wo im Tutorial-Code steht das ".include ...", und wo bei dir?

von Spess53 (Gast)


Lesenswert?

Hi

>.org 0x000
>         rjmp start            ; Reset Handler
>.org INT0addr
>     NOP
>.org INT1addr
>         rjmp interrupt    ; IRQ1 Handler

>.include "M48PAdef.inc"


>G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(6): error: Use of 
undefined or forward referenced symbol 'INT0addr' in .org

Das Include gehört an den Anfang des Programms. Vor dem .include 
"M48PAdef.inc" weiß der Assemler nicht, was z.B. 'INT0addr' bedeutet.

MfG spess

von Reinhard R. (reirawb)


Lesenswert?

K. R. schrieb:
> Fehlermeldung :
ist ja nun geklärt.

Und tu Dir selbst einen Gefallen und setze an den Anfang Deiner 
Programme die gesamte Interruptvektortabelle. Bei nicht genutzen 
Interrupts ein reti reinschreiben. Später -in größeren Programmen- 
sollte man für nicht genutzte Interrupts eine Routine haben, die 
wenigstens die ungewollte Auslösung eines solchen meldet bzw. 
registriert. Aber für den Anfang reicht ein reti.

Reinhard

von A. B. (developer_x)


Lesenswert?

Reinhard R. schrieb:
> K. R. schrieb:
>> Fehlermeldung :
> ist ja nun geklärt.
>
> Und tu Dir selbst einen Gefallen und setze an den Anfang Deiner
> Programme die gesamte Interruptvektortabelle. Bei nicht genutzen
> Interrupts ein reti reinschreiben. Später -in größeren Programmen-
> sollte man für nicht genutzte Interrupts eine Routine haben, die
> wenigstens die ungewollte Auslösung eines solchen meldet bzw.
> registriert. Aber für den Anfang reicht ein reti.
>
> Reinhard

Zwei Probleme sind da aber immer noch:

1)
Der Assembler findet :
1
LDI PCICR, 0b00000010
2
LDI PCMSK1,0b00000001

ist nicht möglich :
1
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(27): error: Invalid register
2
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(28): error: Invalid register
hm...

2)
Irgendwie klappt das mit dem RETI nach dem Include aber auch nicht:
1
.include "M48PAdef.inc"
2
3
; INTERRUPTS INITIALISIEREN bei PCINT8
4
5
.ORG RESET RJMP
6
RETI
7
RETI
8
RETI
9
.ORG PCINT1 RJMP interrupt    ; IRQ1 Handler
10
RETI
11
RETI
12
RETI
13
RETI
14
RETI
15
RETI
16
RETI
17
RETI
18
RETI
19
RETI
20
RETI
21
RETI
22
RETI
23
RETI
24
RETI
25
RETI
26
RETI
27
RETI
28
RETI
29
RETI
30
RETI
31
32
start:
33
SEI
34
35
LDI PCICR, 0b00000010
36
LDI PCMSK1,0b00000001
37
38
39
.DEF STACK_LOW = R16
40
.DEF STACK_HIG = R17
41
42
.DEF COUNTER = R25
43
; //////////////////////////////////////////////////////////////
44
; Stackpointerinitialisierung
45
  LDI STACK_LOW, LOW(RAMEND)    ;Stackpointer initialisieren
46
  OUT SPL, STACK_LOW
47
  LDI STACK_HIG, HIGH(RAMEND)   ;Stackpointer initialisieren
48
  OUT SPH, STACK_HIG
49
; //////////////////////////////////////////////////////////////
50
51
; LCD INITIALISIEREN
52
RCALL Wait1000MS
53
RCALL LCD_INIT
54
;... ab hier weiter wie bisher

Fehler:
1
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(6): error: Use of undefined or forward referenced symbol 'RESET' in .org
2
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(10): error: Overlap in .cseg: addr=0x1 conflicts with 0x0:0x4
3
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(11): error: Overlap in .cseg: addr=0x2 conflicts with 0x0:0x4
4
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(12): error: Overlap in .cseg: addr=0x3 conflicts with 0x0:0x4

von Spess53 (Gast)


Lesenswert?

Hi

>LDI PCICR, 0b00000010
>LDI PCMSK1,0b00000001

ldi funktioniert nur mit den Registern r16...r31.

>.ORG RESET RJMP
>.ORG PCINT1 RJMP interrupt    ; IRQ1 Handler

Das '.org xyz' und 'rjmp abcd' gehören in verschieden Zeilen.

Hast du dir eigentlich mal das Tutorial hier angesehen? Da steht drin, 
wie man es richtig macht.

MfG Spess

von Reinhard R. (reirawb)


Lesenswert?

K. R. schrieb:
> Der Assembler findet :
> LDI PCICR, 0b00000010
> LDI PCMSK1,0b00000001
>
> ist nicht möglich...

Steht alles im Datenblatt, aber das ist -zugegebenermaßen- recht groß.
Also, Datenblatt:

8.5 I/O Memory
... For the Extended I/O space from 0x60 - 0xFF in SRAM, only the
ST/STS/STD and LD/LDS/LDD instructions can be used.

PCICR hat die Adresse 0x68
PCMSK1 hat die Adresse 0x6C
fallen also beide in die oben zitierte Kategorie. Wird dann so gemacht:

ldi ZH,high(PCICR)
ldi ZL,low(PCICR)
ldi r16,0b00000010
st  Z,r16
ldi ZH,high(PCMSK1)
ldi ZL,low(PCMSK1)
ldi r16,0b00000001
st  Z,r16

Dann freut sich Dein AVR-Studio :-)

Reinhard

von Spess53 (Gast)


Lesenswert?

Hi

>ldi ZH,high(PCICR)
>ldi ZL,low(PCICR)
>ldi r16,0b00000010
>st  Z,r16
>ldi ZH,high(PCMSK1)
>ldi ZL,low(PCMSK1)
>ldi r16,0b00000001
>st  Z,r16

>Dann freut sich Dein AVR-Studio :-)

Eher nach dem Motto 'von hinten durch die Brust ins Auge'. Ein
1
  ldi r16,1<<PCIE1
2
  sts PCICR,r16
3
  ldi r16,1<<PCINT8
4
  sts PCMSK1,r16
reicht und ist besser lesbar.

MfG Spess

von A. B. (developer_x)


Lesenswert?

Danke erstma für eure hilfe,

aber es will immer noch nicht klappen :
1
.include "M48PAdef.inc"
2
3
; INTERRUPTS INITIALISIEREN bei PCINT8
4
5
.ORG 0x000
6
  RJMP start
7
RETI
8
RETI
9
RETI
10
.ORG PCINT1 
11
  RJMP interrupt    ; IRQ1 Handler
12
RETI
13
RETI
14
RETI
15
RETI
16
RETI
17
RETI
18
RETI
19
RETI
20
RETI
21
RETI
22
RETI
23
RETI
24
RETI
25
RETI
26
RETI
27
RETI
28
RETI
29
RETI
30
RETI
31
RETI
32
RETI
33
34
start:
35
SEI
36
37
ldi ZH,high(PCICR)
38
ldi ZL,low(PCICR)
39
ldi r16,0b00000010
40
st  Z,r16
41
ldi ZH,high(PCMSK1)
42
ldi ZL,low(PCMSK1)
43
ldi r16,0b00000001
44
st  Z,r16
45
46
.DEF STACK_LOW = R16
47
.DEF STACK_HIG = R17
48
49
.DEF COUNTER = R25
50
; //////////////////////////////////////////////////////////////
51
; Stackpointerinitialisierung
52
  LDI STACK_LOW, LOW(RAMEND)    ;Stackpointer initialisieren
53
  OUT SPL, STACK_LOW
54
  LDI STACK_HIG, HIGH(RAMEND)   ;Stackpointer initialisieren
55
  OUT SPH, STACK_HIG
56
; //////////////////////////////////////////////////////////////
57
58
; LCD INITIALISIEREN
59
RCALL Wait1000MS
60
RCALL LCD_INIT
61
;... hier gehts weiter
1
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(11): error: Overlap in .cseg: addr=0x1 conflicts with 0x0:0x4
2
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(12): error: Overlap in .cseg: addr=0x2 conflicts with 0x0:0x4
3
G:\Software Projects\2013\March\Interrupts\ExternInterrupt.asm(13): error: Overlap in .cseg: addr=0x3 conflicts with 0x0:0x4

Sorry Leute, aber in meinem Buch und den meisten Tutorials (ICH BIN NOCH 
ANFÄNGER, UND MAßE MIR NICHT AN ALLES ZU KÖNNEN!) wird das anders 
gemacht... Deshalb seid mir nicht böse wenn ich wieder was übersehen 
habe, aber ich sehe es echt nicht, und die nächste Sache ist, dass es 
mich wundert, denn im Tutorial stand nicht explizit dass ein 
Zeilenumbruch nötig ist, ich dachte zumindest, weil es in anderen 
Programmiersprachen teilweise auch so ist, dass es nicht nötig ist...

Ich hoffe ihr könnt mir bei diesem letzten Problem helfen, danke

m.f.G. Developer_X

von Karl H. (kbuchegg)


Lesenswert?

K. R. schrieb:

> Sorry Leute, aber in meinem Buch und den meisten Tutorials (ICH BIN NOCH
> ANFÄNGER, UND MAßE MIR NICHT AN ALLES ZU KÖNNEN!) wird das anders
> gemacht...

Dann mach es so, wie du es dort liest.

Aber sieh dir die Dinge um Himmels willen endlich mal GENAU und EXAKT 
an! Es reicht nicht, wenn du die Dinge einfach irgendwie wischi waschi 
abmalst und nach Gutdünken einfach irgendwie in ein File 
zusammenkopierst. Sorgfalt ist einer der Um- Und AUf-Dinge in der ganze 
Programmierung. Sorgfalt und die Beachtung von Details.
Dazu gehören Schreibweisen, dazu gehören Reihenfolgen, dazu gehört Doku 
lesen, dazu gehört ... alles.
WEnn du das nicht kannst, dann fehlt dir etwas wesentliches was ein 
Programmierer haben muss. In dem Fall wäre ein Kunststudium vorzuziehen. 
Da kann man hinterher immer noch sagen, das sollte so sein und die 
Putzfrau verklagen, die das Kunstwerk mit einem Müllhaufen verwechselt 
hat.

von Hmm (Gast)


Lesenswert?

Es mag vielleicht sein, das in den Beispielen nur eine der Möglichkeiten 
benutzt wird, etwas zu erledigen, ohne Hinweis darauf, das es auch 
anders geht. Gerade deswegen ist es empfehlenswert, erstmal genau den 
Beispielen zu folgen und ergänzend ein C-Buch zu lesen. Ansonsten musst 
Du Dir vorwerfen lassen, nicht in jeder zweiten Zeile den Namen Deiner 
Grossmutter genannt zu haben, denn es stand ja nicht da, das das nicht 
zulässig ist.

Naja. Gut, das ich den schönen Artikel über css hier gelesen habe. Dann 
gehab Dich wohl.

von Karl H. (kbuchegg)


Lesenswert?

PCINT0 ist nicht das was du denkst das es ist.

Die Konstante für die Speicherposition des Interrupt Vektors des PCINT1 
heißt
   PCI1addr

Alle symbolischen Namen der Interrupt Vektoren haben IMMER die Endung 
'addr'.
1
.ORG 0x000
2
  RJMP start
3
RETI
4
RETI
5
RETI
6
.ORG PCI1addr 
7
  RJMP interrupt    ; IRQ1 Handler
8
...

Wenn man sie nicht auswendig weiß, dann hindert einen nichts und niemand 
daran, mal das File M48PAdef.inc im Editor aufzumachen und dort drinnen 
nachzusehen. Mit einem Suchen nach "addr" ist man recht schnell bei der 
Aufzählung der symbolischen Namen für alle Interrupt Vektoren.

von Spess53 (Gast)


Lesenswert?

Hi

>.ORG PCINT1

Bei meinem Assmbler ( AVR Studio 4.19 Assembler2) nennt sich das 
'PCI1addr' und nicht PCINT1.

Aus der Include Datei:
.equ  PCI1addr  = 0x0004  ; Pin Change Interrupt Request 0
.equ  PCINT1  = 1  ; Pin Change Enable Mask 1

Da der Assembler dann statt .org. 0x0004 .Org 1 einsetzt kommt natürlich 
das Problem mit dem Overlapping.

MfG Spess

von A. B. (developer_x)


Lesenswert?

Danke, hat jetzt geklappt :D.

Ein Problem ist da immer noch : Die ISR wird 2x aufgerufen.

Im Tutorial wird ja gesagt :
1
int0_handler:
2
         push temp             ; Das SREG in temp sichern. Vorher
3
         in   temp, SREG       ; muss natürlich temp gesichert werden
4
 
5
         sbi PORTB, 0
6
 
7
         out SREG, temp        ; Die Register SREG und temp wieder
8
         pop temp              ; herstellen
9
         reti
Mit RETI wird die ISR beendet.

Bei meiner ISR :
1
interrupt:
2
CLI
3
PUSH ZL
4
PUSH ZH
5
LDI ZL,LOW (text*2)
6
LDI ZH,HIGH(text*2)
7
8
RCALL LCD_LINE2
9
10
loop:
11
  LPM
12
13
; Testen ob Ende
14
  TST R0
15
  BREQ b
16
17
; Zeichen ausgegeben
18
  MOV INFO,R0
19
  RCALL LCD_DATA
20
21
; Zeiger auf nächstes Byte setzen
22
  ADIW ZL,1
23
  RCALL Wait1000MS
24
  RJMP loop
25
26
b :
27
  RCALL LCD_LINE1
28
  RCALL Wait1000MS
29
  RCALL Wait1000MS
30
  RCALL LCD_CLEAR
31
32
  SEI
33
  POP ZH
34
  POP ZL  
35
  RETI

ist das ja auch so, und sie dauert so ungefähr 10 Sekunden,
d.h. den button habe ich schon längst wieder los gelassen, während die 
ISR läuft, und durch CLI wird ja der erneute Aufruf der ISR während 
dieser ISR verhindert. Komisch ist nur, dass nach der Ausführung von der 
ISR, die ISR nochmal aufgerufen wird, und dann erst wieder zum 
Hauptprogramm springt, was ist denn hier falsch?

Muss mann da den PC manipulieren, oder den Stack, oder soll man in 
diesem Falle einen anderen Befehl als "RETI" verwenden, um die ISR 
wirklich zu verlassen.

Ach ja, ich weiß dass ich sowohl den Z-Pointer für den Interrupt kram 
benutze, als auch für die Textauslese aus dem Flash in der ISR, deshalb 
habe ich ZL und ZH auch erstma im Stack gesichert, damit hinterher alles 
wieder so wie vorher sein sollte.

Warum klappt es aber trotzdem nicht?
Danke,
m.f.G. Developer_X

von Spess53 (Gast)


Lesenswert?

Hi

>ist das ja auch so, und sie dauert so ungefähr 10 Sekunden,
>d.h. den button habe ich schon längst wieder los gelassen, während die
>ISR läuft, und durch CLI wird ja der erneute Aufruf der ISR während
>dieser ISR verhindert. Komisch ist nur, dass nach der Ausführung von der
>ISR, die ISR nochmal aufgerufen wird, und dann erst wieder zum
>Hauptprogramm springt, was ist denn hier falsch?

Das ist ein PINCHANGE-Interrupt. Der löst bei jeder Flanke aus. Also 
beim Drücken und beim Loslassen. Außerdem prellt dein Schalter. Da gibt 
es sowieso mehrere Flanken.

Mit dem Cli/sei erreichst du gar nichts. Während des Interrupts passiert 
das automatisch. Aber wenn andere oder auch der gleiche Interrupt 
während der ISR auftreten wird das gespeichert und diese Interrupts 
werden nach Beenden Interruptroutine ausgeführt.

MfG Spess

von Georg G. (df2au)


Lesenswert?

K. R. schrieb:
> RCALL Wait1000MS
>   RCALL Wait1000MS

ist innerhalb einer ISR extrem ungeschickt. Eine ISR sollte so kurz wie 
möglich sein. Flag setzen und wieder raus. Den Rest im Hintergrund 
erledigen.

von r. (Gast)


Lesenswert?

Fuer ein paar AVR ASM Anregungen siehe auch
http://www.ibrtses.com/embedded/avr.html

von A. B. (developer_x)


Lesenswert?

Spess53 schrieb:
> Mit dem Cli/sei erreichst du gar nichts. Während des Interrupts passiert
> das automatisch. Aber wenn andere oder auch der gleiche Interrupt
> während der ISR auftreten wird das gespeichert und diese Interrupts
> werden nach Beenden Interruptroutine ausgeführt.

Und da ist auch nichts zu umgehen?
Hm tja,
außerdem habe ich diese ISR nur so lang gemacht, um das mal auszutesten, 
und was am Bildschirm auszugeben, war ja nur ein Test.

Naja,
Danke dann nochma Leute!

m.f.G. Developer_X

von Justus S. (jussa)


Lesenswert?

K. R. schrieb:
> Und da ist auch nichts zu umgehen?

doch natürlich, einfach Flag vorm Rücksprung zurücksetzen...

von Spess53 (Gast)


Lesenswert?

Hi

>Und da ist auch nichts zu umgehen?
>Hm tja,

Interrupts für Taster sind zu 99% nicht die sinnvollste Lösung. Das 
wurde hier im Forum schon zig mal bis zum Erbrechen diskutiert. Die 
Forumssuche nach 'Taster+ Interrupt' bringt 1906 Treffer.

Eine elegante Lösung findest du hier:

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Tasten

MfG Spess

von A. B. (developer_x)


Lesenswert?

Justus Skorps schrieb:
> doch natürlich, einfach Flag vorm Rücksprung zurücksetzen...

Gut, habe ich versucht, klappt aber anscheinend nicht, im Datenblatt 
steht :
1
12.2.3 EIFR – External Interrupt Flag Register
2
....
3
• Bit 1 – INTF1: External Interrupt Flag 1
4
When an edge or logic change on the INT1 pin triggers an interrupt request, INTF1 becomes set
5
(one). If the I-bit in SREG and the INT1 bit in EIMSK are set (one), the MCU will jump to the corresponding
6
Interrupt Vector. The flag is cleared when the interrupt routine is executed.
7
Alternatively, the flag can be cleared by writing a logical one to it. This flag is always cleared
8
when INT1 is configured as a level interrupt.
Das heißt ich muss im Byte EIFR das Bit INTF1 setzen.

Jetzt steht in "m48adef.inc" :
1
; EIFR - External Interrupt Flag Register
2
.equ  INTF0  = 0  ; External Interrupt Flag 0
3
.equ  INTF1  = 1  ; External Interrupt Flag 1

Daher war mein Code, da man ja das Bit mit iener logischen 1 setzen 
soll, um das Flag zu löschen:
1
interrupt:
2
CLI
3
4
PUSH ZL
5
PUSH ZH
6
LDI ZL,LOW (text*2)
7
LDI ZH,HIGH(text*2)
8
9
RCALL LCD_LINE2
10
11
loop:
12
  LPM
13
14
; Testen ob Ende
15
  TST R0
16
  BREQ b
17
18
; Zeichen ausgegeben
19
  MOV INFO,R0
20
  RCALL LCD_DATA
21
22
; Zeiger auf nächstes Byte setzen
23
  ADIW ZL,1
24
  RCALL Wait1000MS
25
  RJMP loop
26
27
b :
28
  RCALL LCD_LINE1
29
  RCALL Wait1000MS
30
  RCALL Wait1000MS
31
  RCALL LCD_CLEAR
32
33
  SEI
34
  POP ZH
35
  POP ZL  
36
37
  ldi ZH,high(INTF1)
38
  ldi ZL,low(INTF1)
39
  ldi r16,0b00000011  ; Flags löschen, sodass nicht nochmals der Interrupt ausgelöst wird
40
  st  Z,r16  
41
42
  RETI
Es läuft aber trotzdem wieder.

Was habe ich da falsch verstanden?

von Justus S. (jussa)


Lesenswert?

K. R. schrieb:
> Das heißt ich muss im Byte EIFR das Bit INTF1 setzen.

du hast immer noch nicht den Unterschied zwischen INT1 und PCINT1 
verstanden...

von A. B. (developer_x)


Lesenswert?

INT1 ist einfach nur ein Interrupt.
und PCINT1 ist PC (Pin Change).

Wie soll ich es denn dann machen?
Welches Flag soll ich denn dann zurücksetzen?

von A. B. (developer_x)


Lesenswert?

PCIF1, ob wohl Pin Change Interrupt Flag Register
funktioniert auch nicht :(

von A. B. (developer_x)


Lesenswert?

Hat vielleicht noch jemand ne Idee, welches Register es sein könnte?

von Peter D. (peda)


Lesenswert?

K. R. schrieb:
> Ein Problem ist da immer noch : Die ISR wird 2x aufgerufen.

Gähn, postet doch nicht immer und immer wieder die gleichen Fragen.
Schon Fusseln am Mund hab, sonst würd ich die Erklärung zum millionsten 
mal runterleiern.
Wie wärs mit Forumsuche, Tutorials, Artikel benutzen?

von Viktor N. (Gast)


Lesenswert?

E$in weiteres Vorgehen waere nun den Taster durch einen Arbitraer 
generator oder so zu seretzten und im Pinchange Interrupt einen 
Pintoggle zu machen. Beides aufm Scope bringt dann klarheit.

von A. B. (developer_x)


Lesenswert?

Also nur in einem Treffer von mir
https://www.google.de/#hl=de&safe=off&sclient=psy-ab&q=mikrocontroller+isr+wird+zweimal+aufgerufen&oq=mikrocontroller+isr+wird+zweimal+aufgerufen&gs_l=hp.3...347.6107.0.6253.47.38.1.6.6.0.188.5382.1j36.37.0...1.0...1c.1.7.psy-ab.CiolrlryloE&pbx=1&bav=on.2,or.r_qf.&bvm=bv.44442042,d.Yms&fp=6f8d6a216c372f06&biw=1760&bih=832
habe ich das gefunden :
Beitrag "Interrupt wird zwei mal aufgerufen"
GIFR = (1<<INTF1);

Das soll am Ende der ISR stehen, komischer weise habe ich keine Ahnung 
was GIFR ist.
Im Datenblatt und in der inc datei steht nichts.

Wäre wenigstens einer von euch so freundlich mir endlich mal zu 
erklären, wie ich das verdammt nochmal machen soll, ihr könnt doch nicht 
erwarten dass man als Anfänger alles kann. Woher soll ich denn überhaupt 
wissen was GIFR ist, habt endlich mal ein bisschen einsicht, denn das 
bringt mir überhaupt nichts konstruktives.

Ist es so schwer mir endlich zu sagen, wie ich mein Problem lösen kann, 
und das Interrupt zurücksetzen kann??? (IN ASSEMBLER CODE)!!!

von Purzel H. (hacky)


Lesenswert?

Das GIFR ist ein Register.
Du hast das Assembly Instruction Manual sicher gelesen?
Ja, leider muss man jede Seite des Controller Manuals
mindestens einmal genau gelesen haben.
Ja. die Lernkurve ist da besonders steil, aber sicher wert, wenn man ein 
laengerfristiges interesse hat.
und zieh dir mal diesen Beitrag rein :
http://www.ibrtses.com/embedded/avrasmuartint.html

von MWS (Gast)


Lesenswert?

Aber jetzt mal los ! Antwortet gefälligst so, dass auch er's ohne Denken 
versteht !

von Justus S. (jussa)


Lesenswert?

K. R. schrieb:
> Ist es so schwer mir endlich zu sagen, wie ich mein Problem lösen kann,
> und das Interrupt zurücksetzen kann???

es wurde dir schon zig Mal gesagt: Im richtigen Register das richtige 
Bit auf 1 setzen...niemand hier kann was dafür, dass dir anscheinend 
selbst die absoluten Basics fehlen! Der Bitname bringt einem nummal 
nichts, wenn man nicht das passende Register kennt...

von A. B. (developer_x)


Lesenswert?

In Artikel
Beitrag "Atmega8 Taster an Interrupt löst zweimal aus"

heißt es :
der mechatroniker schrieb:
> Ok, ein Versuch einer Erklärung, was passiert.
>
> 1. Der Interrupt wird ausgelöst. Das interne Flag für die
> Interruptquelle wird zurückgesetzt.

Das heißt, wenn ich dann das flagregister abspeicher, und vor dem Ende 
der ISR wieder in das EIFR lade, dann sollte doch alles klappen?
1
interrupt:
2
3
4
PUSH ZL
5
PUSH ZH
6
LDI ZL,LOW (text*2)
7
LDI ZH,HIGH(text*2)
8
9
  ldi ZH,high(EIFR) ; GELÖSCHTES FLAG SPEICHERN
10
  ldi ZL,low(EIFR)
11
  LD  r16,Z  
12
13
RCALL LCD_LINE2
14
15
loop:
16
  LPM
17
18
; Testen ob Ende
19
  TST R0
20
  BREQ b
21
22
; Zeichen ausgegeben
23
  MOV INFO,R0
24
  RCALL LCD_DATA
25
26
; Zeiger auf nächstes Byte setzen
27
  ADIW ZL,1
28
  RCALL Wait1000MS
29
  RJMP loop
30
31
b :
32
  RCALL LCD_LINE1
33
  RCALL Wait1000MS
34
  RCALL Wait1000MS
35
  RCALL LCD_CLEAR
36
37
  POP ZH
38
  POP ZL  
39
40
  ldi ZH,high(EIFR) ; GELÖSCHTES FLAG WIEDERHERSTELLEN
41
  ldi ZL,low(EIFR)
42
  st  Z,r16  
43
44
  RETI
NEIN TUT ES NICHT.

Und ganz ehrlich, vielleicht hattet ihr ja das Glück diese Sachen zu 
studieren, oder in einer Ausbildung zu lernen, ich nicht, und ich 
verstehs nicht, viele dinge über die ihr redet, werden bei ner 
Googlesuche nicht annähernd erklärt, ok dann hab ich eben keine Basics, 
wo soll ich die denn herbekommen? (Komisch, in meinem Buch brauch ich 
eure "BASICS" nicht)

Und ganz ehrlich, wenn mir jemand den Code endlich geben würde, dann 
könnte ich es auch endlich mal nachvollziehen, falls einer von euch so 
kompetent wäre...

von Eumel (Gast)


Lesenswert?

K. R. schrieb:
> Komisch, in meinem Buch brauch ich
> eure "BASICS" nicht

Na, was dabei raus kommt sieht man ja.

K. R. schrieb:
> Das heißt, wenn ich dann das flagregister abspeicher, und vor dem Ende
> der ISR wieder in das EIFR lade, dann sollte doch alles klappen?

Hast du dir durchgelesen was es heißt, dass dein Taster prellt?

von A. B. (developer_x)


Lesenswert?

JA schon klar, aber was ist, wenn meine ISR so lange dauert, dass das 
prellen keine rolle spielt, (ICH HABE DAS MIT DEM PRELLEN GELESEN),
und ich einfach am ende der ISR ein Byte ändere, das EIFR, und dann wird 
es nicht mehr aufgerufen.

WARUM KLAPPT ES DANN NICHT; WAS KANN ICH TUN=?

von Eumel (Gast)


Lesenswert?

Und wenn das Flag nicht gelöscht ist? Wieso machst du denn diese Scheiße 
mit "gelöschtes Flag speichern".
Lösch es doch einfach am Ende, wo ist das Problem?

von A. B. (developer_x)


Lesenswert?

1
interrupt:
2
CLI
3
4
PUSH ZL
5
PUSH ZH
6
LDI ZL,LOW (text*2)
7
LDI ZH,HIGH(text*2)
8
9
RCALL LCD_LINE2
10
11
loop:
12
  LPM
13
14
; Testen ob Ende
15
  TST R0
16
  BREQ b
17
18
; Zeichen ausgegeben
19
  MOV INFO,R0
20
  RCALL LCD_DATA
21
22
; Zeiger auf nächstes Byte setzen
23
  ADIW ZL,1
24
  RCALL Wait1000MS
25
  RJMP loop
26
27
b :
28
  RCALL LCD_LINE1
29
  RCALL Wait1000MS
30
  RCALL Wait1000MS
31
  RCALL LCD_CLEAR
32
33
  SEI
34
  POP ZH
35
  POP ZL  
36
37
  ldi ZH,high(EIFR)
38
  ldi ZL,low(EIFR)
39
  ldi r16,0b00000011  ; Flags löschen, sodass nicht nochmals der Interrupt ausgelöst wird
40
  st  Z,r16  
41
42
  RETI

FUNKTIONIERT AUCH NICHT!

Ob ich r16 jetzt das zweite Bit (also Bit 1) auf 1 oder 0 setze, beides 
klappt nicht.

Ich weiß nicht mehr weiter.

von Viktor N. (Gast)


Lesenswert?

>
loop:
  LPM

; Testen ob Ende
  TST R0
  BREQ b

; Zeichen ausgegeben
  MOV INFO,R0
  RCALL LCD_DATA

; Zeiger auf nächstes Byte setzen
  ADIW ZL,1
  RCALL Wait1000MS
  RJMP loop
.....................................

Die volle Droehnung was ?

Sowas gibt's nicht. Es gibt weder loops, noch einen Delay in einem 
Interrupt. Dies wurde schon mehrfach erwaehnt. Lass es sein, das wird 
nie was. Pflanze Osterglocken oder sowas. Sorry.

Wenn's denn mit Warten sein soll :
http://www.ibrtses.com/embedded/avrlcd.html

von A. B. (developer_x)


Lesenswert?

Ich habs ganz pragmatisch hinbekommen,
und ja ich weiß dass interrupts in der regel nicht für langatmige dinge 
gedacht sind :
1
interrupt:
2
3
IN  r18, PINC
4
SBRC r18,0 
5
RETI
6
7
PUSH ZL
8
PUSH ZH
9
LDI ZL,LOW (text*2)
10
LDI ZH,HIGH(text*2)
11
12
RCALL LCD_LINE2
13
14
loop:
15
  LPM
16
17
; Testen ob Ende
18
  TST R0
19
  BREQ b
20
21
; Zeichen ausgegeben
22
  MOV INFO,R0
23
  RCALL LCD_DATA
24
25
; Zeiger auf nächstes Byte setzen
26
  ADIW ZL,1
27
  RCALL Wait1000MS
28
  RJMP loop
29
30
b :
31
  RCALL LCD_LINE1
32
  RCALL Wait1000MS
33
  RCALL Wait1000MS
34
  RCALL LCD_CLEAR
35
36
  POP ZH
37
  POP ZL  
38
39
  RETI
Genauso funktionierst, nichts mit manipulation von bytes sondern einfach 
gucken, bei neustart der ISR ob der button an ist oder nicht, und dann 
sein lassen oder isr durchführen

danke trotzdem, jetzt weiß ich schon ma mehr,
m.f.G. Developer_X

und frohe Ostern

von Viktor N. (Gast)


Lesenswert?

Also. Nimm einen timer interupt, wie in

http://www.ibrtses.com/embedded/avrasmuartint.html

Timer1Int:
  push  temp
  in  temp,SREG
  push  temp
;isr
; reload
  ldi  temp,0xFF
  out  TCNT1H,temp
  ldi  temp,0x80  ;war 0x80
  out  TCNT1L,temp

;signal : timer came
        ldi     temp,1
        mov     Timercame, temp
;end
t1iend:
  pop  temp
  out  SREG,temp
  pop  temp
  reti

Dann mach dein Ding im Haupt program

von Justus S. (jussa)


Lesenswert?

K. R. schrieb:
> Genauso funktionierst, nichts mit manipulation von bytes sondern einfach
> gucken, bei neustart der ISR ob der button an ist oder nicht, und dann
> sein lassen oder isr durchführen

Und du glaubst ernsthaft, dass du weit kommst in der µC-Welt wenn du 
nichtmal sowas simples wie Bits in bestimmten Registern setzen kannst?

von A. B. (developer_x)


Lesenswert?

Wie soll ich denn bits in registern setzen, was ich kann, ich kann sie 
sogar auslesen, wenn ich nicht weiß wie sie heißen???

von Viktor N. (Gast)


Angehängte Dateien:

Lesenswert?

Naja. Das Datenblatt.... Die Register sind alle angeschriben

von Viktor N. (Gast)


Angehängte Dateien:

Lesenswert?

Resp.

von Eumel (Gast)


Lesenswert?

K. R. schrieb:
> Wie soll ich denn bits in registern setzen, was ich kann, ich kann sie
> sogar auslesen, wenn ich nicht weiß wie sie heißen???

Lesen kannst du ja irgendwie schon. Wieso schaust du nicht einfach im 
Datenblatt nach? Das dauert 2 Minuten und die Wurst ist gegessen.

von Spess53 (Gast)


Lesenswert?

Hi

>interrupt:
>CLI
>...
>  SEI
>  POP ZH
>...

Noch mal: Das cli und sei haben in der Interruptroutine nichts zu 
suchen. Das sei vor dem reti bewirkt sogar das Gegenteil von dem was du 
vor hast. Denn damit gibst du anderen Interrupts die Möglichkeit deinen 
Interrupt zu unterbrechen.

>FUNKTIONIERT AUCH NICHT!

Kann auch nicht. Weil

1. PCIFR für den PCINT zuständig ist
2. es auch so auch mit PCIFR nicht funktioniert:

EIFR und PCIFR liegen in dem Speicherbereich der mit in/out adressierbar 
ist. Und der fängt nach den Registern r0...r31 mit Null an. So sind auch 
die Adressen in der 'M48PAdef.inc' definiert.

>  ldi ZH,high(EIFR)
>  ldi ZL,low(EIFR)
>...
>  st  Z,r16

Der damit adressierte Speicher fängt aber bei $0000 (r0) an. Damit ist 
die Adresse die mit EIFR in der 'M48PAdef.inc' definiert ist um $20 zu 
klein. Ein
1
ldi r16,xyz
2
out PCIFR,r16
ist weniger umständlich und trifft das richtige Register.

Noch etwas allgemeines:

Deiner Interruptroutine fehlt das Sichern von SREG. Fällt bei dir nicht 
auf, führt aber bei richtigen Programmen zu mehr oder weniger lustigen 
Effekten.

Statt die IF-Register zu manipulieren ist es bei PCINTs sinnvoller, am 
Interruptanfang den Pegel des Pins abzufragen. Damit kannst du 
feststellen, welche Flanke den Interrupt ausgelöst hat und entsprechend 
reagieren.

MfG Spess

von A. B. (developer_x)


Lesenswert?

Danke Leute, aber ganz ehrlich ich habe im Datenblatt das Kapitel 
Interrupts und External Interrupts gelesen, ich bin doch noch anfänger 
und in meinem Buch etc. steht nichts von PCIFR, woher soll ich denn 
wissen dass das PCIFR ist, ich weiß ganz ehrlich nicht woher ich das 
hätte wissen sollen, fakt ist es klappt jetzt, und das SREG wird auch 
gesichert.

Danke euch allen, und seid mir nicht böse, aber ich muss mir das alles 
selbst beibringen, und habe nicht so viele quellen und anscheinend auch 
nicht dieses "BASIS" Wissen, um die Dinge zu suchen, die ihr meint.

von Spess53 (Gast)


Lesenswert?

Hi

> woher soll ich denn
>wissen dass das PCIFR ist, ich weiß ganz ehrlich nicht woher ich das
>hätte wissen sollen,

Na ja, die Namen der Register, die für die externen Interrupts (INT0/1) 
zuständig sind fangen alle mit 'E' an. Die Namen der für die Pin Change 
Interrupts zuständigen Register sinnigerweise mit PC.

>Danke euch allen, und seid mir nicht böse, aber ich muss mir das alles
>selbst beibringen,

Das habe ich vor 30 Jahren auch gemacht.

>und habe nicht so viele quellen und anscheinend auch
>nicht dieses "BASIS" Wissen, um die Dinge zu suchen, die ihr meint.

Von der Quellenvielfalt, die heute zur Verfügung steht, konnte ich 
damals nur träumen. Man muss sie halt auch nutzen.

MfG Spess

von A. B. (developer_x)


Lesenswert?

Ja, aber nicht vergessen, du hast das schon hinter dir^^

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.