PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RP6 - Stopwatch



DonGru
15.02.2011, 18:26
Hallo zusammen,

ich hab seit ein paar Tagen einen RP6 und bin gerade dabei mich mit ihm bzw. der Robotertechnik im Allgemeinen anzufreunden.

Heute hab ich mich ein wenig mit der Stopwatch beschäftigt und dabei ein eigenartiges Phänomen festgestellt.
Hier ein einfaches Programm das die Stopwatch1 verwendet um alle 600ms die LEDS paarweise weiterlaufen zu lassen

#include "RP6RobotBaseLib.h" // The RP6 Robot Base Library.

int main(void)
{
initRobotBase();
writeString_P("Do some LED stuff!\n");
startStopwatch1();

uint8_t runningLight = 9;
uint16_t stopVal = 0;

while(true)
{
stopVal = getStopwatch1();
if (stopVal > 600)
{
writeInteger(getStopwatch1(), DEC);
writeChar('\n');
writeInteger(stopVal, DEC);
writeChar('\n');
writeChar('\n');

setLEDs(runningLight);
runningLight <<= 1;
if(runningLight > 36)
runningLight = 9;
setStopwatch1(0);
}

}

return 0;
}


Dazu habe ich mir eine Ausgabe eingebaut um den Wert der Stopwatch zu sehen.
Unerwarteterweise sieht jetzt der Output auf der Konsole so aus:


[READY]
Do some LED stuff!
601
601

601
601

601
601

601
601

601
601

512
767

512
767

512
767

601
601
das heißt der Wert den die Stopwatch liefert stimmt nicht immer mit dem Wert in der Variable (die eigentlich auch den Stopwatch-Wert haben sollte) überein.

Gibt es dafür eine plausible erklärung? :-k

danke schon mal im voraus,
Gruß,
Martin

radbruch
15.02.2011, 21:03
Hallo


#include "RP6RobotBaseLib.h" // The RP6 Robot Base Library.

int main(void)
{
initRobotBase();
writeString_P("Do some LED stuff!\n");
startStopwatch1();

uint8_t runningLight = 9;
uint16_t stopVal = 0;

while(true)
{
cli();
stopVal = getStopwatch1();
sei();
if (stopVal > 600)
{
writeInteger(getStopwatch1(), DEC);
writeChar('\n');
writeInteger(stopVal, DEC);
writeChar('\n');
writeChar('\n');

setLEDs(runningLight);
runningLight <<= 1;
if(runningLight > 36)
runningLight = 9;
setStopwatch1(0);
}

}

return 0;
}


Genau bei stopVal = getStopwatch1(); tritt ein ISR-Aufruf auf. Das Highbyte der StopWatch ist schon erhöht, das Lowbyte noch nicht:

511 ist binär 01 11111111
512 ist binär 10 00000000
767 ist binär 10 11111111

Deshalb ist stopVal größer als 600 und die Stoppuhr aber immer noch kleiner als 600 ;)

Das Stichwort heißt "atomar".

Eigentlich logisch, aber das hat bisher noch keiner bemerkt. Glückwunsch!

Gruß

mic

[Edit]

#include "RP6RobotBaseLib.h" // The RP6 Robot Base Library.

int main(void)
{
initRobotBase();
startStopwatch1();

while(true)
{
if (getStopwatch1() > 600)
{
writeInteger(getStopwatch1(), DEC);
if(getStopwatch1() < 601) writeChar('*');
writeChar('\n');
setStopwatch1(0);
}
}
return 0;
}


#include "RP6RobotBaseLib.h" // The RP6 Robot Base Library.

int main(void)
{
initRobotBase();
startStopwatch1();

while(true)
{
cli();
if (getStopwatch1() > 600)
{
sei();
writeInteger(getStopwatch1(), DEC);
if(getStopwatch1() < 601) writeChar('*');
writeChar('\n');
setStopwatch1(0);
}
else sei();
}
return 0;
}

Schlanker und schneller wäre wohl ein schlichtes

}
sei();

anstelle von

}
else sei();

DonGru
16.02.2011, 14:27
Dankeschön radbruch - für die Hilfe und die Glückwünsche :)
da hätte ich sonst wohl noch länger daran zu grübeln gehabt

mfG,
Martin

DonGru
16.02.2011, 16:28
...dabei drängt sich noch folgende Frage auf: empfiehlt es sich dann generell vor timer-abfragen interrupts zu blockieren?

weil "verloren gehen" sollten sie ja ohnehin nicht wenn ich sie nachher mit sei() wieder freigebe

mfG,
Martin

radbruch
16.02.2011, 17:05
Hallo

Ob man die Interrupts bei StopWatch-Abfragen generell sperren sollte hängt wohl in erster Linie von der geforderten Genauigkeit der Anwendung und dem gewählten Zeitintervall ab. Wenn man die Interrupts nicht sperren will, könnte man den Effekt auch mit einer kleinen Plausibilitätsprüfung vermeiden:


#include "RP6RobotBaseLib.h" // The RP6 Robot Base Library.

int main(void)
{
initRobotBase();
writeString_P("Do some LED stuff!\n");
startStopwatch1();

uint8_t runningLight = 9;
uint16_t stopVal = 0;

while(true)
{
stopVal = getStopwatch1();
if(stopVal != getStopwatch1())
stopVal = getStopwatch1();

if (stopVal > 600)
{
writeInteger(getStopwatch1(), DEC);
writeChar('\n');
writeInteger(stopVal, DEC);
writeChar('\n');
writeChar('\n');

setLEDs(runningLight);
runningLight <<= 1;
if(runningLight > 36)
runningLight = 9;
setStopwatch1(0);
}

}

return 0;
}


Entweder stört der Interrupt die erste Zuweisung oder die If-Abfrage oder er tritt dazwischen auf. In allen Fällen wird dann die zweite Zuweisung nicht mehr gestört sein. Oder der Interrupt stört gar nicht, dann ist schon die erste Zuweisung erfolgreich gewesen.

Oder allgemein:

#include "RP6RobotBaseLib.h" // The RP6 Robot Base Library.

int main(void)
{
initRobotBase();
startStopwatch1();

while(true)
{
if ((getStopwatch1() > 600) && (getStopwatch1() > 600))
{
writeInteger(getStopwatch1(), DEC);
if(getStopwatch1() < 601) writeChar('*');
writeChar('\n');
setStopwatch1(0);
}
}
return 0;
}


Gruß

mic

DonGru
16.02.2011, 17:09
alles klar - danke nochmal für die Hilfe :)

mfG,
Martin