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
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.
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
>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.
Ich habe den anderem Thread gelesen. Besser als Wolfram hätte ich es nicht schreiben können. Genau auf den Punkt.
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
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; }
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) .. }
>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.
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; } } //}
> 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.
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
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
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 |
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
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
>#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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.