PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM Signal für Motor in C



semicolon
12.10.2005, 15:45
Hallo zusammen

Ich habe bereits ein paar Beiträge über PWM Signale durchsucht, bin aber leider noch nicht richtig fündig geworden. Lieg wahrscheinlich daran, dass ich noch nicht lange mit uC zu tun habe. Nun zur Frage:

Ich währe froh, wenn mir jemand etwas helfen könnte, damit ich bein Motor DC mittels PWM ansteuern kann. Ein kleines Beispiel eines Codes wäre echt nett.

Vielen dank!

Kjion
12.10.2005, 19:09
Ist eigentlich ganz einfach, wenn man mal die Sektion im Datenblatt dazu in Ruhe durchgelesen hat :-)

ein kleines Beispiel dazu:
http://www.kreatives-chaos.com/index.php?seite=c_t1_pwm

Über OCR1AL und OCR1BL kann dann das PWM Signal gesteuert werden...

MfG Kjion

semicolon
12.10.2005, 20:47
Was ich noch nicht ganz begriffen habe ist folgendes mit diesem PWM Signal.
Ich habe ein Eingang (z.B PB1) eines Atmel atmega32 der mir den Befehl für das Laufen des Motors gibt. Heisst das jeztzt, das am Port OC1B oder OC1A das PWM Signal an den Motor gesendet wird, solange am Eingang PB1 eine logische 1 ist? Das heisst auch, dass je nach dem wie das PWM Siganl eingestellt ist, eine kontinuierliche Geschwindigkeit erfolgt?

Vielen Dank für eure Hilfe!!!

Atreyu
15.10.2005, 22:17
ich hab einen Atmega8, dürfte aber aufs gleiche rauskommen!
also, ich hab das mit mit der PWM so verstanden, dass von PB1 bzw. PB2 strom abgeht.
wenn du mal in den schaltplan guckst, siehst du, dass die motorbrücken, über AND-gatter mit strom versorgt werden, d.h. es geht nur strom durch, wenn an beiden eingängen strom anliegt. OCR1A und B schalten wechseln jetzt immer ganz schnell zwischen an und aus. je länger sie in einer periode strom "senden", desto schneller läuft der motor. und ich denke, dass was du mit kontinuierlich mienst, ist dann, wenn OCR1A und/oder B dauerhaft strom "senden".
hab ich deine frage beantwortet?
p.s. welchen roboter betreibst du denn damit? eigenproduktion?

luma
20.10.2005, 14:02
Hio. Also ausgehend von diesem Thread hier: https://www.roboternetz.de/phpBB2/viewtopic.php?p=123683#123683
hab ich genau das Codebeispiel versucht zu benutzen. Auf meinem RN-Controll läuft das aber nicht, d.h. ich seh nichts auf meinem Voltmeter und der Motor dreht sich auch nicht. Nur wenn ich das Testhexfile von der CD zu RN-Controll verwende dreht sich der Motor und ich seh auch ne Spannung. Warum?

Gruß
Lutz

Toastbrot
09.01.2006, 16:34
Hallo,
ich benutze auch die RN-Control, allerdings mit einem externen L298 als Motortreiber.

Ich verwende folgenden Code, welcher allerdings nur einen Motor ansteuert:


int main(void)
{
//---------------------------------------------------------------------------------------------------------#
// I/O Konfiguration

// Port A (ADC)
// US Front Batterie RN-Taster
DDRA = (0 << DDA0) | (0 << DDA6) | (0 << DDA7);

// Port B
PORTB = 0x00;


// Port C
PORTC = 0x00;
// Motor1.1 Motor1.2 Motor2.1 Motor2.2
DDRC = (1 << DDC4) | (1 << DDC5) | (1 << DDC6) | (1 << DDC7);


// Port D
PORTD &= (1<<PD2) | (1<<PD3) | (1<<PD4) | ~(1<<PD5) | ~(1<<PD6) | ~(1<<PD7); //Default-Belegung
// RXD RS232 TXD RS232 INT0 INT1 Test PWM M1 PWM M2 Sound
DDRD = (0 << DDD0) | (1 << DDD1) | (0 << DDD2) | (0 << DDD3) | (0 << DDD4) | (1 << DDD5) | (1 << DDD6) | (1 << DDD7);


//---------------------------------------------------------------------------------------------------------#

PORTC |= (1<<PC4) | (1<<PC6); //Fahrtrichtung


TCCR1A = 0x00; //Timer alles auf 0
TCCR1B = 0x00;

TCCR1A |= (1<<WGM10) | (1<<COM1A1) | (1<<COM1B1); //Timer konfigurieren
TCCR1B |= (1<<CS10) | (1<<CS12);

OCR1BL = 255;
OCR1AL = 255;

//---------------------------------------------------------------------------------------------------------#
return(1);
}

Eigentlich sollte damit doch beide PWM Ausgänge voll durchschalten, oder? Wo liegt der Fehler?
Wenn ich die PWM-Pins am Motortreiber tausche, dreht entsprechend der andere Motor, das scheint also zu funktionieren. Danke für eure Unterstützung!

Andun
09.01.2006, 21:34
Ich hab jetzt nciht sooo die Ahnung und weiß auhc gar nicht ob das stimmt was ich sage, aber hier ein Tipp:

Wo sind denn die beiden PWM Ausgänge am AVR? An welchen Pins? Hast du die beide auch als Ausgänge deklariert? (Wobei ich auch nur vermute, dass man das tun muss)

Ich bin grade zu faul, raus zu suchen, welchen AVR die RN-Control verwendet und dann zu schauen, wo da die OC1a und B sind. Man verzeihe mir, da ich denke, dass dies eh nciht das Problem ist.

Andun

Arexx-Henk
09.01.2006, 22:19
Wo sind denn die beiden PWM Ausgänge am AVR?

Bei ATmega8 28-pins DIL package sind dass:
OC1A = pin 15 = PB1
OC1B = pin 16 = PB2

Mann kann in Register TCCR1A mittels die bits (COM1A1 und COM1A0) und (COM1B1 und COM1B0) eingeben wie die pin15 oder pin16 sich verhalten sollen.
Zum Beispiel: sind alle die bits NUL dan kan mann pin 15 und 16 als normaler PB1 und PB2 port benutzen. Bei andere bit kombination reagieren pin 15 und 16 direct auf timer1. (sehe datenblat .pdf) Aber mann muss die beide pinnen daneben doch auch noch als ausgang programmieren sonst geschied nix auf die beide pins.


gruss,

Henk

Toastbrot
10.01.2006, 07:41
Erneuter Blick in das Datenblatt des ATmega32 ergab folgendes:


The COM1A1:0 and COM1B1:0 control the Output Compare pins (OC1A and OC1B
respectively) behavior. If one or both of the COM1A1:0 bits are written to one, the OC1A
output overrides the normal port functionality of the I/O pin it is connected to. If one or
both of the COM1B1:0 bit are written to one, the OC1B output overrides the normal port
functionality of the I/O pin it is connected to. However, note that the Data Direction Register
(DDR) bit corresponding to the OC1A or OC1B pin must be set in order to enable
the output driver.
When the OC1A or OC1B is connected to the pin, the function of the COM1x1:0 bits is
dependent of the WGM13:0 bits setting. Table 44 shows the COM1x1:0 bit functionality
when the WGM13:0 bits are set to a normal or a CTC mode (non-PWM).

Um beide PWM Ausgänge zu nutzen müssen COM1A1,COM1A0,COM1B1,COM1B0 auf 1 gesetzt werden, werde das sobald ich zu Hause bin mal probieren!

Toastbrot
10.01.2006, 19:17
Wie bereits geschrieben, habe ich meinen Code wie folgt umgeändert:


//PWM
TCCR1A = 0x00;
TCCR1B = 0x00;

TCCR1A |= (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1A0); //Timer konfigurieren
TCCR1B |= (1<<CS10) | (1<<CS12);

PORTC |= (1<<PC4) | (1<<PC6); //Fahrtrichtung

OCR1A = 0;
OCR1B = 255;


Laut diesem Code sollte ja eigentlich ein Motor auf 100% und der andere auf 0% laufen. Es laufen aber beide Motoren gleich schnell.
Hat da jemand eine Idee?

Arexx-Henk
11.01.2006, 22:15
Da steht zweimal 'COM1A0' und keine 'COM1B0'

gruss

Henk

Arexx-Henk
11.01.2006, 22:37
//PWM
TCCR1A = 0x00;
TCCR1B = 0x00;

//WGM10 = mode 1 = PWM Phase correct TOP=0x00FF
//COM1A1 und COM1A0 = 11 = (Table 38 pdf)
// => OC1A high on upcounting compare match, low on downcouting compare match
//COM1B1 und COM1B0 = 11 = (Table 38 pdf)
// => OC1B high on upcounting compare match, low on downcouting compare match
TCCR1A |= (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0); //Timer konfigurieren

//prescaler /1024
TCCR1B = (1<<CS10) | (1<<CS12);

//======>>> port als Ausgang schalten <<<======
//pin 19 (OC1A) und pin 18 (OC1B) als ausgang schalten (ATmega32)
DDRD |=(1<<PD5) | (1<<PD4);

//???
//PORTC |= (1<<PC4) | (1<<PC6); //Fahrtrichtung

//geschwindigkeit 0
OCR1A = 0;
//geschwindigkeit max
OCR1B = 255;



Meine bemerkungen (keine garantie es sei fehlerfrei....)

Beim ATmega32 sind es die ports PD5 (OC1A) und PD4 (OC1B) die das PWM signal liefern.
Die sollten als ausgang definiert sein mit 'DDRC'.
In die Zeile mit 'TCCR1A |=' stand zweimal 'COM1A0' und keine 'COM1B0'


99,99% dass es jetzt lauft...

gruss

Henk

Toastbrot
12.01.2006, 14:49
Hallo Henk,
danke für deine Hilfe! Tatsächlich habe ich zweimal COM1A0 verwendet und auch anstatt PD4+PD5 PD5+PD6 als Ausgang deklariert. Das kann dann ja nicht funktionieren.
Nun habe ich folgenden Code:



//PWM
TCCR1A = 0x00;
TCCR1B = 0x00;

TCCR1A |= (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0); //Timer konfigurieren
TCCR1B |= (1<<CS10) | (1<<CS12); //Prescaler 1024


//---------------------------------------------------------------------------------------------------------#

// Port D
PORTD = 0x00;
PORTD |= (1<<PD2) | (1<<PD3); //Default-Belegung
// RXD RS232 TXD RS232 INT0 INT1 PWM M1 PWM M2 Sound
DDRD = (0 << DDD0) | (1 << DDD1) | (0 << DDD2) | (0 << DDD3) | (1 << DDD4) | (1 << DDD5) | (1 << DDD7);


// Port C
PORTC = 0x00;
// Motor1.1 Motor1.2 Motor2.1 Motor2.2
DDRC = (1 << DDC4) | (1 << DDC5) | (1 << DDC6) | (1 << DDC7);


PORTC |= (1<<M1_D1) | (1<<M2_D1); //Fahrtrichtung

OCR1A = 255;
OCR1B = 100;



Das führt jetzt dazu, dass die Motoren mit steigender Zahl langsam werden! Ab etwa 230 tut sich garnichts mehr. Aber ansonsten scheint es doch zu funktionieren (hatte anfangs bedenken wegen der Antiproportinalen Motordrehzahl). Nochmal vielen Dank!

Toastbrot
12.01.2006, 20:17
Noch eine Frage: Kann ich OCR1A und OCR1B zeitgleich mit einem Befehl setzen? Ansonsten verzieht der Bot beim Anfahren, weil ein Motor verspätet andreht.

Arexx-Henk
12.01.2006, 22:12
Kann ich OCR1A und OCR1B zeitgleich mit einem Befehl setzen?

Gute Frage.

Nein, dass geht nicht, aber wenn z.B. die ATmega ein externen oszilator hat mit 8 MHz taktfrequenz werden die zwei register ungefahr 1us (!) nach einander beschrieben.

Bei theoretischen Motor (start) geschwindigkeit von 1 Meter pro Sekunde (!) macht dass ein unterschied zwischen beide Rader von 1 tausenste von eine Millimeter... Ist ja ungeheuer......;-)

Da musste mann doch ganz empfindlich sein dass irgendwo zu spuren. Ich denke wenn mann eine mechanische Schalter mit zwei kontakten benutzen sollte das die unterschied viel grosser ware.


gruss

Henk

Toastbrot
13.01.2006, 09:54
Doch doch, den Unterschied merkt man schon, hab es ja schon pronbiert! Der Bot hat so eine Abweichung von gut 1cm schon direkt beim Start! Und diese Abweichung potenziert sich ja mit fortlaufender Fahrt.

Wenn man die nicht gleichzeitig setzen kann, muss ich den ersten per Software wohl etwas langsamer anlaufen lassen. Experimentieren ist angesagt....

Arexx-Henk
13.01.2006, 16:37
Hallo Toastbrot,

hast Du schon mal probiert um OCR1A und OCR1B um zu tauschen? Ich meine
nicht:
OCR1A=0xFF; OCR1B=0xFF;
programmieren sondern
OCR1B=0xFF; OCR1A=0xFF;
programmieren und dann getestet wass die unterschied ist?
Vielleicht hat der Bot noch immer die gleiche abweichung.
Dass liegt an die reibung zwischen zahnrader u.s.w. und keine zwei motoren sind gleich, denke ich.

Gruss

Henk

Toastbrot
14.01.2006, 13:57
Habe ich noch nicht probiert, werde ich aber auf jeden Fall noch machen! Allerdings fährt der Bot nachher sehr genau geradeaus, daher denke ich schon, dass es an der Steuerung liegt. Ich werde es aber noch ausprobieren, danke für den Tipp.