www.mikrocontroller.net

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


Autor: XC866 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: XC866 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan (Gast)
Datum:

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

Autor: XC866 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: XC866 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;
}

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)
..
}

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: XC866 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;

 }

  }
 //}



Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: xc866 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
q.e.d.

??

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: xc866 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe es mal besser lesbar gemacht:
//******************
//******************
//***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;

    // Senden ermöglichen
    TI = 1;

    // Empfangen ermöglichen
    // RI = 1; ### Eben nicht. Diese Stelle ist auskommentiert... ###

    //***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

        //***Winkelberechnen***
        // winkel_alt = winkel;
        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;
        }

        // Motordrehrichtung festlegen
        if (winkel > w)
        // if ((winkel_neu<(winkel_alt+2)) && ((winkel_neu+2)>w))
        {
            P04 = 0; // Gewicht nach rechts
        } 
        else                          
        { 
            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 Sollwinkel erreicht wurde
            P02 = 0; 
        }
        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 0
        // ### Auskommentiert wegen,...
        if(y <= 26) 
        { 
            // Ist Ausgabe Wert des Reglers unter 26 dann ist der 
            // Reload_Wert 0 um die Regelung etwas zu verlangsamen
            Reload_Wert=0;
        }              
#endif 

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

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

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

            //***Empfangen***
            // TI = 0;
            scanf("%c",&Empfangen);
            // RI = 0;
           
            /*
               scanf wartet bis ein Zeichen empfangen wurde. 
               Das Zeichen steht anschliessend in der Variable Empfangen
               und könnte als Wert -127 bis 127 interpretiert werden. 
               Was soll damit gemacht werden? Im Restprogramm ist kein
               Bezug darauf vorhanden.
            */
        }
   } // end-while-forever
} // 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:
    // Senden ermöglichen
    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:
    while (RI == 0)          // Warten bis Zeichen im Interrupt anliegt
        ;
    scanf("%c",&Empfangen);  // dann mit Nicht-Interrupt-Funktion klauen

  

Autor: xc866 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lars (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.


Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.