PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : waitms wird von einer Subroutine "eingefangen"



oberallgeier
01.12.2012, 17:02
Hallo Alle,

sorry für den seltsamen Titel. Ich hänge seit Stunden an einem undurchsichtigen Problem und bitte um Hilfe. Irgendwo steckt in einer Subroutine ein Fehler - den ich leider nicht finden kann. Einzig allein der Verzicht auf die (nicht unbedingt nötige) Routine RUNslow1 beseitigt die beschriebene Fehlfunktion - ABER ich würde gerne sehen/wissen/lernen wo ich den Fehler habe.

Stand: Eine waitms-Routine (aus dem C-Code für die RN-Control abgeschrieben und seit Jahren störungsfrei in Betrieb) wird derzeit nach Benutzung in einer bestimmten Subroutine von anderen Routinen nicht mehr benutzbar - zeigt aber in der "Kidnapping"routine weiter saubere Ergebnisse.

Die waitms aus meiner AKTUELLEN Quelle kopiert:

//================================================== ============================ =
//### Programm 1 ms pausieren lassen !! Der Pausenwert ist nur experimentell !
void waitms(uint16_t ms)
{
for(; ms>0; ms--)
{
uint16_t __c = 4000;
__asm__ volatile (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__c)
: "0" (__c)
);
}
}
// ================================================== ============================ =

Auszug aus der Schleife im main:

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Testversion = ...
// - - - - - - - - - - - - - - -
while ( 1 ) //
{ //
TC1TMR_on (); // Vor Servofahrt(en) Servotimer enablen ~tmr~
// RUNi2c_02 (); // Servotest02, Fahre alle Servos mit I2C-Befehlen ~tst~
// RUN_tst2 (); // Servotest, Fahre alle Servos ~tst~
BULid (1); // Servos S2+3 auf mit "1" ~r2n~
waitms ( 5000);
BULid (0); // Servos S2+3 zu mit "0" ~r2n~
waitms ( 5000);
RN2aua90G (); // Servotest, Fahre (alle) Servos 2x auf-ab-90Grad ~r2n~
RUNslow1 () ; // Fahre 10 Servo slow durch Micropositionierung ~r2n~
uart_puts("\r\n\tVor waitms 5000 in main/while(1) \r\n"); //
waitms ( 5000);
uart_puts("\r\n\tEnde main/while(1) \r\n"); //
} //
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
return 0; // Ende int main(void)

Die verdächtige Routine "RUNslow1". Wenn die Routine RUNslow1 im obigen Code im main nicht aufgerufen wird, läuft alles bestens. Es werden in der RUNslow1 keine anderen Interrupts initialisiert - es wird dort nur das benutzt, was in den anderen Routinen auch läuft.

//================================================== ============================ =
// ALLE Servoports werden aus unterschiedlichen Startpositionen heraus zwischen
// gleichen Betriebsgrenzen mit gleichen Incrementen gewobbelt
// ##>> Eine Anpassung an unterschiedliche Betriebsgrenzen und Änderungsicremente
// ist durch leichte Änderungen möglich
// KEINE I²C-Funktionalität
// ================================================== ============================ =
void RUNslow1 (void) // Fahre 10 Servo durch Micropositionierung, damit
// geringe Drehgeschwindigkeit
{ // und unabhängig voneinander
uint8_t nservo = 10; //
uint8_t lowbyte, hibyte; //
uint16_t iword = 0; // NUR zum Auslesen
// Word-Variable für Byte 2 (low) + 3 (high)
int16_t mdmmy; // Dummy-Wert
int16_t maxsrv, minsrv; // allgemeine Extrema der Servo
maxsrv = 600; // 28.Nov.2012, 22:59
minsrv = 300; // dto
// - - - - - - - - - - - - - - -
int16_t s[12]; // Vorzeichenbehaftetes Increment für Rampenwert
for (uint8_t i = 0; i <= 12; i++) { s[i] = 2; } // Startwerte
// - - - - - - - - - - - - - - -
// Ausgabe über die serielle Schnittstelle
uart_puts("\tAktiv ist RUNslow1\r\n");
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// und noch quick´n dirty Servos ansteuern
// Startwerte für Servos ##>> IM TESTbetrieb
// ==========
cli();
Srv_tm [1] = 350;
Srv_tm [2] = 400;
Srv_tm [3] = 450;
Srv_tm [4] = 500;
Srv_tm [5] = 550;
Srv_tm [6] = 600;
Srv_tm [7] = 400;
Srv_tm [8] = 500;
Srv_tm [9] = 600;
Srv_tm [10] = 400;
sei();
// - - - - - - - - - - - - - - -
while ( 1 ) // Endlosschleife für Test
{ //
for (uint8_t n = 1; n <= 10; n++)
{ // Servo-Sollwerte wobbeln
cli(); //
mdmmy = Srv_tm [n];
sei(); //
if (mdmmy > maxsrv) s[n] = -2; //
if (mdmmy < minsrv) s[n] = 2; //
cli(); //
Srv_tm [n] = Srv_tm [n] + s[n]; //
sei(); //
} // Ende for (uint8_t n = 0; n =... = EINE 10er Periode !!
waitms ( 21); // Wartezeit für Servozyklus
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Ist die "Abbruchtaste" gedrückt?
if ( IsBitClr (PIND, 2 )) break;
} // Ende while ( 1 )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uart_puts("\tEnde RUNslow1\r\n");
return; //
} // Ende RUNslow1 (void)
// === Ende RUNslow1 (void)
// ================================================== ============================ =

Die Routine void "BULid (uint8_t auf)" läuft bei den ersten beiden Malen einwandfrei - mit den Parametern 0 und 1, diese Parameter werden (nach der Benutzung der RUNslow1) beim zweiten Durchlauf der BULid gut übergeben, aber die BULid (1) zeigt keine Reaktion, weil die Pause - mit waitms - danach nicht gefahren wird, ebenso nicht die nach dem BULid (0). Dagegen laufen die waitms sowohl in der RUNslow1 als auch in der RN2aua90G.

Sorry für diese Arbeit - aber ich weiß im Moment wirklich nicht weiter.

Danke im Voraus für Hilfe.

robo_tom_24
01.12.2012, 18:01
Hallo
Endet die Endlosschleife im RUNslow1 auch wirklich? Meiner Meinung nach wäre besser gewesen du unterbrichst das nicht mit einer if-Anweisung sondern mit der Schleifenbedinung selbst...

while(!IsBitClr (PIND, 2 ))
{
//Anweisungen
}

Semantisch macht es keinen Unterschied, aber vielleicht wird es vom µC irgendwie falsch interpretiert....

Hast du globale Variablen deklariert? Also, welche die irgendwie im Zusammenhang mit den Warteschlangen stehen?
Ich weiß auch nicht ob es das ist, ist aber das einzige was mir sonst noch einfällt.

markusj
01.12.2012, 19:41
Hast du das ganze Mal simuliert? Solche hässlichen Seiteneffekte sind mit einer Simulation oft noch am einfachsten aufzudecken (oder mit HW-Debugging). Alternativ könntest du waitms (warum verwendest du eigentlich nicht die delay-Makros aus der avr-libc?) mit Debug-Ausgaben versehen um dir einen Zeitstempel + Parameter bei Eintritt und Verlassen der Funktion auszugeben.

mfG
Markus

ahabakukuk
01.12.2012, 20:29
Hallo Oberallgeier

Meiner Meinung nach, kann man einen Code nur in seiner ganzen Form, sprich das ganze C-File beurteilen, alles andere ist gebastelt.

Vielleicht stellst du noch den ganzen Code hoch?

Gruss

MagicWSmoke
01.12.2012, 21:02
Wenn es 10 Servos sind und Srv_tm auf ein Array von 10 dimensioniert ist, dann wird hier:

for (uint8_t n = 1; n <= 10; n++)
{
Srv_tm [n] = Srv_tm [n] + s[n];
}
die Arraygrenze überschritten und eine andere Variable überschrieben.
Gleiches gilt für s[i] in der entsprechenden Initialisierungsschleife.
Das <= muss jeweils zu einem < werden.

oberallgeier
01.12.2012, 23:35
Hallo ihr Vier, danke für die schnelle Hilfe.


Wenn es 10 Servos sind und Srv_tm auf ein Array von 10 dimensioniert ist ...Ja, zehn Servos, aber das Array hat 12 Elemente, siehe weiter unten.

@robot_tom_24: Die Endlosschleife endet wohl (siehe Heilungserfolg), aber Deine Semantik ist eben besser als meine, danke.

@markusj: Simulation - bitte nicht weiterlesen - hatte ich noch nie gemacht. Kann ich nicht. Na ja, im Assembler, im AVRStudio - für tiny13 etc. - hatte ich das ganz gern getan und auch mit Erfolg, aber direkt in Hochsprache hatte ich mich da nie reingearbeitet. Vermutlich nicht zuletzt deswegen, weil ich fast immer Interrupts in meinen Programmen habe und mir die Simulation von Interrupts etwas undurchsichtig vorkommt.

@markusj: das delay-Makro aus der avr-lib kenne ich seit einigen Monaten. Aber ich hatte eben schon viel früher dieses Modulchen bei meinem ersten Kontakt mit der RNControl gesehen und dann immer mitgeschleppt. Die Testausgaben mit Ein- und Austrittsparameter, aber ohne Zeitstempel, hatte ich schon getestet gehabt vor meinem Posting. Leider ohne Erfolg.

@ahabakukuk: Danke, Du hast sicher recht mit dem ganzen Code, der ist schon deutlich umfangreicher. Ich habe an sich keine Bange so etwas online zu stellen - ausser, dass es für die freundlichen Helfer dann abstossend viel Lesezeug sein kann. Es ist eben eine etwas zwiespältige Sache mit etlichen hundert Codezeilen (auch wenn ihr Erfahrenen da sicher ziemlich schnell den richtigen und kurzen Faden durchfindet).

@MagicWSmoke: Huiiii! Also erstmal hatte ich so von oben herab sagen wollen (habs eigentlich deutlich gedacht): kenn ich, da schütze ich mich davor : ich habe ein Feld Srv_tm [12] - weil ich ein fauler Hund bin, nicht den ersten Servo mit Servo 0 sondern lieber mit Servo 1 bezeichne - und hintenraus kostet mich ein unbenutztes Byte nicht die Welt und bringt genau diese benötigte Sicherheit. Konntest Du natürlich leider nicht prüfen, weil ich da sicher war, dass kein Fehler vorliegt und meine Definitionen und Deklarationen weggelassen hatte. ABER - Du hast natürlich so was von Recht - im vorgelegten Code ist das Feld int16_t s[12]; eingetragen und das ist genau um ein Word zu knapp ausgelegt. >> Und das wars dann.

Fazit: es läuft wie geschmiert. Gibt richtig Wochenendlaune ! ! Danke!

Danke Euch für die freundliche Mithilfe. Wieder einen Klacks Semantik dazugelernt und wieder einen Fehler entfernt. Klasse von Euch und schönen Sonntag,

MagicWSmoke
02.12.2012, 00:00
... und das ist genau um ein Word zu knapp ausgelegt. >> Und das wars dann.
Es sind zwei Words, denn wenn Du in der For-Schleife auf <= 10 testest, dann zählst Du genau bis 11. Es wird zuerst die Bedingung geprüft und da sie auch bei 10 noch wahr ist, wird i ein weiteres Mal erhöht und der Schleifenblock ausgeführt. Wenn Du nicht auf auf 12 Elemente erhöhen willst, dann nimm das "=" raus.