Forum: Mikrocontroller und Digitale Elektronik Mit goto in eine andere Funktion springen.


von XC866 (Gast)


Lesenswert?

Hallo

Der goto Bêfehl funktioniert ja nur in der selben Funktion in der er 
Aufgerufen wurde. Gibt es einen Befehl mit dem ich von einer Funktion in 
die andere Springen kann dort etwas ausführen und dann wieder zurück 
springen.

zum Beispiel:

In UART.C

Interupt RI = 1

goto Empfangen (scanf in Funktion MAIN.C)

dort wird dann der scanf Befehl ausgeführt und dann setzte ich das RI 
wider auf Null und weiter gehts.¨

scanf muss ich in MAIN.C machen, weil wenn ich den Befehl in UART.C 
schreibe gibt es ein Problem mit dem RAM, dass ich nicht lösen kann.

Gruss
Matthias

von Stefan (Gast)


Lesenswert?

Das Problem mit dem RAM ist wahrscheinlich ein Stacküberlauf, weil mehr 
weiter Interrupts als gedacht kommen und Material auf den Stack packen, 
du aber noch am Trödeln mit der Auswertung vom ersten Interrupt bist. 
Bring vielleicht mehr Infos über dein Programm bzw. was du eigentlich 
vor hast.

von XC866 (Gast)


Lesenswert?

Hallo

Ich habe mein Problem schon einmal hier geschrieben. Hier noch einmal 
der Link: Beitrag "Probleme mit scanf"
Ich bin noch nicht so erfahren mit uP`s und muss das Proekt jetzt dann 
abschliessen.

Gruss
Matthias

von Wolfram (Gast)


Lesenswert?

>Der goto Bêfehl funktioniert ja nur in der selben Funktion in der er
>Aufgerufen wurde. Gibt es einen Befehl mit dem ich von einer Funktion in
>die andere Springen kann dort etwas ausführen und dann wieder zurück
>springen.

Du gehst falsch an das Problem heran, die Frage ist nicht: Wie kann ich 
das Problem mit goto Lösen? sondern ich habe folgende Aufgabe, wie kann 
ich die lösen?

Ganz offensichtlich hindert dich der Compiler etwas zu tun. Dafür gibt 
es Gründe, möglicherweise auch hardwaretechnischer Natur.
Ich denke du willst den Aufruf von scanf irgendwo in Main haben und aus 
der Interruptroutine dorthin springe und zurück, richtig?

Du bist aber immer noch in der Interruptroutine! So löst man kein 
Problem sondern verschärft es nur. In einer Interruptroutine für die 
UART scanf oder printf aufzurufen ist einfach strukturell FALSCH.
Gründe:
Es dauert möglicherweise zu lange.
Möglicherweise sind die Funktionen der Library nicht reentrant.
etc.

Ändere deine Struktur. In der Interruptroutine der UART werden Zeichen 
entgegengenommen und in einen Puffer gespeichert. Dies wird mittels 
Variable signalisiert. Wenn das Signal kommt wird im Hauptprogramm der 
Puffer mit scanf oder sscanf ausgewertet.

von Stefan (Gast)


Lesenswert?

Ich habe den anderem Thread gelesen. Besser als Wolfram hätte ich es 
nicht schreiben können. Genau auf den Punkt.

von XC866 (Gast)


Lesenswert?

Hallo

Danke für die Antwort. Also scanf wird dann sowiso in Main.C 
ausgewertet, sehr gut. Dank deiner ausführlichen antwort verstehe ich 
jetzt die Gründe.
Ich werde das einmal versuchen.
Ein kleines Beispiel hast du aber doch nicht auf der Seite?

Gruss uns vielen Dank

Matthias

von XC866 (Gast)


Lesenswert?

Noch eine Frage zu dem ganzen UART zeugs. Wenn ich das ganze mit DaVE 
initialisiere sieht das dann so aus. Wie meintest du das es werden 
zeichen entgegengenommen? Passiert das automatisch und nicht in der if 
RI
abfrage?

void UART_viIsr(void) interrupt UARTINT

{
  //if (TI)
  {
    // USER CODE BEGIN (UART_Isr,2)

    // USER CODE END
   // TI = 0;
  }
  if (RI)
  {
    // USER CODE BEGIN (UART_Isr,3)



   scanf("%f" , &asa);
       RI = 0;
}

von Wolfram (Gast)


Lesenswert?

für AVR wird es dir nicht viel bringen
zur Demonstration des Prinzips:

volatile char Befehl=0; (volatile wichtig für Austausch mit Interrupt)

uart_rx_interrupt (Empfangsinterruptroutine)
{
hole Zeichen aus Empfangsregister
wenn Befehl=0 weiter sonst raus (blockiert solange Befehl in 
Bearbeitung)
speichere es in Kommandopuffer
wenn vollständiger Befehl in Kommandopuffer setze Befehl auf 1
}

mainloop:
...
while{1}
{..
wenn Befehl=1
  puffer auswerten mit sscanf (wenn es denn sein muss)
  abarbeiten
  Befehl=0 (damit neuer Befehl angenommen wird)
..
}

von Wolfram (Gast)


Lesenswert?

>Noch eine Frage zu dem ganzen UART zeugs. Wenn ich das ganze mit DaVE
>initialisiere sieht das dann so aus. Wie meintest du das es werden
>zeichen entgegengenommen? Passiert das automatisch und nicht in der if
>RI abfrage?

Keine Ahnung, ich arbeite nicht mit DaVE noch mit einem XC866.
Der Code den du da ins Forum wirfst hat keinerlei Bezug und könnte als 
Democode für Anfänger über if Verzweigungen dienen. Man sieht weder was 
TI noch was RI ist. Das Schlüsselword interrupt läßt vermuten das das 
eine Interruptroutine sein soll. (da verhält sich jeder Compiler anders)
Dir bleibt also nichts weiter übrig als dich mit Dave und dem 
generierten Code auseinanderzusetzen, das Datenblatt des 
Mikrocontrollers zu lesen und den C-Compiler (Keil?) auch etwas näher 
Dir anzuschauen.

von XC866 (Gast)


Lesenswert?

Hallo

Mein Main.C Programm sieht so aus, falls es dich wunder nimmt:

Gruss
Matthias

//********************************************************************** 
**********************************************
//********************************************************************** 
**********************************************
//*********************************Tariersystem************************* 
**********************************************
//********************************************************************** 
**********************************************
//********************************************************************** 
**********************************************


#include "MAIN.H"
#include <stdio.h>
#include <math.h>


void MAIN_vInit(void)
{

  ///  Initialization of module 'GPIO'
  IO_vInit();

  ///  Initialization of module 'UART (Serial Interface)'
  UART_vInit();

   ///  Initialization of module "ADC"
  ADC_vInit();

  //Timer 2 Initialisieren
  T2_vInit();

  //   Interrupt Priority

  IP            =  0x20;         // load Interrupt Priority Register 
// Priorität von T2
  IPH           =  0x20;         // load Interrupt Priority High 
Register    // höher als von UART
  IP1           =  0x00;         // load Interrupt Priority 1 Register
  IPH1          =  0x00;         // load Interrupt Priority 1 High 
Register

EA          =  1;              //Interupt einschalten
ET2      =  1;
ES      =  1;
}

//****************************************Variablen 
definieren*************************************************************

float winkel;
float winkel_print;
float winkel_alt;
//float result;
float x  ;
float y  ;
float esum ;
float Ausgabe_Stellgroesse ;
//float Kp;
float e;
//float Ki;
float Ta;
float w;

//int i;
unsigned int Reload_Wert;
//unsigned int Frequenz;
unsigned int xx;

//int ww;
int result;
int Kp;
int Ki;
int Frequenz;
int Ua;
char print_zaehler;
char Empfangen;
//Empfangen = 0;
//char print_versuch = 22;
//*****************************************Hauptprogramm**************** 
***************************************************

void main(void)
{

//unsigned int i;
 MAIN_vInit();
    TR2 = 1;
    TI = 1;     // Senden ermöglichen
  // RI = 1;
      // Empfangen ermöglichen
//****************************************AD-Wandler******************** 
**************************************************
    while(1)
  {
  ADC_PAGE = 0x06;
  ADC_CRCR1 |= 0x40;      //  write channel information to be converted
  ADC_CRMR1 |= 0x40;       //  generate load event

  while(ADC_bBusy());      //  warten bis Wandlung komplett

  ADC_PAGE = 0x02;
    {
    result = ADC_RESR2H;  //  Das 8-Bit resultat wird gelesen
  }
  PORT_PAGE = 0x00;
  P3_DATA  = result ;              //  Port3 als Visualisierungsausgang 
benützen
//  winkel_alt=winkel;
//*******************************************Winkelberechnen************ 
**************************************************

  winkel = ((result/51.2 - 2.5)/4);   //    Hier wird aus dem 8 Bit 
Digitalwert des Winkelwertes wieder
  winkel = asin(winkel);          //     der float Wert des richtigen 
Winkels berechnet.
  winkel /= 3.1415926;
  winkel *= 180;
  x = winkel;
  winkel_print = winkel;
  winkel_print =winkel_print +50.0;
//  winkel_neu=winkel;

  print_zaehler++;

  if(print_zaehler >= 5)
  {

  printf (" %.2f ",winkel_print);

  print_zaehler =0;
  }
//  TI=0;
    //printf ("%i",print_versuch);
//********************************************Motoransteuerung********** 
**************************************************

  if (winkel ==0) {
  zaehler = 0;
  }

  if (winkel>w)
  //if ((winkel_neu<(winkel_alt+2)) && ((winkel_neu+2)>w)) 
//Motordrehrichtung festlegen
           {P04 = 0;}                     //Gewicht nach rechts
  else                          //Motordrehrichtung festlegen
           {P04 = 1;}                    //Gewicht nach links


  if ((winkel>(w-4))&& (winkel <(w+4))){      // Halbschrittmodus 
einschalten
    P03 = 1;
    }
  else {
      P03 = 0;}



  if ((winkel >(w-0.4))&&(winkel<(w+0.4))){     //Motor ausschalten wenn 
praktisch der
    P02=0;                     //Sollwinkel erreicht wurde
    }
  else {
    P02=1;
  }

//printf (" %i\t",zaehler);

//*******************************Ab hier wird der PI Regler 
Programmiert***************************************************

  w = 0.0 ;       // Hier können die Werte für den Regler verändert 
werden.
  Kp = 20.0 ;
  Ki = 40.0 ;
  Ta = 0.01;

   e = w - x;                // Vergleich      w = Sollwert        x = 
Istwert
   esum = esum + e;              // Integration I - Anteil
   if ( esum < -400) {esum = -400;}      // Begrenzung I - Anteil
   if (esum > 400) {esum = 400;}
   y = Kp * e + Ki  Ta  esum ;      // Reglergleichung
   if (y < -260) {y = -260;}        // Begrenung Stellgrösse
   if (y > 260) {y = 260;}

 //  printf(" %f\t",y);
   Ausgabe_Stellgroesse = y;        // Übergabe der Stellgrösse

                    //Timer2 einschalten

//********************************Reload Wert 
ermitteln*******************************************************
  //if(y<=26) {                //Ist Ausgabe Wert des Reglers unter 26 
dann
  //Reload_Wert=0;}              //ist der Reload_Wert 0 um die Regelung 
etwas zu verlangsamen

  //if(y>=26) {
   Ausgabe_Stellgroesse= abs(Ausgabe_Stellgroesse);
   xx=1668750 / (Ausgabe_Stellgroesse) ;

   Reload_Wert = (65535 - xx)/(pow(2,8));      //Reload Wert High 
ermitteln, Low wird vernachlässigt.

   //Frequenz= 1668750 / (65535-Reload_Wert);
   //  printf(" %i\n", Frequenz);

    //TI =0;
//************************************Empfangen************************* 
**************************************

   scanf("%c",&Empfangen);
  // RI=0;

 }

  }
 //}



von Stefan (Gast)


Lesenswert?

> Der Code den du da ins Forum wirfst hat keinerlei Bezug

> Man sieht weder was TI noch was RI ist.

> Dir bleibt also nichts weiter übrig als dich mit Dave und dem
> generierten Code auseinanderzusetzen, das Datenblatt des
> Mikrocontrollers zu lesen und den C-Compiler (Keil?) auch etwas näher
> Dir anzuschauen.

q.e.d.

von xc866 (Gast)


Lesenswert?

q.e.d.

??

von Stefan (Gast)


Lesenswert?


von Lars (Gast)


Lesenswert?

Hallo,

RI und TI sind die Bits die anzeigen ob ein Sende oder 
Empfangs-interrupt ausgelöst wurde. RI wird gesetzt wenn ein zeichen 
empfangen wurde. Das Empfangsregister kopierst du in eine variable um 
und meldest dies durch eine andere Variable an main. Danach sofort die 
Interruptroutine verlassen.


Gruß Lars

von xc866 (Gast)


Lesenswert?

Hallo

Das mit RI und TI ist mir schon klar.

Ich habe jetzt so gemacht:

also

if (RI) (hier kommt der interrupt)
{
Empfangen_SBUF = SBUF;
}

So brauchr ich die scanf funktion gar nicht, der eingegangene Wert wird 
dann als Variable für einen PI-Regler weiterverwendet.
Da ich den uP nicht bei mir habe, kann ich das im Moment nicht testen, 
dass sollte ja aber funktioniern.

Gruss und Danke

von Stefan (Gast)


Lesenswert?

Ich habe es mal besser lesbar gemacht:
1
//******************
2
//******************
3
//***Tariersystem***
4
//******************
5
//******************
6
7
#include "MAIN.H"
8
#include <stdio.h>
9
#include <math.h>
10
11
void MAIN_vInit(void)
12
{
13
14
  ///  Initialization of module 'GPIO'
15
  IO_vInit();
16
17
  ///  Initialization of module 'UART (Serial Interface)'
18
  UART_vInit();
19
20
  ///  Initialization of module "ADC"
21
  ADC_vInit();
22
23
  //Timer 2 Initialisieren
24
  T2_vInit();
25
26
  //   Interrupt Priority
27
  IP            =  0x20;  // load Interrupt Priority Register
28
                          // Priorität von T2
29
  IPH           =  0x20;  // load Interrupt Priority High Register    
30
                          // höher als von UART
31
  IP1           =  0x00;  // load Interrupt Priority 1 Register
32
  IPH1          =  0x00;  // load Interrupt Priority 1 High Register
33
34
  EA  = 1;                //Interupt einschalten
35
  ET2 = 1;
36
  ES  = 1;
37
}
38
39
//**************************
40
//***Variablen definieren***
41
//**************************
42
43
float winkel;
44
float winkel_print;
45
float winkel_alt;
46
//float result;
47
float x  ;
48
float y  ;
49
float esum ;
50
float Ausgabe_Stellgroesse ;
51
//float Kp;
52
float e;
53
//float Ki;
54
float Ta;
55
float w;
56
57
//int i;
58
unsigned int Reload_Wert;
59
//unsigned int Frequenz;
60
unsigned int xx;
61
62
//int ww;
63
int result;
64
int Kp;
65
int Ki;
66
int Frequenz;
67
int Ua;
68
char print_zaehler;
69
char Empfangen;
70
//Empfangen = 0;
71
//char print_versuch = 22;
72
73
//*******************
74
//***Hauptprogramm***
75
//*******************
76
77
void main(void)
78
{
79
    // unsigned int i;
80
81
    MAIN_vInit();
82
    TR2 = 1;
83
84
    // Senden ermöglichen
85
    TI = 1;
86
87
    // Empfangen ermöglichen
88
    // RI = 1; ### Eben nicht. Diese Stelle ist auskommentiert... ###
89
90
    //***AD-Wandler***
91
    while(1)
92
    {
93
        ADC_PAGE = 0x06;
94
        ADC_CRCR1 |= 0x40;  //  write channel information to be converted
95
        ADC_CRMR1 |= 0x40;  //  generate load event
96
        while(ADC_bBusy())
97
            ;               //  warten bis Wandlung komplett
98
        ADC_PAGE = 0x02;
99
        {
100
            result = ADC_RESR2H;  //  Das 8-Bit resultat wird gelesen
101
        }
102
        PORT_PAGE = 0x00;
103
        P3_DATA = result;   //  Port3 als Visualisierungsausgang benützen
104
105
        //***Winkelberechnen***
106
        // winkel_alt = winkel;
107
        winkel = ((result/51.2 - 2.5)/4); // Hier wird aus dem 8 Bit Digitalwert des Winkelwertes wieder
108
        winkel = asin(winkel);            // der float Wert des richtigen Winkels berechnet.
109
        winkel /= 3.1415926;
110
        winkel *= 180;
111
        x = winkel;
112
        winkel_print = winkel;
113
        winkel_print = winkel_print + 50.0;
114
        // winkel_neu = winkel;
115
116
        print_zaehler++;
117
        if(print_zaehler >= 5)
118
        {
119
            printf(" %.2f ",winkel_print);
120
            print_zaehler = 0;
121
        }
122
123
        //  TI = 0;
124
        // printf("%i",print_versuch);
125
126
        //***Motoransteuerung***
127
        if (winkel == 0) 
128
        {
129
            zaehler = 0;
130
        }
131
132
        // Motordrehrichtung festlegen
133
        if (winkel > w)
134
        // if ((winkel_neu<(winkel_alt+2)) && ((winkel_neu+2)>w))
135
        {
136
            P04 = 0; // Gewicht nach rechts
137
        } 
138
        else                          
139
        { 
140
            P04 = 1; // Gewicht nach links
141
        }
142
143
144
        if ((winkel>(w-4))&& (winkel <(w+4)))
145
        {
146
            // Halbschrittmodus einschalten
147
            P03 = 1;
148
        }
149
        else 
150
        {
151
            P03 = 0;
152
        }
153
154
        if ((winkel >(w-0.4))&&(winkel<(w+0.4)))
155
        {     
156
            // Motor ausschalten wenn praktisch 
157
            // der Sollwinkel erreicht wurde
158
            P02 = 0; 
159
        }
160
        else 
161
        {
162
            P02 = 1;
163
        }
164
165
        // printf(" %i\t",zaehler);
166
167
        //***Ab hier wird der PI Regler Programmiert***
168
169
        w = 0.0;   // Hier können die Werte für den Regler verändert werden.
170
        Kp = 20.0;
171
        Ki = 40.0;
172
        Ta = 0.01;
173
174
        e = w - x; // Vergleich      w = Sollwert        x = Istwert
175
        esum = esum + e;             // Integration I - Anteil
176
        if ( esum < -400) {esum = -400;}  // Begrenzung I - Anteil
177
        if (esum > 400) {esum = 400;}
178
        y = Kp * e + Ki * Ta * esum ;     // Reglergleichung
179
        if (y < -260) {y = -260;}         // Begrenung Stellgrösse
180
        if (y > 260) {y = 260;}
181
182
        // printf(" %f\t",y);
183
        Ausgabe_Stellgroesse = y;         // Übergabe der Stellgrösse
184
185
        //***Timer2 einschalten***
186
187
        //***Reload Wert ermitteln***
188
#if 0
189
        // ### Auskommentiert wegen,...
190
        if(y <= 26) 
191
        { 
192
            // Ist Ausgabe Wert des Reglers unter 26 dann ist der 
193
            // Reload_Wert 0 um die Regelung etwas zu verlangsamen
194
            Reload_Wert=0;
195
        }              
196
#endif 
197
198
        // if(y >= 26) 
199
        {
200
            Ausgabe_Stellgroesse = abs(Ausgabe_Stellgroesse);
201
            xx = 1668750 / (Ausgabe_Stellgroesse);
202
203
            // Reload Wert High ermitteln, Low wird vernachlässigt.
204
            Reload_Wert = (65535 - xx)/(pow(2,8)); 
205
206
            // Frequenz = 1668750 / (65535-Reload_Wert);
207
            // printf(" %i\n", Frequenz);
208
209
            //***Empfangen***
210
            // TI = 0;
211
            scanf("%c",&Empfangen);
212
            // RI = 0;
213
           
214
            /*
215
               scanf wartet bis ein Zeichen empfangen wurde. 
216
               Das Zeichen steht anschliessend in der Variable Empfangen
217
               und könnte als Wert -127 bis 127 interpretiert werden. 
218
               Was soll damit gemacht werden? Im Restprogramm ist kein
219
               Bezug darauf vorhanden.
220
            */
221
        }
222
   } // end-while-forever
223
} // end-main

> RI und TI sind die Bits die anzeigen ob ein Sende oder
> Empfangs-interrupt ausgelöst wurde. RI wird gesetzt wenn ein zeichen
> empfangen wurde.

Dem widerspricht die Verwendung in obiger main(). Wenn RI und TI derart 
unter UART Kontrolle wäre, hätten Zuweisungszeilen und die 
entsprechenden mit RI in main() nichts zu suchen:
1
    // Senden ermöglichen
2
    TI = 1;

Maximal wären dann Abfrageloops zur Umgehung der Interruptroutine 
denkbar (aber unschöner Stil). Vorausgesetzt in der Interruptroutine 
selbst oder bei deren Verlassen wird RI nicht gelöscht:
1
    while (RI == 0)          // Warten bis Zeichen im Interrupt anliegt
2
        ;
3
    scanf("%c",&Empfangen);  // dann mit Nicht-Interrupt-Funktion klauen

  

von xc866 (Gast)


Lesenswert?

Danke für deine Bemühungen. Habe die unschöne Variante gewählt. 
Simulationsmässig funktioniert es, mit der Hardware kann ich es erst am 
Mittwoch testen.

Gruss
Matthias

von Lars (Gast)


Lesenswert?

Hallo,

@Stefan:  TI und RI zu setzen macht keinen Sinn. TI und RI sind dazu da 
um zu unterscheiden ob ein Sende oder Empfangsinterrupt war. RI und/oder 
TI in der Inerruptroutine auf 0 setzen.

Eine UART Inerruptroutine (KEIL 8051) könnte so aussehen:

void iSer0 (void) interrupt 4 using 1
{
if (RI==1)
   {
   // user code  z.B. Empfangen_SBUF = SBUF;
   RI=0;
   }

if (TI==1)
   {
   // user code  z.B.  SBUF=NextChar;
   TI=0;
   }
}

In dem von XC866 angegebenen C Code ist bisher keine Interruptroutine zu 
enthalten:

Gruß Lars

von Wolfram (Gast)


Lesenswert?

>#include "MAIN.H"        <<
>#include <stdio.h>
>#include <math.h>

C ist Groß/Kleinschreibung sensitiv, wenn du sowas machst, dann sollte 
MAIN.H
im Dateisystem auch wirklich so geschrieben sein, sonst kommt ein 
Compiler mal ganz schnell ins stolpern.


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.