Forum: Mikrocontroller und Digitale Elektronik Interrupt stört Programmablauf und umgekehrt?


von elko (Gast)


Lesenswert?

Hallo Leute,
ich habe seit geraumer Zeit das Problem, dass mein C-Programm mysteriöse 
Dinge tut... nun habe ich das Problem, denke ich, ziemlich eingegrenzt:
1
var0=0xFF;
2
3
while (1)
4
{       
5
   var0=hallo();
6
7
}
8
9
10
unsigned char hallo(){
11
   return 7;
12
}

Außerdem gibt es noch den Interrupt:
1
// Timer für ms- Zähler  (bringt die LED A4 blinken)
2
3
static void T1_isr (void) interrupt 3 using 3
4
{  TL1 = 0xC0;    // L-Register laden insgesamt: 0xF831
5
  TH1 = 0x07;    // H-Register laden
6
  if (LED_BLINK)
7
  {
8
    if (LED_COUNT-- == 0)  // Zähler zurücksetzen
9
    {  LED_COUNT = 50;    // Schleifenzähler neu setzen
10
      OUTA ^= 0x10;    // LED umschalten
11
    }
12
  }
13
}

So, das Problem ist folgendes:
Die an den Interrupt-Port angeschlossene LED blinkt (allerdings viel zu 
schnell im Vergleich zum "normalen" blinken; ist nur mit dem Oszilloskop 
nachweisbar...) und das Register von der Variablen var0, das eigentlich 
den Wert 7 enthalten müsste, enthält immer den vorher zugewiesenen Wert 
0xFF.
Nunhabe ich das Gefühl, dass sich das Pogramm und der Interrupt 
irgendwie gegenseitig die "Suppe versalzen..." Hat jemand eine Idee, an 
was das liegen könnte?

Viele Grüße,
elko

PS: Ich nutze den µC AN2131 von Cypress

von Falk B. (falk)


Lesenswert?

Siehe Interrupt, Stichwort volatile.

von Michael U. (amiga)


Lesenswert?

Hallo,

Wenn var0 auf 0xFF landet, ist er eben abgestürzt und hat von vorn 
angefangen.

Im Fragment ist (wie oft) keine Ursache erkennbar.

Initialisierung des Timers und der Interrupts?
Falsche ISR?

Gruß aus Berlin
Michael

von elko (Gast)


Lesenswert?

Okay, hier nochmal die ganze Main-Routine:
1
void main()
2
{  EA = 0;
3
  // Ohne die folgenden 5 Zeilen kann das USB-Board sich nicht am USB-Port melden,
4
  // wenn Sie aus der IIC- Datei ein EEPROM herstellen!!!
5
  EUSB = 1; // Enable Firmware- USB
6
  USBCS = 4;
7
  USBIRQ = 0x1E;
8
  IBNIRQ = IBNIEN = TOGCTL = 0;
9
  EPIO[0] = 0x0A; // Enable Firmware- USB Ende
10
           
11
  OUTA = 0x00;    // Register vorbelegen
12
  OEA = 0x30;      // LED-Out ausschalten
13
  T2CON = 3;    // Timer 2 aus
14
  TR0 = 0;    // Timer 0 aus
15
  T1M = 0;    // Clock div 12
16
  CT1 = 0;    // Timer- Betrieb ein
17
  TH1 = 0x07;    // H-Register laden
18
  TL1 = 0xC0;    // L-Register laden insgesamt: 0xF831
19
  TF1 = 1;    // Interrupt ein
20
  ET1 = 1;    // Timer 1 Interrupt ein 
21
  TR1 = 1;    // Timer 1 einschalten
22
  EA = 1;      // Interrupt ein  
23
  LED_COUNT = LED_BLINK = 1;  // Zähler zurücksetzen und Blinken einschalten
24
  PORTACFG = 0;
25
  PORTBCFG = 0;
26
  PORTCCFG = 0;
27
  OUTA = 0x00;    // Register vorbelegen
28
  OEA = 0x30;      // LED-Out einschalten
29
30
  OEC=0xFF;
31
32
  
33
var0=0xFF;
34
35
while (1)
36
{       
37
  var0=hallo();
38
}
39
40
41
}

Was es mit den Initialisierungen am Anfang auf sich hat, weiß ich leider 
nicht, aber vielleicht hilft es euch ja weiter ;-)

Viele Grüße,
elko

von kurz (Gast)


Lesenswert?

> TL1 = 0xC0;    // L-Register laden insgesamt: 0xF831
> TH1 = 0x07;    // H-Register laden

was jetzt? 0x07c0 oder wie im Kommentar 0xf831 ?

Eins ist doch falsch, oder nicht?

von elko (Gast)


Lesenswert?

Wie gesagt, mit den Initialisierungen kenne ich mich leider nicht aus... 
ich habe mal die andere Variante wie im Kommentar ausprobiert, 
funktioniert aber immer noch nicht...

von kurz (Gast)


Lesenswert?

Hast Du irgendeine Ahnung vom Programmieren oder von Deinem Prozessor?

von kurz (Gast)


Lesenswert?

Wo hast denn den Code abgeschrieben? Schau doch dort noch mal nach.

von elko (Gast)


Lesenswert?

Vom Programmieren hab ich Ahnung, ja (habe auch schon viel mit dem µC 
programmiert...). Meine Programme haben immer auf einen winzigen 
"Basisprogramm" aufgebaut, was eben die notwendigen Initialisierungen 
enthält. Von diesen habe ich jedoch keine Ahnung. Logische Zusammenhänge 
bezüglich dem Programmieren kann ich nachvollziehen, nur eben solche 
-auf den ersten Blick willkürlichen Zeilen wie TH1=5 oder so- kann man 
ja nicht mit Logik verstehen... und die Technical Manual von Cypress ist 
so dick, dass man Monate bräuchte, sie durchzugehen...So sieht das 
Basisprogramm aus:
1
/*------------------------------------------------------------------------------
2
Blink.C
3
4
Copyright 1999-2003 by MmVisual - M.Müller
5
Erstellung BlinkLED 29.12.2001
6
--------------------------------------------------------------------------------
7
Testprogramm "Blinkende LED"
8
9
LED ist an Port PA4 des Cypress- Chips angeschlossen. Es wird nur dieser eine
10
Port als Ausgang definiert. Das Programm kann in den Speicher des AN21xx geladen
11
und gestartet werden. Sofort muss die LED anfangen zu Blinken (ca. 3 Hz). 
12
------------------------------------------------------------------------------*/
13
14
#include <REGAN21.H>      /* Register des AN21xx  */
15
#include <EZREGS.H>        /* Externe Register des AN21xx  */
16
17
// Definitionen der Routinen
18
19
// Belegung des Speichers
20
xdata unsigned char T0LED;
21
xdata unsigned char LED_BLINK _at_ 0x0101;  // LED blinken lassen
22
xdata unsigned char LED_COUNT _at_ 0x0100;  // Blinkende LED - Zähler nach Timer
23
24
xdata unsigned char iOEA _at_ 0x0110;
25
xdata unsigned char iOEB _at_ 0x0111;
26
xdata unsigned char iOEC _at_ 0x0112;
27
xdata unsigned char iOUTA _at_ 0x0113;
28
xdata unsigned char iOUTB _at_ 0x0114;
29
xdata unsigned char iOUTC _at_ 0x0115;
30
xdata unsigned char iPINSA _at_ 0x0116;
31
xdata unsigned char iPINSB _at_ 0x0117;
32
xdata unsigned char iPINSC _at_ 0x0118;
33
34
/*------------------------------------------------
35
The main C function.  Program execution starts
36
here after stack initialization.
37
------------------------------------------------*/
38
void main()
39
{  EA = 0;
40
41
  // Ohne die folgenden 5 Zeilen kann das USB-Board sich nicht am USB-Port melden,
42
  // wenn Sie aus der IIC- Datei ein EEPROM herstellen!!!
43
  EUSB = 1; // Enable Firmware- USB
44
  USBCS = 4;
45
  USBIRQ = 0x1E;
46
  IBNIRQ = IBNIEN = TOGCTL = 0;
47
  EPIO[0] = 0x0A; // Enable Firmware- USB Ende
48
49
  OUTA = 0x00;    // Register vorbelegen
50
  OEA = 0x30;      // LED-Out ausschalten
51
  T2CON = 3;    // Timer 2 aus
52
  TR0 = 0;    // Timer 0 aus
53
  T1M = 0;    // Clock div 12
54
  CT1 = 0;    // Timer- Betrieb ein
55
  TH1 = 0x07;    // H-Register laden
56
  TL1 = 0xC0;    // L-Register laden insgesamt: 0xF831
57
  TF1 = 1;    // Interrupt ein
58
  ET1 = 1;    // Timer 1 Interrupt ein 
59
  TR1 = 1;    // Timer 1 einschalten
60
  EA = 1;      // Interrupt ein  
61
  LED_COUNT = LED_BLINK = 1;  // Zähler zurücksetzen und Blinken einschalten
62
  PORTACFG = 0;
63
  PORTBCFG = 0;
64
  PORTCCFG = 0;
65
  iOUTA = 0x00;    // Register vorbelegen
66
  iOEA = 0x30;      // LED-Out ausschalten
67
  
68
  while (1)    // IO- Werte kopieren ...
69
  {  OEA = iOEA;
70
    OEB = iOEB;
71
    OEC = iOEC;
72
    OUTA = iOUTA;
73
    OUTB = iOUTB;
74
    OUTC = iOUTC;
75
    iPINSA = PINSA;
76
    iPINSB = PINSB;
77
    iPINSC = PINSC;
78
  }
79
}
80
81
//————————————————————————————————————————————————————————————————
82
// Timer für ms- Zähler
83
static void T1_isr (void) interrupt 3 using 3
84
{  TL1 = 0xC0;    // L-Register laden insgesamt: 0xF831
85
  TH1 = 0x07;    // H-Register laden
86
  if (LED_BLINK)
87
  {
88
    if (LED_COUNT-- == 0)  // Zähler zurücksetzen
89
    {  LED_COUNT = 50;    // Schleifenzähler neu setzen
90
      iOUTA ^= 0x10;    // LED umschalten
91
      OUTA = iOUTA;
92
    }
93
  }
94
}

Wie gesagt: Vom Programmieren an sich habe ich Ahnung, nur was solche 
"Spezialregister" machen, weiß ich nicht.

Viele Grüße,
elko

PS: Ich arbeite an einem 1-Wire-Projekt, bei dem ich Temperatursensoren 
auslesen will ;-)

von kurz (Gast)


Lesenswert?

>{  TL1 = 0xC0;    // L-Register laden insgesamt: 0xF831
>  TH1 = 0x07;    // H-Register laden

Diese Programmzeilen laden den Timer 1. Wenn der die Blinkfrequenz 
vorgibt, so ist es essentiel, welcher Wert dort geladen ist.

Also Prozessorfrequenz, Teiler und gewünschte Blinkfrequenz 
zusammensuchen und den Wert für den Timer 1 bestimmen. Sonst wird des 
nix.

von elko (Gast)


Lesenswert?

Also es wäre toll, wenn du mir erklären kannst, was diese Speziellen 
Programmzeilen machen! (unter anderem auch, was in der "Blink-Funktion" 
das
1
 interrupt 3 using 3
 bedeutet). Was meinst du mit "Diese Programmzeilen laden den Timer 1."? 
Er gibt die Blinkfrequenz offensichtlich vor, jedoch was bedeuten die 
"L- und H-Register"?
Trotzdem noch mal zu meinem eigentlichen Problem: Das Blinken hat bisher 
eigentlich funktioniert, jedoch irgendwie schmeckt dem Programm das 
Aufrufen der Funktion "hallo()", die in diesem Test nicht mehr als einen 
Wert zurückgibt, nicht... warum das? Programmtechnisch ist doch 
eigentlich alles richtig, oder?

Viele Grüße,
elko

von Helmut L. (helmi1)


Lesenswert?

>Also es wäre toll, wenn du mir erklären kannst, was diese Speziellen
>Programmzeilen machen! (unter anderem auch, was in der "Blink-Funktion"
>das interrupt 3 using 3

Die besagen das das eine Interruptroutine ist die den Interruptvector 3 
belegt. Interrupt vector 3 ist der Interruptvector für den Timer 1.
Using 3 bedeutet das bei eintritt in die Interruptserviceroutine auf den 
Registersatz 3 umgeschaltet werden soll. Damit geht der eintritt in die 
Serviceroutine schneller als wenn man erst alle Register auf den Stack 
retten muss.

Gruss Helmi

von elko (Gast)


Lesenswert?

Also nachdem ich jetzt das Tutorial gelesen habe, ist ein 
Interruptvektor eine Art Zeiger auf eine bestimmte Adresse, die beim 
Auslösen des Interrupts angesprungen wird. Warum bedeutet die 3 denn 
Timer1?
Kann mir jemand nochmal genau sagen, was die einzelnen "Wörter im 
folgendem Codesegment bedeuten (und damit klar machen, wie man es 
schafft, einen Timer einzuschalten)?
1
static void T1_isr (void) interrupt 3 using 3
2
{  TL1 = 0xC0;    // L-Register laden insgesamt: 0xF831
3
  TH1 = 0x07;    // H-Register laden
4
//...
Was bedeutet denn "auf den Registersatz 3 umschalten"? Könnte es so 
passieren, dass Daten verloren gehen und das Programm "spinnt"?

Viele Grüße,
elko

von Helmut L. (helmi1)


Lesenswert?

>Warum bedeutet die 3 denn Timer1?

Weil das vom Hersteller so vorgegeben ist.

>Was bedeutet denn "auf den Registersatz 3 umschalten"?

Der 8051 Prozessor hat 4 Registerbänke. Also die Register R0 .. R7 sind 
4 mal vorhanden. Du hast aber nur jeweils eine dieser Registerbänke im 
direkten zugriff. Di anderen kann man dann nur über absolute Addressen 
ansprechen. Umgeschaltet wird zwischen diesen 4 Bänken über 2 Bits im 
PSW.
Und genau dieses umschalten bewirkt die Angabe "using 3"

>Könnte es so
>passieren, dass Daten verloren gehen und das Programm "spinnt"?

Ja .

von elko (Gast)


Lesenswert?

Okay, das hört sich schonmal sehr aufschlussreich an... jetzt stellt 
sich mir nur die Frage, was man dagegen tun kann ;-) ich habe gelesen 
(bei avr-µC), dass man die sfr temporär speichern kann, die sfr so 
manipulieren, dass Interrupt ausgeschaltet wird, dann Code, der nicht 
unterbrochen werden darf ausführen lassen kann und dann über die kopie 
wieder die sfr so setzen, wie sie vorher waren. Doch dabei stellt sich 
natürlich die Frage, ob und wie das beim an2131 so geht (wovon ich mal 
ausgehe) und vor allem: Welche Programmteile muss ich dann schützen? Ich 
kann ja unmöglich das ganze Programm "schützen", sonst kommt von den 
Interrupts ja nix mehr an...

von Helmut L. (helmi1)


Lesenswert?

Der Compiler sollte beim eintritt in die Interruptserviceroutine schon 
alles sichern. Die Interrupts must du im Hauptprogramm nur dann sperren 
wenn du auf Variablen zugreifen möchtest die in der Serviceroutine 
verändert werden können. Wenn du auf eine 16 Bit Variable zugreifen 
möchtest die in deiner Serviceroutine verändert werden kann sokann es 
passieren das du das erste Byte erwischst und dann kommt der Interrupt 
der verändert jetzt das andere Byte der Variable. Danach stimmt der Wert 
der Variable in der Hauptroutine nicht mehr. Das eine Byte stammt ja vor 
dem eintritt in die Serviceroutine und das andere Byte nach ablauf der 
Routine. Du must halt vorher die Interrupts mit "EA = 0" sperren und 
danach wieder mit "EA = 1" freigeben.

von elko (Gast)


Lesenswert?

Schön zu hören ;-)
Dann Frage ich mich, warum -obwohl ich bezüglich Variablen, die in der 
ISR verwendet werden nichts geändert habe- sich die Blinkgeschwindigkeit 
so krass ändert.
Gibt es eigentlich eine schöne Übersicht, in der alle Registernamen wie 
EA und THirgendwas aufgelistet und erklärt sind? Das wäre für mich sehr 
hilfreich, denn unter den vielen Abkürzungen kann ich mir herzlich wenig 
vorstellen...

von Helmut L. (helmi1)


Lesenswert?

Hier waeren 2 Manuals fuer dich allerdings in Englisch.
Deutsche Literatur gabs mal zum 8051 in den fruehern 90er Jahre des 
vorigen Jahrhunderts.


http://www.atmel.com/dyn/resources/prod_documents/doc0509.pdf

http://www.nxp.com/acrobat_download/various/80C51_FAM_PROG_GUIDE_1.pdf

Gruss Helmi

von Peter D. (peda)


Lesenswert?

elko schrieb:
> Also es wäre toll, wenn du mir erklären kannst, was diese Speziellen
> Programmzeilen machen! (unter anderem auch, was in der "Blink-Funktion"
> das
1
 interrupt 3 using 3
 bedeutet).


Bei allen 8051-Fragen, ist die Keil Webseite ein vorzügliche Referenz. 
Da gibt es z.B. die Knowledgebase und die FAQs.

Die Interruptvektoren werden durchnumeriert (wie bei allen MCs). Welche 
Nummer welcher Quelle entspricht, steht im Datenblatt Deines konkreten 
8051-er.

Die ersten 6 Vektoren sind in der Regel gleich (0..5 = EX0, T0, EX1, T1, 
UART, T2).

Das "using 3" ist in der Regel falsch.
Es richtet mehr Schaden als Nutzen an und sollte daher nur von 
erfahrenen Programmierern verwendet werden.
Laß es weg!


Peter

von elko (Gast)


Lesenswert?

Heyy :D
Die letzten beiden Nachrichten haben mir echt sehr weitergeholfen! 
Vielen Dank dafür euch schonmal!
Ich habe mir jetzt mal die Datenblätter und Manuals durchgelesen und mir 
ist jetzt einiges klarer ;-)
Außerdem habe ich festgestellt, dass die hallo-Funktion tatsächlich 
durch den Interrupt gestört wird. Das habe ich dadurch erkannt, dass 
ohne die Interrupt-Funktion 7 zurückgegeben wird, mit jedoch viele 
Verschiedene Werte... Kann mir da jemand weiterhelfen und erklären, 
woran das liegt?

Viele Grüße,
elko

von elko (Gast)


Lesenswert?

Es hat doch bestimmt jemand eine Idee, oder?

von APW (Gast)


Lesenswert?

Was passiert, wenn du die Int-Funktion komplett leerräumst (also 
nichtmal TH/TL neu laden) ?
Wie groß ist denn das Programm ?
Hat es event. einen Sinn, wenn du den Compileroutput (asm-Listing) mal 
vorzeigst ?

von Robert W. (rweber)


Lesenswert?

elko schrieb:
> Vom Programmieren hab ich Ahnung, ja (habe auch schon viel mit dem µC
> programmiert...). Meine Programme haben immer auf einen winzigen

> Wie gesagt: Vom Programmieren an sich habe ich Ahnung, nur was solche
> "Spezialregister" machen, weiß ich nicht.
>

Das kannst Du noch ein parmal wiederholen, obs dadurch allerdings 
richtiger wird?

Ein Teil der Loesung steht im 1, Post vom Falk. Schon mal schlau gemacht 
was volatile bedeutet?

Der andere Teil waere, sich zu verdeutlichen, dass der Zugriff auf den 
XDATA memory nicht atomar vonstatten geht.

von elko (Gast)


Lesenswert?

Also:
@APW:
Ich habe den Quelltext folgendermaßen modifiziert:
1
...
2
3
while (1)
4
{          
5
var1=3;
6
var0=hallo();  
7
var1=4;
8
}
9
10
...
11
12
13
unsigned char hallo(){
14
return 7;
15
}
16
17
18
19
//————————————————————————————————————————————————————————————————
20
// Timer für ms- Zähler  (bringt die LED A4 blinken)
21
22
static void T1_isr (void) interrupt 3
23
{  TL1 = 0xC0;    // L-Register laden insgesamt: 0xF831
24
  TH1 = 0x07;    // H-Register laden
25
  if (LED_BLINK)
26
  {
27
    if (LED_COUNT-- == 0)  // Zähler zurücksetzen
28
    {  LED_COUNT = 50;    // Schleifenzähler neu setzen
29
      OUTA ^= 0x10;    // LED umschalten
30
    }
31
  }
32
}

Wie man sieht, habe ich nicht viel verändert, aber es ergibt sich 
wunderliches:
1. var0 nimmt NICHT den Wert 7 an
   var1 nimmt NUR den Wert 3 an
   die LED blinkt (wie zu erwarten)
Kommentiere ich die beiden Zeilen
1
  TL1 = 0xC0;    // L-Register laden insgesamt: 0xF831
2
  TH1 = 0x07;    // H-Register laden
aus, so ergibt sich folgendes:
2. var0 nimmt irgendwelche schnell wechselden Werte an
   var1 nimmt sowohl den Wert 3, als auch 4 an (wie erwartet)
   die LED blinkt (trotz entfernen der beiden Zeilen)

Ist die Interrupt-Funktion komplett leer, so sieht man:
1. var0 nimmt NICHT den Wert 7 an
   var1 nimmt NUR den Wert 3 an
   die LED blinkt NICHT (okay, hätte mich auch gewundert...)

@Robert:
>Das kannst Du noch ein parmal wiederholen, obs dadurch allerdings
>richtiger wird?
Danke.
Ja, ich habe nachgeschaut, was es mit volatile auf sich hat und dabei 
festgelstellt: Ich habe KEINE Variablen, die sowohl in der isr, als auch 
im Hauptprogramm benutzt werden (die paar Aufrufe am Anfang zählen für 
mich nicht, da das Programm im Prinzip immer in der while-Schleife 
ist...

>Der andere Teil waere, sich zu verdeutlichen, dass der Zugriff auf den
>XDATA memory nicht atomar vonstatten geht.

Das hört sich schon eher nach einer Lösung oder besser gesagt nach einem 
Problem an. Was kann ich denn dagegen tun?

Viele Grüße,
elko

von elko (Gast)


Lesenswert?

Nachtrag: Ich habe leider keine Information gefunden, was TH1 und TL1 
genau bedeutet (okay, high und low bytes, aber was für einen Sinn haben 
sie?

von elko (Gast)


Angehängte Dateien:

Lesenswert?

hier noch das asm-listing ;-)

von APW (Gast)


Lesenswert?

Wieso nagelst du eigentlich die meisten deiner Variablen auf bestimmten 
Adressen fest ?

von Robert W. (rweber)


Lesenswert?

elko schrieb:

> Ja, ich habe nachgeschaut, was es mit volatile auf sich hat und dabei
> festgelstellt: Ich habe KEINE Variablen, die sowohl in der isr, als auch
> im Hauptprogramm benutzt werden (die paar Aufrufe am Anfang zählen für
> mich nicht, da das Programm im Prinzip immer in der while-Schleife
> ist...
>
Fuer deinen Code, den um um 26.07.2009 18:22 gepostet hast trifft das 
definitiv nicht zu.


@APW
> Wieso nagelst du eigentlich die meisten deiner Variablen auf bestimmten
> Adressen fest ?

Beim 8051 kann man ueber das ext. memory Interface seine Peripherie in 
den XDATA Space mappen und so wie auf normale Variablen zugreifen. Ob 
das in diesem Fall so ist, kann nur der Author verraten. Sollten es nur 
ganz "normale" Variablen sein, so macht im gezeigen Code weder das 
festnageln, noch das xdata Sinn.

von elko (Gast)


Lesenswert?

>> Ja, ich habe nachgeschaut, was es mit volatile auf sich hat und dabei
>> festgelstellt: Ich habe KEINE Variablen, die sowohl in der isr, als auch
>> im Hauptprogramm benutzt werden (die paar Aufrufe am Anfang zählen für
>> mich nicht, da das Programm im Prinzip immer in der while-Schleife
>> ist...
>>
>Fuer deinen Code, den um um 26.07.2009 18:22 gepostet hast trifft das
>definitiv nicht zu.

Das stimmt... ich habe das Beispielprogramm so modifiziert, dass in der 
while-Scleife nicht mehr auf Port A zugegriffen wird. Also von daher 
stimmt dann doch meine Aussage, doer meintest du etwas anderes?

@"festnageln":
Ich habe nicht ganz verstanden, ob Robert das meint, was zumindest mein 
Grund für das "festnageln" der Variablen ist: Irgendwie möchte ich ja 
wissen, was im Chip vor sich geht. Wenn den Variablen Speicheradressen 
fest zugewiesen sind, kann ich vom PC aus mir die Werte der Variablen 
anschauen. So habe ich auch immer festgestellt, was ich in den vorigen 
Posts geschrieben habe (" var0 nimmt NICHT den Wert 7 an", etc. etc.).
Gibt es vielleicht eine bessere oder einfacherere Art, in den Chip 
"hineinzuschauen", damit man das Programm debuggen kann?
Ich weise nochmal darauf hin, dass ich in meinem Post vom 28.07.2009 
01:08 beschrieben habe, was sich für Dinge in dem Programm ereignen. 
Vielleicht hilft das zu einer Lösung weiter ;-))

Gruß,
elko

von Helmut L. (helmi1)


Lesenswert?

>Nachtrag: Ich habe leider keine Information gefunden, was TH1 und TL1
>genau bedeutet (okay, high und low bytes, aber was für einen Sinn haben
>sie?

Dann hast du dir das Datenblatt zum 8051 aber noch nicht genau 
durchgelesen.
Diese beiden Register und auch TH0,TL0 sind die Zaehlregister von Timer 
1 und Timer 0 und seit anbegin der 8051 Zeit in jedem Prozessor drin. 
Beim ueberlauf dieser beiden Register wird ein Interrupt ausgeloest. 
Innerhalb der Interruptserviceroutine muessen dann diese beiden Register 
neu gesetzt werden. Unterbleibt das dann wird die Interruptroutine immer 
nach 65536 Countercyclen wieder aufgerufen. Diese Zaehler zaehlen 
aufwaerts. Wenn diese Zeit kuerzer werden soll muss du diese beiden 
Register beim eintritt in die Serviceroutine wieder neu laden. Der 
Reloadwert berechnet sich da die Zaehler ja aufwaerts zaehlen und der 
Interrupt beim Ueberlauf von 0xffff -> 0x0000 aufgeloest wird 
folgendermassen:

Reload(TL1,TH1) = 65536 - (t * fc / 12).

t ist deine Zeit zwischen 2 Interrupts
fc ist die Clockfrequenz deines Prozessors.

Gruss Helmi

von elko (Gast)


Lesenswert?

Ah, also müsste dann die Blinkgeschwindigkeit abnehmen, wenn man das 
Laden der beiden Register rausnimmt, oder?
Seeehr, schön :D habs mal ausprobiert und es klappt :D (endlich mal 
wieder was, was auf Anhieb funktioniert...)
Trotzdem fuchst es mich teuflisch, dass allein der Aufruf der Funktion 
hallo(), selbst wenn ich auch noch das "return 7" rausnehme, die LED zum 
ausrasten bringt... Hat jemand dazu eine Idee?
Wenn gewünscht, hänge ich auch nochmal die entsprechenden Passagen 
Quelltext dran ;-)

Gruß,
elko

von Helmut L. (helmi1)


Lesenswert?

>Ah, also müsste dann die Blinkgeschwindigkeit abnehmen, wenn man das
>Laden der beiden Register rausnimmt, oder?

Richtig , dann macht der Zaehler eine komplette Umdrehung.

>(endlich mal wieder was, was auf Anhieb funktioniert...)

Kaum macht man es richtig funktionierts.


>Trotzdem fuchst es mich teuflisch, dass allein der Aufruf der Funktion
>hallo(), selbst wenn ich auch noch das "return 7" rausnehme, die LED zum
>ausrasten bringt... Hat jemand dazu eine Idee?

Hat deine IDE keinen integrierten Simulator wo du das ganze mal Step by 
Step im PC durchsteppen kannst ?

Welche IDE / Compiler benutzt du ueberhaupt ?

Ansonsten lade die mal die Demo von Keil runter da ist ein Simulator mit 
drin.

von Robert W. (rweber)


Lesenswert?

elko schrieb:

> @"festnageln":
> Ich habe nicht ganz verstanden, ob Robert das meint, was zumindest mein
> Grund für das "festnageln" der Variablen ist: Irgendwie möchte ich ja
> wissen, was im Chip vor sich geht. Wenn den Variablen Speicheradressen
> fest zugewiesen sind, kann ich vom PC aus mir die Werte der Variablen
> anschauen. So habe ich auch immer festgestellt, was ich in den vorigen

Gibt es keinen vernuneftigen Grund, Variablen ins XDATA zu legen, dann 
lass es bleiben. Nimm data, oder alternativ idata. Wenn XDATA, dann 
musst Du sicherstellen, dass dein Contoller an den von dir festgelegten 
Adressen auch wirklich XDATA Memory hat und evtl (haengt von Consoller 
ab) auch aktiviert ist. Sonst laeuft der Speicherzugriff ueber das 
externe Memeory interface in leere und man liest unsinnige Daten ueber 
P0 ein.

Das Festlegen der Speicheradresse fuer Variablen sollte man tunlichst 
dem Compiler ueberlassen. Schonmal eine Fehlerquelle weniger.

Du solltest dir mal wirklich die Zeit nehmen, und dir das Memory Layout 
des 8051 verinnerlichen.

von elko (Gast)


Lesenswert?

Jupp, ich nutze µVision3... aber das mit dem Simulator ist halt immer so 
ne Sache. Wenn man dann einen Input simulieren will ist sdas meiner 
Meinung nach sehr umständlich...

von APW (Gast)


Lesenswert?

Vom assembler-Listing her müsste das eigentlich einwandfrei 
funktionieren, meine ich.
Meine Befürchtung ist nur, dass die Variablen an Speicherstellen 
platziert sind, die schon anderweitig benutzt werden (Debugger, 
C-Hilfsfunktionen o.ä.).  Wenn ich dich richtig verstehe, sind die 
Var-Adressen echtes Ram, also keine Register von externen Chips ?
Ich kenne den speziellen uC nicht. Ist das XRAM extern oder on Chip ?
Wie debuggst du eigentlich ?
Wieviel XRAM hast du ? Was passiert, wenn du die Variablen etwa in der 
Mitte des zur Verfügung stehenden XRAM-Bereiches platzierst ?
Oder du lässt die Variablen wie üblich vom Compiler/Linker reservieren 
und schaust dann fürs debuggen im .map-File nach, wo diese platziert 
wurden.

von elko (Gast)


Lesenswert?

@Robert: und wie soll ich dann die einzelnen Variablenwerte auslesen?

von Helmut L. (helmi1)


Lesenswert?

>Jupp, ich nutze µVision3... aber das mit dem Simulator ist halt immer so
>ne Sache. Wenn man dann einen Input simulieren will ist sdas meiner
>Meinung nach sehr umständlich...

Koennte ich so nicht sagen. Der Keil-Simulator ist so schon gut.
Aber trotzdem simulier doch mal dein Program. Dann siehst du doch wer 
dir da in die Suppe spuckt.

von Robert W. (rweber)


Lesenswert?

elko schrieb:
> @Robert: und wie soll ich dann die einzelnen Variablenwerte auslesen?

Versteh ich nicht. Variablen haben doch Namen, damit kann man sie such 
auslesen? Oder meinst Du im Simulator? Der kann auch mit Variablen Namen 
umgehen.

Poste doch endlich mal das komplette Programm und verrate welchen 
Controller du verwendest.

von elko (Gast)


Angehängte Dateien:

Lesenswert?

Robert schrieb:
>Poste doch endlich mal das komplette Programm und verrate welchen
>Controller du verwendest.

Das mit dem Simulieren werde ich nachher nochmal ausprobieren, hier 
schonmal das komplette Programm im jetzigen Zustand.
Ich verwende den AN2131 von Cypress...

von elko (Gast)


Lesenswert?

@Robeert:
was ich noch vergessen hatte: Wie soll ich vom PC aus die Variablen aus 
dem µC auslesen?

von APW (Gast)


Lesenswert?

>Ich verwende den AN2131 von Cypress...
Steht die Bezeichnung auf den Chip drauf ??

von elko (Gast)


Lesenswert?

Jupp, okay, das SC hat noch gefehlt: AN2131SC

von elko (Gast)


Lesenswert?

Kann mir jemand erklären, wie ich einen Interrupt mit µVision3 
simulieren kann? Ohne dass ich den Interrupt einbringe scheint es 
simulieert nämlich zu funktionieren.

von elko (Gast)


Lesenswert?

Huhuu ;-)

von Helmut L. (helmi1)


Lesenswert?

Draengel nicht so.

Wenn du deinen Timer korrekt initialisiert hast sollte der auch im 
Simulator ausloesen. Ansonsten kannst du das entsprechende Bit das den 
Interrupt ausloest auch in den Perepherieregistern von Hand setzen.

von elko (Gast)


Lesenswert?

Das ist aber sehr seltsam. Wenn ich das ganze step-by-step durchgehe 
komme ich nie in die isr, und wenn ich auf RUN klicke und eine Weile 
später auf Stop, war das Programm auch nicht in der isr.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

elko schrieb:
> Das ist aber sehr seltsam. Wenn ich das ganze step-by-step durchgehe
> komme ich nie in die isr, und wenn ich auf RUN klicke und eine Weile
> später auf Stop, war das Programm auch nicht in der isr.

Wie schon woanders beschrieben sind beim Steppen die Interrupts 
ausgeschaltet.
Also: BP an den Beginn einer ISR setzen und dann Go!

von elko (Gast)


Lesenswert?

Also: ich habe jetzt auch mal ausprobiert, einen Interrupt in der ISR zu 
setzen und dann im debug-modus auf RUN zu klicken... wenn ich einen 
Breakpoint in der Main-Funktion oder in eine von main() aufgerufene 
Funktion setze, so hält das Programm am BP. Die ISR wird in der 
Simulation nie ausgelöst. Eine Idee?

von elko (Gast)


Lesenswert?

Ich glaube mein letzter Post ist etwas komisch formuliert:
Wenn ich einen BP in der ISR setze, hält das Programm dort nicht an, 
weil der Interrupt nie ausgelöst wird... obwohl ich auf RUN geklickt 
habe...
Jetzt eine Idee?

von Random .. (thorstendb) Benutzerseite


Lesenswert?

elko schrieb:
> Ich glaube mein letzter Post ist etwas komisch formuliert:
> Wenn ich einen BP in der ISR setze, hält das Programm dort nicht an,
> weil der Interrupt nie ausgelöst wird...

genau!
- interrupt ist eingeschaltet (enable?)
- bedingung für interrupt wird erfüllt? Z.B. timer überlauf?

Bedenke, dass die Simulation um eiiiiiniges langsamer (faktor 10...100) 
laufen kann in bestimmten situationen als auf real HW.
Setze mal die Timer bedingung für den INT etwas runter (z.B. /10)

Kannst dir auch nen neuen Target machen, namens "Simulator".
In der "Options for Target" setzt du dann bei C/C++ ein #define namens 
USE_SIMULATOR__

in deinem code machste dann:

#if defined USE_SIMULATOR
  ... timerPreload = val/10;
#else
  ... timerPreload = val;
#endif


VG,
/th.

von elko (Gast)


Lesenswert?

Hallöle :D
ich habe nun die Lösung (bei den Debug-Einstellungen hat die Angabe 
einer DLL gefehlt...)! Danke Thorsten!
Nun noch zu eienr anderen Frage zum gleichen Thema:
Durch verschiedene int-Variablen, die in Funktionen untergebracht 
wurden, blinkt die LED, die den Timer-Interrupt anzeigt, viel 
schneller... nachdem ich sie als unsigned char deklariert habe, blinkt 
die LED wieder normal. Hat jemand eine Erklärung?

Viele Grüße,
elko

von elko (Gast)


Lesenswert?

Halluu

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.