Hallo Frühaufsteher,
Ich hoffe, dass es Du mir nicht allzu krumm nimmst, wenn ich bei manchen Fragen oder Aussagen recht pingelig formuliere/nachhake. Ich hatte schon angenommen, dass Du es so meinst . . . aber solche Annahmen sind manchmal die Grundlage von unnötigen Missverständnissen.Zitat:
Zitat von juhecomp, Heute um 6:53,
Wir setzen voraus, dass Du einen m32 hast. Und dann gehen wir mal ein bisschen Technologie klauen. Öffne bitte diesen Link in einer extra Registerkarte/Fenster und geh auf S31 - Schaltplan. Den Schaltplan gibt es auch hier aus dem RNWissen zur RNControl. Wenn Du Zeit hast, kannst Du vielleicht beide Beschreibungen lesen - und vielleicht Einiges zum Schaltungsaufbau und zum Betrieb des m32 lernen. !!Aber das ist nur eine von mehreren Möglichkeiten!!Zitat:
Zitat von juhecomp
In der Mitte-unten-rechts siehst Du den Motorcontroller = Motortreiber L293D, wenn Du den Schaltplan der RNControl auf Querformat stellst. Da siehst Du, dass die Eingänge EN1 und EN2 des Motortreibers, also seine Pinne 1 und 9, an den Pinnen OC1A und OC1B des Controllers hängen. Nur diese beiden müssen beim L293D durch ne PwM versorgt werden, um die Motordrehzahl zu steuern. Die restlichen Steuerleitungen werden (nur) geschaltet - das ergibt dann Vor- oder Rückwärtsfahrt oder Stop, siehe z.B. im Code unten. Andere Motortreiber machen das ähnlich - aber ich kenne nicht allzuviele Varianten aus eigener Erfahrung. Eines sollte Dir jetzt klar sein: Motoren sind häufig mit einer 8bittigen PwM genug fein dosiert bedient. Du benutzt den Timer1 (wieder meine Annahme des m32), der ein 16Bitter ist - also wären das theoretisch 65 535 Geschwindigkeitsstufen; praktisch läuft der Motor irgendwo im unteren Drittel an und im obersten Viertel tut sich nicht mehr viel. Dieser Timer ist vielleicht für andere Aufgaben (Zeitmessung u.ä.) besser eingesetzt.
Du hast Deine angedachte Pinbelegung also richtig ausgelegt.
Das Folgende ist nicht zum Lesen gedacht. Hier gibts meine Motoransteuerung und -regelung mit einem mega168 und einem L293D. Für die Motorpwm wird der 8bittige Timer0 des m168 verwendet.
Ausserdem könntest Du Dir mal eine (funktionierende) Motorregelung ansehen. Aber - wie gesagt - das ist eher für Mussestunden geeignet - *gggg*: nicht zum Lesen *gggg*.Code:/* >> Sicherung 15sep08 1740 ...C1..\m168D_10\m168D_mot_10x80.c
===================================================================================
Target MCU : M168
Target Hardware : m168D
Target cpu-frequ. : In der Quelle wählbar
===================================================================================
Enthaltene Routinen: Alle Motorroutinen
void XTI_0_1_init( void )
ISR(INT0_vect) // hiess mal: ISR(SIG_INTERRUPT0)
ISR(INT1_vect) // hiess mal: ISR(SIG_INTERRUPT1)
void rgl_mo_12(void) // Regelung für Motor 12 (neuer Name: 09jul08)
void rgl_mo_34(void) // Regelung für Motor 34
void TC0PWM_init(void) //Init Timer/Counter0 für Erzeugung des PWM-Signals
void setPWMrechts(uint8_t speed) //Geschwindigkeit rechter Motor
void setPWMlinks(uint8_t speed) //Geschwindigkeit linker Motor
void Mrechtsvor(void) //Motor dreht im mathematisch positiven Drehsinn
void Mrechtszur(void) //Motor 1,2 dreht im Uhrzeigersinn
void Mrechtsstop(void) //Motor aus
void Mlinksvor(void) //Motor dreht im mathematisch positiven Drehsinn
void Mlinkszur(void) //Motor 3,4 dreht im Uhrzeigersinn
void Mlinksstop(void) //Motor aus
===================================================================================
*** Versionsgeschichte:
====================
x80 15sep08 1740 Version wie x77 - für zusätzliches Modul ~kal~
x70 22jul08 1620 Nach erfolgreicher Regelung versuch eines "echten" Laufes
mit Ausweichmanövern etc
....
x342 26jun08 08ff Interrupt für Motoren in TC0PWM_init/~mo1~ auf 1200 Hz stellen
===================================================================================
*** Aufgabenstellung : Software für R2_D03
in einer ersten Ausbaustufe angelehnt an: siehe Original
Original: ...C1..\m168D_10\mm168D_mo1_10x342.h 26jun08 08ff
================================================================================ */
/* ============================================================================== */
/* === 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 46/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)
{ // Zuerst mal sehen, ob das ein Spike ist
uint8_t itest = 16;
Iztmp_0 = Izeit_1 - Iz_yseci0; //Wie lange seit der letzten Flanke
if (Iztmp_0 < itest) //wenn zu kurz (spike!?), dann
{
return; // Routine verlassen
}
else
{ // ansonsten
Iencdr0 ++; //zähle Counter/encoder0 hoch
Ienc0alt = Iencdr0;
Iz_yseci0 = Izeit_1; //Weise Iz_ysec1 dem akt. Timerwert zu
Iz_diff0 = Iz_yseci0-Iz_ysecv0; //Neue Zeit-Differenz1 ausrechnen
Iz_ysecv0 = Iz_yseci0; //der aktuelle Zeitwert wird "Alter"
}
// Bessere Spikeerkennung - dynamisch
itest = Iztmp_0 - 8;
}
/* ============================================================================== */
/* ============================================================================== */
/* === Nicht unterbrechbare ISR für EXT_INT1 auf Pin 17/PD3/mega16(32) ======== */
/* Routine setzt einfach einen Zähler hoch.
Sonst wie ISR für EXT_INT0 für Motor li,re und PWM/Geschw. */
ISR(INT1_vect) // hiess mal: ISR(SIG_INTERRUPT1)
{ // Zuerst mal sehen, ob das ein Spike ist
uint8_t itest = 10;
Iztmp_1 = Izeit_1 - Iz_yseci1; //Wie lange seit der letzten Flanke
if (Iztmp_1 < itest) //wenn zu kurz (spike!?), dann
{
return; // Routine verlassen
}
else
{ // ansonsten
Iencdr1 ++; //zähle Counter/encoder1 hoch
Iz_yseci1 = Izeit_1; //Weise Iz_ysec1 dem akt. Timerwert zu
Iz_diff1 = Iz_yseci1-Iz_ysecv1; //Neue Zeit-Differenz1 ausrechnen
Iz_ysecv1 = Iz_yseci1; //der aktuelle Zeitwert wird "Alter"
}
// Bessere Spikeerkennung - dynamisch
itest = Iztmp_1 - 8;
}
/* ============================================================================== */
/* ============================================================================== */
/* == Initialisierung der PWM zur Motoransteuerung ============================ */
void TC0PWM_init(void) //Init Timer/Counter0 für Erzeugung des PWM-Signals
{
TCCR0A |= (1<<COM0A1)|(1<<COM0B1); //Clear/set OC0A/OC0B on Compare Match,
// doc S102 , OC0A/OC0B ist Port PD6/D5
TCCR0A |= (1<<WGM01)|(1<<WGM00); // Fast PWM, TOP=0xFF=dez255, doc S104
// das ergibt aus 20 MHz mit Prescaler 1/64 1220 Hz
TCCR0B |= (1<<CS01)|(1<<CS00); // Prescaler ist clk/64 doc S106
TIMSK0 &= ~(1<<OCIE0A)|(1<<OCIE0B); // Tmr/Cntr0 Oput CompB Match intrrpt dsabld
TIMSK0 &= ~(1<<TOIE0); // Tmr/Cntr0 Overflow interrupt disabled
OCR0A = 0; // PWM auf Null setzen
OCR0B = 0; // PWM auf Null setzen
Iz_diff0 = 0;
iesum12 = 0;
ie_mot12 = 0;
}
/* ============================================================================== */
void setPWMrechts(uint8_t speed) //Geschwindigkeit rechter Motor
{OCR0A = speed;} // PWM auf PD6
/* ============================================================================== */
void setPWMlinks(uint8_t speed) //Geschwindigkeit linker Motor
{OCR0B = speed;} // PWM auf PD5
/* ============================================================================== */
/* ============================================================================== */
/* === 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;
}
/* ============================================================================== */
/* ============================================================================== */
/* === Regelungsroutine für Motor 34 ========================================== */
/* Die gemessene Zeitdifferenz Iz_diff1 wird zur Regelung verwendet
*/
void rgl_mo_34(void) // (Wird) Regelung für Motor 34
{
if (stupsi34 <= 5) // Soll überhaupt gefahren werden?
{
OCR0B = 0;
return;
}
tupsi34 = Iz_diff1; // Übernahme Iz-Wert in Regelung
ndrz34 = stupsi34;
if ( tupsi34 > 100 ) { tupsi34 = 100; } // Eingrenzen
idrz34 = 1000 / tupsi34;
ie_mot34 = ndrz34 - idrz34; // Vergleich => Regelabweichung
iesum34 = iesum34 + ie_mot34;
if (iesum34 < -10) { iesum34 = -10;}
if (iesum34 > 500) { iesum34 = 500;}
iy34 = iesum34/2;
iy34 = iy34 + ie_mot34 + ie_mot34 + ie_mot34 + ie_mot34 + ie_mot34;
if ( iy34 < 0 ) { iy34 = 0;}
if ( iy34 > 255 ) { iy34 = 255;}
OCR0B = iy34; // Ansteuerung der PWM direkt statt "setPWMxxx"
return;
}
/* ============================================================================== */
/* ============================================================================== */
/* Motoransteuerung mit dem L293D, hier werden die Drehrichtungen gesetzt */
/* Vorgesehene/belegte Anschlüsse am ATMega168 für R2D03:
==========
hier, unter anderem, für die Motoransteuerung (Stand 22mai08 11ff) :
(E7) _|-- 3,4 Guz, PD4___6 23___PC0, SFH 5110, IN irDME 1-2 } ´168 n
VCC 7 22 GND
GND 8 21 AREF
XTAL1 PB6___9 20___VCC
XTAL2 PB7 10 19 PB5, Startblink (LED0), 3sec v Tmr0, Mehrzweck
(E6) PWM 1,2 uz+Guz,PD5 11 18 PB4 _|-- 3,4 uz (E4) (hier oder PB3)
(E5) PWM 3,4 uz+Guz,PD6___2 17___PB3, Reserve 2
(E8) _|-- 1,2 uz,PD7 13 16 PB2, Reserve 1
(E9) _|-- 1,2 Guz,PB0 14 15 PB1 SFH 415, OUT (irDME) */
// -----------------------
// Drehrichtungsbefehle für Motor 1,2 = "rechter" Motor
void Mrechtszur(void) //Motor 1,2 dreht im Uhrzeigersinn
{PORTB |= (1<<PB4); PORTD &= ~(1<<PD4);}
// r r r r r r r rechts rechter Motor r r r r r r
void Mrechtsvor(void) //Motor dreht im mathematischer Drehsinn
{PORTB &= ~(1<<PB4); PORTD |= (1<<PD4);}
// r r r r r r r rechts rechter Motor r r r r r r
void Mrechtsstop(void) //Motor aus
{ PORTB &= ~(1<<PB4); PORTD &= ~(1<<PD4);}
// -----------------------
// Drehrichtungsbefehle für Motor 3,4 = "linker" Motor
void Mlinkszur(void) //Motor 3,4 dreht im Uhrzeigersinn
{PORTB |= (1<<PB0); PORTD &= ~(1<<PD7);}
// l l l l l l l links linker Motor l l l l l l l
void Mlinksvor(void) //Motor dreht im mathematischer Drehsinn
{PORTB &= ~(1<<PB0); PORTD |= (1<<PD7);}
// l l l l l l l links linker Motor l l l l l l l
void Mlinksstop(void) //Motor aus
{ PORTB &= ~(1<<PB0); PORTD &= ~(1<<PD7);}
/* ============================================================================== */
/* ============================================================================== */
/* ===== ENDE Subroutinen ================================================== */
/* ============================================================================== */