Hallo ?ternthaler¿

Zitat von
Sternthaler
... Der mit Fragezeichen versehene ... Sternthaler
Tut mir leid, dass ich Dich mitternächtlicher Weise ins Grübeln und zum Durcheinanderrechnen bringe. Die 1220 Hz stammen primär von der PwM für die Motoren. Die anderen Timer sind/werden genutzt, wie es die untenstehenden Übersicht zeigt. Ich nehme die gleiche Aufteilung beim MiniD0 wie beim R2D03.
............Bild hier
Die ursprünglich höhere Frequenz für die Motor-PwM, 4,88 kHz, musste ich nach unten korrigieren, damit mir die davon abgeleiteten ISR für die irDME´s - Deine CIRperei - nicht zu viel CPU-Auslastung in den Interrupts bringt. Außerdem passte die niedrigere Frequenz dann auch noch fürs Auslesen des ADC-Sharp (alle 10 ms ist etwas schnell, aber dadurch bekomme ich die neuesten Ergebnisse des Sharp eben recht flott) und für die Regelung. Der Ablauf sieht in einem simplen Diagramm damit so aus:
Code:
---C---1---2---3---4---5---6---7---8---9---A---B---C---1---2---3---4--> >
| | v | |
| v AR *) Mot34 | v
v AR Mot 12 v AR Mot 12
Auslesen des ADC/Sharp Auslesen des ADC/Sharp
*) AR: Aufruf der Regelungsroutine
Die externen Interrupts der Encoder/Gabellichtschranken werden so initialisiert und ausgelesen (Ausleseroutine sinngemäß für beide) :
Code:
/* ============================================================================== */
/* === Initialisierung fuer EXT_INT0/1 auf Pin 4+5/PD2,3 bei m168 ================
$002 jmp SIG_INTERRUPT0 ; IRQ0 Handler _VECTOR(1)
$004 jmp SIG_INTERRUPT1 ; IRQ1 Handler _VECTOR(2) ================ */
void XTI_0_1_init( void )
{ //Initialisiere beide Interrupts auf rising edge
// d.h. EICRA ISC00,01,10+11 auf 1 (doc,S68)
EICRA |= (1<<ISC11)|(1<<ISC10)|(1<<ISC01)|(1<<ISC00);
EIMSK |= (1<<INT1)|(1<<INT0); // und erlaube diese I´s in EIMSK
// Initialisierung der Zeiten:
Iencdr0 = 0;
Iz_diff0 = 0;
Iz_yseci0 = 0;
Iz_ysecv0 = 0;
}
/* ============================================================================== */
// =================================================================================
// === Nicht unterbrechbare ISR für EXT_INT0 auf Pin 4/PD2/mega168 ===============
/* Routine setzt einen Zähler hoch. Der Zähler wird im main ausgelesen
##>> cli/sei setzen ?? <<## und nach 2 (od. 5) hunderstel Sekunden
auf den Speicher WEG_L/_R vorzeichenrichtig aufaddiert und dann zurückgesetzt.
##>> Beim Richtungswechsel (cli/sei) wird der Zähler ausgelesen und genullt,
damit ist eine saubere Wegmessung möglich.
Der zugehörige Motor auf PD7/PB0 = re,li und PB1 Geschwind./PWM */
ISR(INT0_vect) // hiess mal: ISR(SIG_INTERRUPT0)
{ //
if (nenc0 < 4)
nenc0 = nenc0 + 1;
else
{ // Zähle NUR jeden vierten Interrupt
nenc0 = 1;
Iencdr0 ++; //zähle Counter/encoder0 hoch
Ienc0alt = Iencdr0;
Iz_yseci0 = Izeit_1; //Weise Iz_ysec-ist-0 dem akt. Timerwert zu
Iz_diff0 = Iz_yseci0-Iz_ysecv0; //Neue Zeit-Differenz1 ausrechnen
Iz_ysecv0 = Iz_yseci0; //der aktuelle Zeitwert wird "Alter"
}
}
/* ============================================================================== */
Die Größe Iencdr0 dient für allfällige Odometrieaufgaben, also z.B. um eine Drehung um genau 60° oder so zu erzeugen. Sie wird entweder sinnlos rundum gezählt, oder bei Bedarf auf Null gesetzt und in der entsprechenden Routine abgefragt.
Damit sollte Deine Frage nach dem Gewinnen der Encoderdaten doch beantwortet sein!? Also für mich sieht das nicht aus wie Pollen. Sowas brächte ja blos Heuschnupfen! Jede extINT-ISR holt sich (ja ja, das wär aber doch pollen) den aktuellen Zeitwert Izeit_1 aus dem 50µs-Timer und weist ihm dem Wert Iz_yseci0 --- i wie "ISTzeit" --- zu, errechnet daraus die Zeitdifferenz zum vorherigen Interrupt und merkt sich die aktuelle ISTzeit als Iz_ysecv0=VORheriger Wert. Ok?
Die Initialisierung der PWMs etc hatte ich in diesem Thread bereits vorgestellt und die Regelung zum Dottie hatten wir bereits diskutiert (da gings um die Asymmetrie von iesum12 - ich kann den Link gerade nicht finden). Den Code für MiniDO stelle ich vor (wenns Dir recht ist), sobald die aktuelle Version auch weitgehend stimmt - derzeit sind die Parameter keinesfalls optimal.
Code:
/* ============================================================================== */
/* === Regelungsroutine für Motor 12 ========================================== */
/* Die gemessene Zeitdifferenz Iz_diff0 wird zur Regelung verwendet
*/
void rgl_mo_12(void) // (Wird) Regelung für Motor 12
{
if (stupsi12 <= 5) // Soll überhaupt gefahren werden?
{
OCR0A = 0;
return;
}
tupsi12 = Iz_diff0; // Übernahme Iz-Wert in Regelung
ndrz12 = stupsi12;
if ( tupsi12 > 100 ) { tupsi12 = 100; } // Eingrenzen
idrz12 = 1000 / tupsi12;
ie_mot12 = ndrz12 - idrz12; // Vergleich => Regelabweichung
iesum12 = iesum12 + ie_mot12;
if (iesum12 < -10) { iesum12 = -10;}
if (iesum12 > 500) { iesum12 = 500;}
iy12 = iesum12/2;
iy12 = iy12 + ie_mot12 + ie_mot12 + ie_mot12 + ie_mot12 + ie_mot12;
// Diese Rechenoperation benötigt in float 0,20 bis 0,25 ms!
if ( iy12 < 0 ) { iy12 = 0;}
if ( iy12 > 255 ) { iy12 = 255;}
OCR0A = iy12; // Ansteuerung der PWM direkt statt "setPWMlinks"
return;
}
/* ============================================================================== */
So, damit habe ich hoffentlich für Deine Feiertagsruhe gesorgt - wenigstens soweit, dass Du nicht nach meinem Cäh-Code grübeln musst. Wenn Du mehr Softfutter möchstest - kein Problem.
Übrigens hatte ich die Sprungantwort fürs MiniD0 etwas oberflächlich gemessen (auch nur ein Mal *brrrr*) und eine entdeckte Macke im Kurvenverlauf lasch als Aussreisser interpretiert und unbeachtet gelassen. Tatsächlich war die Messung für die Tonne, an neueren Messungen habe ich schon gearbeitet, aber heute standen auch (wieder) ein paar geradelte Straßenkilometer, gepaart mit Höhenmetern, auf dem Plan.
Lesezeichen