Forum: Compiler & IDEs Code wird nicht in richtiger Reihenfolge abgearbeitet


von Jens J. (trial)


Lesenswert?

Hallo...

ich bin ja noch recht neu hier und vermisse irgendwie die Möglichkeit 
gezielt beim Code helfen zu lassen. Finde ich das nur nicht?

Nachfolgend bin ich mir nicht sicher ob es sich u ein Compiler oder Code 
Problem handelt. Bin nämlich nicht nur auf dieser Seite neu. Bin aktuell 
noch auf der Technikerschule und hatte vorher keine Microcontroller 
Erfahrung.


Mein Problem, oder besser meine Verwunderung besteht darin das unten 
stehendes Programm beim debuggen nicht step für step durchstept sondern 
z.B. erst die Interrupt Freigaben abarbeitet und dann die Deklarationen.

Bei den Ausgaben z.B. auch erst die Ports A und dann erst die B´s.
Gibt noch mehr solche Abweichungen die sicherlich alle den gleichen 
Grund haben. Nur welchen? im Zweiten Durchlauf geht es dann (fast) alles 
in der richtigen Reihenfolge. Was bleibt ist, das er nach dem 
hundertstel++ nochmal zur Deklaration des selbigen springt.

Es handelt sich um eine Stoppuhr die wohl alles andere als genau geht, 
doch steht erstmal das programmieren an sich im Vordergrund.

Oh.... und wenn wir schon dabei sind: Vllt. kann mir jemand sagen wie 
ich es schaffe im AVR Studio 7 die Interrupts zu simulieren. Bekomme das 
irgendwie nicht hin.

Hier erstmal der Code:

1
#define TAKT 1000000LU /* Controlertakt 1Mhz*/
2
3
4
#include <asf.h> // Bibliothek für STK600 (glaub ich)
5
#include <avr/interrupt.h>
6
#include <util/delay.h>
7
8
volatile char on_off = 1; //Interrupt gesteuertes bit um Stoppuhr laufen zu lassen oder nicht
9
volatile char reset = 0; // für den Reset der Stoppuhr
10
11
char segment_code[16]={0xC0,0xF9,0xA4,0xB0, 0x99,0x92,0x82,0xF8,
12
            0x80,0x90,0x88,0x83,0xC6,0XA1,0x86,0x8E};
13
            
14
ISR(INT0_vect)
15
{
16
  if ( on_off == 0)
17
  {
18
     on_off = 1;
19
  }
20
  else
21
  {
22
    on_off = 0;
23
  }
24
}        
25
26
ISR(INT1_vect)
27
{
28
  reset = 1;
29
}
30
31
32
33
34
int main (void)
35
{
36
  /* Insert system clock initialization code here (sysclk_init()). */
37
38
  board_init();
39
40
  /* Insert application code here, after the board has been initialized. */
41
  
42
  char anzeigen;
43
  char Hundertstel = 0;
44
  char ein_sec = 0;
45
  char zehn_sec = 0;
46
  char ein_min = 0;
47
  
48
  GICR  &= 0xFF;
49
  MCUCR &= 0xFA;
50
  
51
  DDRA = 0xff;
52
  DDRB = 0xff;
53
  DDRD = 0x00;
54
  
55
  sei();
56
  while (1)
57
{
58
    
59
  
60
  if(on_off==1) //start Zähler
61
{
62
    if (Hundertstel == 9)
63
    {
64
      if (ein_sec == 9)
65
      {
66
        if (zehn_sec == 5)
67
        {
68
          if (ein_min == 9)
69
          {
70
            on_off=0;
71
          } 
72
          else
73
          {
74
            ein_min++;
75
            zehn_sec = 0;
76
            ein_sec = 0;
77
            Hundertstel = 0;
78
          }
79
        } 
80
        else
81
        {
82
          zehn_sec++;
83
          ein_sec = 0;
84
          Hundertstel = 0;
85
        }
86
      }
87
      else
88
      {
89
        ein_sec++;
90
        Hundertstel = 0;
91
      }
92
    } 
93
    else
94
    {
95
      Hundertstel++;
96
    }
97
} // Ende zähler
98
99
100
101
  for (anzeigen=5;anzeigen>0;anzeigen--)
102
  {
103
  
104
  
105
    if (reset==1)
106
    {
107
      ein_min = 0;
108
      zehn_sec = 0;
109
      ein_sec = 0;
110
      Hundertstel = 0;
111
      reset = 0;
112
    }
113
    
114
      
115
        PORTA = 0x01;
116
        PORTB = segment_code[Hundertstel];
117
        _delay_ms(5);
118
      
119
        PORTA = 0x02;
120
        PORTB = segment_code[ein_sec];
121
        _delay_ms(5);
122
        
123
        PORTA = 0x03;
124
        PORTB = segment_code[zehn_sec];
125
        _delay_ms(5);
126
        
127
        PORTA = 0x04;
128
        PORTB = segment_code[ein_min];
129
        _delay_ms(5);
130
  
131
  
132
  }
133
  
134
  
135
  
136
}
137
  
138
  
139
  
140
  return 0;
141
}

[Mod: C-Tags eingefügt]

: Bearbeitet durch Moderator
von Nop (Gast)


Lesenswert?

Jens N. schrieb:

> Mein Problem, oder besser meine Verwunderung besteht darin das unten
> stehendes Programm beim debuggen nicht step für step durchstept sondern
> z.B. erst die Interrupt Freigaben abarbeitet und dann die Deklarationen.

Der Compiler darf Zugriffe umordnen, wenn das keinen externen Effekt 
hat. Die Anordnung von volatile-Zugriffen darf er nicht umordnen, wohl 
aber die nicht-voltile um Verhältnis zu den volatile.

> Bei den Ausgaben z.B. auch erst die Ports A und dann erst die B´s.

Da ist ja auch erst a und dann B im Quelltext, und beidemale steckt 
volatile dahinter.

von Jens J. (trial)


Lesenswert?

> Da ist ja auch erst a und dann B im Quelltext, und beidemale steckt
> volatile dahinter.

Ich meinte das er erst jedes A aus gibt bevor er sich an die B´s macht.


Die volatile stecken doch nur dort wo die Interrupts die Variablen 
ändern. Reicht der Effekt so weit?

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

Jens N. schrieb:
> Mein Problem, oder besser meine Verwunderung besteht darin das unten
> stehendes Programm beim debuggen nicht step für step durchstept sondern
> z.B. erst die Interrupt Freigaben abarbeitet und dann die Deklarationen.

Hast du vor dem Debuggen alle Optimierungen des Compilers abgedreht?
Die veraendern durchaus den Programmfluss, und/oder es schaut dann so 
aus.

leo

von Jens J. (trial)


Lesenswert?

>
> Hast du vor dem Debuggen alle Optimierungen des Compilers abgedreht?
> Die veraendern durchaus den Programmfluss, und/oder es schaut dann so
> aus.
>
> leo

Ich weis garnicht wie das geht. Ich wüsste nichtmal nach was ich, in der 
Hilfe, auf Englisch suchen müsste. Aus dem nichts heraus ein Englisches 
Programm zu verstehen wird sicher ´ne Weile dauern....

Kannst du mir sagen was ich abstellen muss? Oder zumindest nach was ich 
suchen soll?

von leo (Gast)


Lesenswert?

Jens N. schrieb:
> Kannst du mir sagen was ich abstellen muss? Oder zumindest nach was ich
> suchen soll?

Ich habe kein Atmel-Studio, aber das gefunden:
https://www.microchip.com/webdoc/GUID-ECD8A826-B1DA-44FC-BE0B-5A53418A47BD/index.html?GUID-8FF26BD2-DBFF-48DD-91FB-8585D91A938D

HTH leo

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Jens N. schrieb:
> Ich weis garnicht wie das geht.

Im AVR-Studio kannst Du für das Projekt RELEASE oder DEBUG einstellen. 
Wenn Du DEBUG wählst, werden die Optimierungen in der Regel auch 
abgeschaltet (falls man nicht daran gedreht hat).

Dann wird die Code-Reihenfolge auch wieder so sein, wie Du es erwartest.

von Rolf M. (rmagnus)


Lesenswert?

Jens N. schrieb:
>> Da ist ja auch erst a und dann B im Quelltext, und beidemale steckt
>> volatile dahinter.
>
> Ich meinte das er erst jedes A aus gibt bevor er sich an die B´s macht.

Das dürfte er nicht.

> Die volatile stecken doch nur dort wo die Interrupts die Variablen
> ändern. Reicht der Effekt so weit?

Nein. Alle I/O-Register sind als volatile definiert.

Noch eine kleine Anmerkung unabhängig davon:

Jens N. schrieb:
> #define TAKT 1000000LU /* Controlertakt 1Mhz*/

Da du die Delay-Funktionen nutzt: Die brauchen die Information über den 
CPU-Takt, allerdings müsste es dafür nicht TAKT, sondern F_CPU heißen.

von Markus (Gast)


Lesenswert?

ähnliches hat mich vor ein paar wochen an den rande des wahnsinns 
getrieben.
stell mal die optimierung von -O1 auf -Og, so hats bei mir dann perfekt 
funktioniert.

Properties => Toolchain => AVR/GNU C Compiler => Optimization

von Kaj (Gast)


Lesenswert?

Markus schrieb:
> stell mal die optimierung von -O1 auf -Og, so hats bei mir dann perfekt
> funktioniert.
Wenn der Code ohne Optimierung funktioniert, aber mit Optimierung nicht, 
dann ist der Code kaputt.

Beitrag #5745971 wurde vom Autor gelöscht.
von Oliver S. (oliverso)


Lesenswert?

Der Zusammenhang zwischen Sourcecode und Assemblerbefehlen geht in den 
höheren Optimierungsstufen schon mal verloren, oder wird falsch 
dargestellt. Da zeigt der Debugger dann falsche Positionen im Sourcedode 
an. Ist so, und lässt sich auch nicht ändern.

Was der Prozessor tatsächlich macht, sieht man dann nur noch im 
Assemblercode.

-Og wurde extra deshalb erfunden, da klappt das mit dem Debuggen noch. 
Bei allen anderen Optimierungsstufen geht es gerade beim avr-gcc häufig 
schief.

Oliver

von hunderstel (Gast)


Lesenswert?

>if (Hundertstel == 9)

Zählen die Hunderstel nur bis 9?
Sollte es nicht 99 heißen?

Oder hab ich was übersehen?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

hunderstel schrieb:
> Zählen die Hunderstel nur bis 9?

Vermutlich meint er Zehntel.

von Jens J. (trial)


Lesenswert?

Frank M. schrieb:
> hunderstel schrieb:
>> Zählen die Hunderstel nur bis 9?
>
> Vermutlich meint er Zehntel.

ja genau... das mir das selbst nicht aufgefallen ist …

von Jens J. (trial)


Lesenswert?

Markus schrieb:
> ähnliches hat mich vor ein paar wochen an den rande des wahnsinns
> getrieben.
> stell mal die optimierung von -O1 auf -Og, so hats bei mir dann perfekt
> funktioniert.
>
> Properties => Toolchain => AVR/GNU C Compiler => Optimization

wo finde ich denn diese properties?
Toolchain habe ich zwar unter Tools/Optionen gefunden aber ohne AVR/GNU

von Jens J. (trial)


Lesenswert?

Frank M. schrieb:
> Jens N. schrieb:
>> Ich weis garnicht wie das geht.
>
> Im AVR-Studio kannst Du für das Projekt RELEASE oder DEBUG einstellen.
> Wenn Du DEBUG wählst, werden die Optimierungen in der Regel auch
> abgeschaltet (falls man nicht daran gedreht hat).
>
> Dann wird die Code-Reihenfolge auch wieder so sein, wie Du es erwartest.

Wo denn? Ich suche und suche und finde nichts.

von Jens J. (trial)


Lesenswert?

> Da du die Delay-Funktionen nutzt: Die brauchen die Information über den
> CPU-Takt, allerdings müsste es dafür nicht TAKT, sondern F_CPU heißen.

Ah okay. Meines Wissens sollte das dafür sein den CPU Takt festzunageln. 
Habe ich seitens meines Lehrers wohl eine Fehlinformation.

Heißt also: wenn man Programme mit Timern mal auf einen anderen 
Controller portiert, müsste man sie neu berechnen?!

von Sven S. (boldie)


Lesenswert?

Bevor du das Debuggen anfängst, ein paar Tipps zum Programm.

Die Stoppuhr wird sehr ungenau werden, da du die Zähler nicht an eine 
Zeitbasis hängst, sondern im Hauptprogramm mit allen Einflüssen 
Weiterzähler. Je nachdem welche Stelle du Weiterzähler läuft dein Code 
langsamer oder schneller. Normal macht man das besser so dass man einem 
Timer nimmt und dann entweder mit einer Zeit rechnet oder sich z.b. 
Ticks merkt und die dann nutzt um die Uhr weiterzustellen.

Ich nehme an du hast noch Probleme mit Start und Stop da die Eingänge 
nicht entprellt sind.

Das wirst du im Debugger beides nur schwer finden, da die Sachen 
timingabhängig sind.

von Rolf M. (rmagnus)


Lesenswert?

Jens N. schrieb:
>> Da du die Delay-Funktionen nutzt: Die brauchen die Information über den
>> CPU-Takt, allerdings müsste es dafür nicht TAKT, sondern F_CPU heißen.
>
> Ah okay. Meines Wissens sollte das dafür sein den CPU Takt festzunageln.
> Habe ich seitens meines Lehrers wohl eine Fehlinformation.

Was meinst du mit "festzunageln"? F_CPU ändert am Takt jedenfalls 
nichts. Den stellt man über die Fuses, ggf. Taktteiler-Register und 
falls vorhanden den verwendeten Quarz ein. F_CPU dient lediglich dazu, 
den Delay-Funktionen mitzuteilen, mit welchem Takt der Prozessor läuft, 
damit sie intern die Delay-Zeiten korrekt berechnen können.

> Heißt also: wenn man Programme mit Timern mal auf einen anderen
> Controller portiert, müsste man sie neu berechnen?!

Wenn der einen anderen Takt hat, ja. Das kann man aber natürlich auch 
als Formel in den Code schreiben und F_CPU dann dafür benutzen.

von Kaj (Gast)


Lesenswert?

Jens N. schrieb:
>> Da du die Delay-Funktionen nutzt: Die brauchen die Information über den
>> CPU-Takt, allerdings müsste es dafür nicht TAKT, sondern F_CPU heißen.
>
> Ah okay. Meines Wissens sollte das dafür sein den CPU Takt festzunageln.
> Habe ich seitens meines Lehrers wohl eine Fehlinformation.
Auweia. Da braucht dein Lehrer aber nochmal Nachhilfe...
Was da per #define gesetzt wird hat keine auswirkung auf den Takt der 
CPU. Die laeuft so schnell wie es die (ueber die Fuses) eingestellte 
Taktquelle (interner RC, externer Quarz, etc.) vorgibt.

Jens N. schrieb:
> Heißt also: wenn man Programme mit Timern mal auf einen anderen
> Controller portiert, müsste man sie neu berechnen?!
Ja. Die Register koennen anders sein, andere Prescaler, anderer CPU 
Takt, etc. Alles was an der Hardware haengt muss ueberarbeitet werden, 
wenn es auf eine neue Architektur geht.
Deswegen trennt man Programmlogik von Hardwarezugriffen, damit man 
moeglichst wenig neumachen muss, wenn man die Architektur wechselt.

von Jens J. (trial)


Lesenswert?

Sven S. schrieb:
> Bevor du das Debuggen anfängst, ein paar Tipps zum Programm.
>
> Die Stoppuhr wird sehr ungenau werden, da du die Zähler nicht an eine
> Zeitbasis hängst, sondern im Hauptprogramm mit allen Einflüssen
> Weiterzähler. Je nachdem welche Stelle du Weiterzähler läuft dein Code
> langsamer oder schneller. Normal macht man das besser so dass man einem
> Timer nimmt und dann entweder mit einer Zeit rechnet oder sich z.b.
> Ticks merkt und die dann nutzt um die Uhr weiterzustellen.
>
> Ich nehme an du hast noch Probleme mit Start und Stop da die Eingänge
> nicht entprellt sind.
>
> Das wirst du im Debugger beides nur schwer finden, da die Sachen
> timingabhängig sind.

Das man das in echt so nicht machen würde und wohl einfach einen Zähler 
nimmt, den mit rechnerischen Hilfsmitteln aufstückelt um die passenden 
Werte für die Segmentanzeigen zu bekommen, habe ich schon erkannt, bzw. 
in einer Musterlösung gesehen.

Dennoch möchte ich halt das Wesen der Controller und Programme 
verstehen, und da hilft es nichts einfach fertige Programme abzutippen.

Wie würde man denn Softwareseitig einen Interrupt Taster entprellen? Mit 
meinem bisherigen Verständnis wäre das eigentlich unmöglich. Es sei denn 
das Interrupts der gleichen Quelle verschluckt werden während man sich 
in seiner Service Routine befindet. Dann ja einfach mit delay. Wenn aber 
wirklich jeder Interrupt gezählt wird, dann weiß ich (NOCH) keinen Weg.
was passiert eigentlich wenn ein Interrupt auftritt während das Programm 
grade in einer anderen ISR steckt?

von Peter D. (peda)


Lesenswert?

Jens N. schrieb:
> Wie würde man denn Softwareseitig einen Interrupt Taster entprellen?

Dafür kann der externe Interrupt komplett entfallen.
Vorzugsweise nimmt man den selben Interrupt zum Tasten einlesen, 
entprellen und Zeit zählen. Will man 100ms genau messen, nimmt man einen 
10ms Timerinterrupt. Ein Teiler /10 erzeugt dann die 100ms Zeitbasis.
Genauer zu messen ist bei Handstoppung eh nur in die eigene Tasche 
lügen. Ein Erwachsener hat typisch 300ms Reaktionszeit.

von Jens M. (schuchkleisser)


Lesenswert?

Jens N. schrieb:
> Es sei denn
> das Interrupts der gleichen Quelle verschluckt werden während man sich
> in seiner Service Routine befindet. Dann ja einfach mit delay.

Bloß kein Delay in einer ISR.
Und ein Int in einer ISR wird ignoriert, allerdings kann es sein, das 
das Flag des Int gesetzt wird und nach der ISR sofort die passende 
andere gestartet wird.

"Machen" macht man das mit dem Entprellen normalerweise so, das ein 
Timer-Int einfach nachsieht ob der Knopp gedrückt ist.
Wenn er es ist, wird ein Zähler hochgesetzt, wenn nicht, gelöscht.
Erreicht der Zähler x, so ist der Taster lang genug betätigt, also 
entprellt.
x ist in reeller Zeit z.B. so 50ms.

von Bernd K. (prof7bit)


Lesenswert?

Kaj schrieb:
> Markus schrieb:
>> stell mal die optimierung von -O1 auf -Og, so hats bei mir dann perfekt
>> funktioniert.
> Wenn der Code ohne Optimierung funktioniert, aber mit Optimierung nicht,
> dann ist der Code kaputt.

Es ging doch darum daß er beim Debuggen rosa Elefanten sieht, was ja 
auch nicht weiter verwunderlich ist da geschriebener Code und 
ausführbares Binary nur in Bezug auf die gewünschte Außenwirkung 
übereinstimmen müssen, keinesfalls jedoch über einzelne hingeschriebene 
Schritte die vom Compiler ohnehin nur als beispielhafte und umständliche 
Umschreibung des eigentlich Gewünschten interpretiert werden und von 
denen er beliebig weit abweichen darf solange das Ergebnis gleich 
bleibt.

Daß der Code nicht funktioniert, davon hat er nichts geschrieben.

: Bearbeitet durch User
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.