mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Anfängerfrage: Motor Rechts-, Linkslauf mit PWM


Autor: Rocco L. (kaufparkangucker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

zur Zeit versuche ich einen Motor über eine H-Brücke mit einem ATmega8 
anzusteuern. Ziel soll es sein das der motor in einer "for" schleife 
eine bestimmte Zeit rechts herum und anschliesend in einer zweiten 
Schleife links herum dreht.

Ich habe mir schon einige Tutorials, das Datenblatt usw. durchgelesen. 
Leider begreife ich nicht warum OCR1A und OCR1B nicht in die Schleife 
dürfen. Steht nur einer dieser beiden Werte auserhalb der While geht 
alles wuderbar - zumindest in eine Richtung. Stehen beide auserhalb der 
while beinflussen sie sich gegenseitig entsprechend.

Wie mus man das machen das der Motor erst rechts und dann links herum 
läuft?

Hier mein bisheriger Code - zum größten Teil aus dem Tutorial von dieser 
Seite:
/* Standard Includes */
//#include <avr/interrupt.h>
#include <avr/io.h>
#define F_CPU 8000000UL     /* Quarz mit 8 Mhz */
#include <util/delay.h>
#include <stdint.h>
#include <inttypes.h>
 

#define Draht1     _BV(PB1)    //Motor vorwärts    
#define Draht2     _BV(PB2)    //Motor rückwärts    
    


int main(void)
{
  DDRB = 0xff;                      /* alle B Port Pins sind Outputs */
  PORTB = 0x00;                     /* fangen alle bei 0V an */

  const uint16_t delay = 1000;
  // OC1A auf Ausgang
  //DDRB = (1 << PB1 );    // OC1A auf Ausgang
  //DDRB = (1 << PB2 );  // OC1B auf Ausgang
  //
  // Timer 1 einstellen
  //  
  // Modus 14:
  //    Fast PWM, Top von ICR1
  //
  //    WGM13    WGM12   WGM11    WGM10
  //      1        1       1        0
  //
  //    Timer Vorteiler: 1
  //     CS12     CS11    CS10
  //       0        0       1
  //
  //  Steuerung des Ausgangsport: Set at BOTTOM, Clear at match
  //     COM1A1   COM1A0
  //       1        0
 
  TCCR1A = (1<<COM1A1) | (1<<WGM11)| (1<<COM1B1);
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
 
  //  den Endwert (TOP) für den Zähler setzen
  //  der Zähler zählt bis zu diesem Wert
 
  ICR1 = 0x6FFF;
  

  //OCR1A = 0x3FFF;     //Geschwindigkeit für vorwärts
  //OCR1B = 0x6FFF;    //Geschwindigkeit für rückwärts


 while( 1 ){
    
   for (int i=0; i<100; i++){
  OCR1A = 0x3FFF;
  _delay_ms(delay);
  PORTB |= Draht1;      //Motor vorwärts
  _delay_ms(delay);
   }

   for (int k=0; k<100; k++){
  OCR1A = 0x6FFF;
  _delay_ms(delay);
  PORTB |= Draht2;      //Motor rückwärts
  _delay_ms(delay);
   }

 }  
}


Danke für die Hilfe

fg Rocco

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
_delay mit Variablen funktioniert - soweit ich das weiß - nicht (ich 
benutze es nicht).

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Rocco L. (kaufparkangucker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

STK500-Besitzer schrieb:
> _delay mit Variablen funktioniert - soweit ich das weiß - nicht (ich
> benutze es nicht).

_delay_xs funktioniert mit Variablen. Hat bei einer älteren Bastelei 
auch funktioniert. Trotzdem habe ich die Variable erst mal gegen eine 
1000 getauscht.

Falk Brunner schrieb:
> http://www.mikrocontroller.net/articles/AVR-GCC-                           > 
Tutorial#Warteschleifen_.28delay.h.29

Daher habe ich das Grundgerüst für meinen Code. Ich Habe das Register 
TCCR1A um COM1B1 erweitert damit auch der Pin PB2 als OC1B angesprochen 
wird. Damit müsste ich ja eigentlich 2 Pins haben die über den Timer1 
angesprochen werden. Jetzt, dachte ich mir, braucht jeder Pin nur noch 
einen Vergleichswert, um so unterschiedliche Geschwindigkeiten zu 
erzeugen.
Somit hatte ich in der zweiten for Schleife ursprünglich OCR1B = 0x6FFF; 
statt OCR1A = 0x6FFF; stehen - aber das alles funktioniert nicht. der 
Motor dreht dabei entweder immer nur in eine Richtung - oder alles ist 
so falsch, dass der Motor garnicht dreht.

Danke für weitere Tips

fg Rocco

Autor: Christian T. (shuzz)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ohne jetzt die Timer-Einstellungen genau angeschaut zu haben:
Ich verstehe Deine while-Schleife nicht.

Du willst doch die H-Brücke per Hardware-PWM ansteuern, richtig?
Dazu setzt Du in die OCR1A/B Register einfach den jeweiligen Wert und 
gehst danach in eine delay-schleife.

Draht1 und Draht2 scheinen die Drehrichtung anzugeben, vllt. solltest Du 
einen der Ports einfach abschalten bevor Du den anderen aktivierst?
Nicht dass Dir noch die Brücke durchschiesst.

btw, ein Schaltplan Deiner H-Brücke wäre hilfreich. Hast Du ein 
Treiber-IC genommen oder diskret aufgebaut?

Autor: Rocco L. (kaufparkangucker)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Christian T. schrieb:
> Ohne jetzt die Timer-Einstellungen genau angeschaut zu haben:
> Ich verstehe Deine while-Schleife nicht.
>
> Du willst doch die H-Brücke per Hardware-PWM ansteuern, richtig?
> Dazu setzt Du in die OCR1A/B Register einfach den jeweiligen Wert und
> gehst danach in eine delay-schleife.
>
> Draht1 und Draht2 scheinen die Drehrichtung anzugeben, vllt. solltest Du
> einen der Ports einfach abschalten bevor Du den anderen aktivierst?
> Nicht dass Dir noch die Brücke durchschiesst.
>
> btw, ein Schaltplan Deiner H-Brücke wäre hilfreich. Hast Du ein
> Treiber-IC genommen oder diskret aufgebaut?

Hallo Christian,

Das abschalten des Drahtes habe ich jetzt so gelöst:
 while( 1 ){
    
   for (int i=0; i<100; i++){
    OCR1A = 0x3FFF;
    _delay_ms(delay);
    PORTB |= Draht1;      //Motor vorwärts
    _delay_ms(delay);
   }
    PORTB &= ~Draht1;
   for (int k=0; k<100; k++){
   
    OCR1B = 0x6FFF;
    _delay_ms(delay);
    PORTB |= Draht2;      //Motor rückwärts
    _delay_ms(delay);
   }
    PORTB &= ~Draht2;
 } 

Leider dreht der Motor trotzdem nur in eine Richtung. Was auch seltsamm 
ist ist, dass der Motor ca 2-3 min langsamm und dann 2min schneller 
dreht

Die H Brücke habe ich mal fix geEAGLEed - siehe Anhang

Autor: Rocco L. (kaufparkangucker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, Habe es raus gefunden. Ich muste nur noch die Schleife verkürzen.

 while( 1 ){

   for (int i=0; i<1; i++){
    OCR1A = 0x3FFF;
    _delay_ms(delay);
    PORTB |= Draht1;      //Motor vorwärts
    _delay_ms(delay);
   }
    OCR1A = 0x0000;
    PORTB &= ~Draht1;
   for (int k=0; k<1; k++){

    OCR1B = 0x3FFF;
    _delay_ms(delay);
    PORTB |= Draht2;      //Motor rückwärts
    _delay_ms(delay);
   }
    OCR1B = 0x0000;
    PORTB &= ~Draht2;
 }

Danke an alle

fg Rocco

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kannst du mir mal erklären, was die for-Schlaufen deiner Meinung nach da 
tun sollen?!?

Autor: Stephan V. (orca)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Rocco,

mir ist nicht ganz klar, was du eigentlich machen willst, aber ich 
glaube, dass du was anderes im Sinn hast, als du programmiert hast.
   for (int i=0; i<1; i++){  // ist wohl eine sehr kurze for-schleife von 0 bis 0???
    OCR1A = 0x3FFF;      // ok hier wird PWM für vorwärts mit 57% aktiviert (dein max ist ja laut erstem Posting 0x6FFF)
    _delay_ms(delay);    // dank PWM dreht sich der Motor jetzt mal selbstständig
    PORTB |= Draht1;     // => kurzes reinpfuschen in die PWM, wozu das???
    _delay_ms(delay);    // Motor dreht weiter
   }
    OCR1A = 0x0000;      // PWM ausschalten

   ... // und das ganze nochmal in die andere Richtung

Ist das wirklich das was du machen wolltest?
Probier mal zu Testzwecken ein kleines Programm, dass den Motor mal 5 
Sek. mit 50% vorwärts und anschließend 5 Sek. rückwärts dreht und dann 
den Motor abstellt.
(kleiner Tipp: du brauchst dafür keine for Schleifen und überleg dir wo 
dein while(1) hinkommt.)

by(e)
Stephan

Autor: Thilo M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die H-Brücke funktioniert so?
Sollten T1 und T2 nicht besser PNP sein?

Autor: Rocco L. (kaufparkangucker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

das mit der zu kurzen for Schleife 0 bis <1 ist natürlich mathematisch 
totaler Unsinn. Habe jetzt noch mal mit meinen geringen 
Programmierkenntnissen an meinem Quelltext herum gefuscht.
#include <avr/io.h>
#define F_CPU 8000000UL     /* Quarz mit 8 Mhz */
#include <util/delay.h>
#include <stdint.h>
#include <inttypes.h>
 

#define Draht1     _BV(PB1)    //Motor vorwärts    
#define Draht2     _BV(PB2)    //Motor rückwärts    
    
uint8_t hallsensor;

int main(void)
{
  DDRB = ((1<<DDB1) | (1<<DDB2));   /* B Port Pins sind Outputs */
  DDRB&= ~(1<<DDB0);        /* B Port Pins sind Inputs*/
  PORTB |=(1<<PB0);          /*interne Pull up Wiederstände ein*/
  PORTB = 0x00;                     /* fangen alle bei 0V an */

  const uint16_t delay = 3000;

  hallsensor = PB0;          // Status von PB0 in hallsensor kopieren

  //-----PWM--TIMER--EINSTELLEN----------------------
                          //    |
  TCCR1A = (1<<COM1A1) | (1<<WGM11)| (1<<COM1B1);//  |
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);//   |
                          //    |
  ICR1 = 0x6FFF;// ENDWERT DES ZÄHLERS       //    |
  //-------------------------------------------------

// while( 1 ){
    
   for (float i=0; i<124000; i++){
    OCR1A = 8186;      //Geschwindigkeit
    PORTB |= Draht1;        //Motor vorwärts
   }
    PORTB &= ~Draht1;  //Motor aus
    OCR1A = 0x0000;    //Geschwindigkeit 0
    _delay_ms(delay);  //Warten wegen Trägheit des Motors
   for (float k=0; k<124000; k++){
    OCR1B = 8186;      //Geschwindigkeit
    PORTB |= Draht2;        //Motor rückwärts
   }
    PORTB &= ~Draht2;  //Motor aus
    OCR1B = 0x0000;    //Geschwindigkeit 0
    _delay_ms(delay);  //Warten wegen Trägheit des Motors
// }  
}


 Ich finde das mit der for Schleife ja auch nicht so toll, schließlich 
erzeugt diese ja bereits so was wie eine PWM. Wie ich das allerdings 
ganz ohne Schleifen erleding sollte weis ich leider nicht. Bin halt noch 
ein Anfänger. Allerdings würde ich mich über weitere Tips sehr freuen.

Später soll mal an irgend einem Pin "gehorcht" werden und je nachdem was 
für ein binäres Signal anliegt soll der Motor bzw das Getriebe eine 
bestimmte Anzahl an Umdrehungen links oder rechts herum drehen. Die 
Umdrehungen messe ich z.Z. mit einem Hallsensor am Ende des Getriebes.

Danke für Eure Hilfe

fg Rocco

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso lässt du nicht erst mal die PWM weg und steuerst die H-Brücke über 
den Controller per Tasten?
Die "Einschaltperiode", wie du sie mit den For-Schleifen machen willst, 
kannst du auch vom Timer ableiten.
float ist auf (8Bit-)Mikrocontrollern nicht wirklich zu empfehlen, vor 
allem nicht, wenn man damit nur zählen will.
Dafür gibt es genug ganzzahlige Datentypen.

Autor: Rocco L. (kaufparkangucker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thilo M. schrieb:
>Die H-Brücke funktioniert so?
>Sollten T1 und T2 nicht besser PNP sein?

In der aufgebauten Schaltung sind es auch PNP Transistoren. Warum ich 
mich beim erstellen des Schaltplans in Eagle verguckt habe weis ich auch 
gerade nicht...




STK500-Besitzer schrieb:
> Wieso lässt du nicht erst mal die PWM weg und steuerst die H-Brücke über
> den Controller per Tasten?
> Die "Einschaltperiode", wie du sie mit den For-Schleifen machen willst,
> kannst du auch vom Timer ableiten.
> float ist auf (8Bit-)Mikrocontrollern nicht wirklich zu empfehlen, vor
> allem nicht, wenn man damit nur zählen will.
> Dafür gibt es genug ganzzahlige Datentypen.

Das Steuern per Tasten ist sehr einfach. So was habe ich bereits 
gemacht. Jetzt war es, wie ich finde, an der Zeit mich weiter zu 
entwickeln und mal was mit den Sonderfunktionen des Atmega8 zu 
probieren. PWM war dabei die erste Idee nachdem ich schon mit dem 
Analogkomperator und den D/A A/D Wandlern herum gespielt habe.

Hat vieleicht einer etwas passenden Code wo ich mir so etwas mit Timern 
statt der for Schleifen mal ansehen kann?

Danke Rocco

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.