Forum: Mikrocontroller und Digitale Elektronik Avr Studio - PWM mit atmega328p


von Almir J. (almir)


Lesenswert?

Hallo liebe Leute.

Bin ganz neu beim Arduino und gerade am kennenlernen.
Habe mich vorher mit dem Tiva C Series TM4C1294 beschäftigt, und komme 
mit dem sehr gut klar. Also kein absoluter Neuling auf dem Gebiet.

Ich bräuchte jetzt etwas Hilfe beim Arduino UNO und PWM, da blicke ich 
gerade nicht ganz durch.

Hat einer von euch viell. einen exampple Code.
Möchte ein PWM Signal von 1,5ms rausschicken, und stehe etwas auf der 
Leitung.

Danke im Vorraus.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Almir J. schrieb:
> Möchte ein PWM Signal von 1,5ms rausschicken, und stehe etwas auf der
> Leitung.

Lass mich raten - meinst du ein 1,5ms Puls mit etwa 20ms Wiederholrate? 
Um RC-Servos anzusteuern?
Dann sollte das hier helfen:
https://www.arduino.cc/en/Reference/Servo

von Almir J. (almir)


Lesenswert?

Vielen Dank für deine Antwort.

Genau, ich möchte einen Servomotor steuern.

Was ich bis jetzt gefunden habe ist dass ich mit PWM's:
1 - 1,5 ms in Uhrzeigersinn drehen kann
1,5 ms = stop
1,5 - 2 ms gegen Uhrzeigersinn.

als Platfrom dient mir der Arduino Uno.

Ich möchte das aber ohne Sktech machen, also reiner C-Code mit so wenig 
Librarys wie möglich.

Wie es bei dem Tiva C board geht weiß ich. Aber hier stehe ich etwas an.

Am hilfreichsten wäre ein example wo das wirklich ausprogrammiert ist, 
leider konnte ich bis jetzt nur sketch Beispiele finden.

z.b. myservo.write(pos);
ich weiß dass hier ein PWM gesendet wird, aber wie sieht das ohne die 
library aus.

gibt es ein bsp wo quasi drinnen steht?
"PWM(dauer) auf PIN XY" für das AVR studio. oder ein tutorial dazu?

von Sascha (Gast)


Lesenswert?

Nennt sich AVR Tutorial, oben links auf dieser Internetseite zu finden.

Wenn du nach Arduino googelst findest du Sketche, wenn du nach AVR 
googelst C-Code.

von Almir J. (almir)


Lesenswert?

Jetzt komme ich da langsam rein. =)
 Vielen Dank.

von Almir J. (almir)


Lesenswert?

So ich habe jetzt aus Tutorials und mit Internetrecherche einen Code.

Leider bewegt sich der Motor kein Stück.

Irgenwdo ist da noch ein Wurm drinnen, den ich leider nicht sehe.
Vielleicht weiß jemand was es sein könnte.

Zur erklärung.
Ein Servomotor hängt jetzt bei mir am Arduino UNO am Pin 5.
Das ist der PD5.

Im Sketch funktioniert es, daher ist der Motor und das Board ok. Aber in 
meinem Code hab ich einen Fehler.

Der Motor müsste sich jetzt eigentlich im Uhrzeigersinn drehen. Der Code 
müsste mir mit einer Frequenz von 50 HZ ein 1.264ms PWM Signalerzeugen.

Bin für Hilf sehr dankbar.

LG

#include <inttypes.h>
#include <avr/io.h>
#define F_CPU 16000000
int main( void )
{

  TCCR1A|= (1<<7)| (1<<5) | 1; //COM1A1 COM1B1 WGM11   non inverted pwm
  TCCR1B|= (1<<4) | (1<<3) | 1<<1 | 1<<0;; //WGM13  WGM12  CS11 CS10 
prescaler = 64
  ICR1 = 4999; //pwm = 50Hz
  DDRD |= (1<<5); // DataDirection Port D: Pin D5 = Output (Led)
  while (1)
  {
    OCR1A=316;
  } // endlessly
  return(0);
}

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Almir J. schrieb:
> TCCR1A|= (1<<7)| (1<<5) | 1; //COM1A1 COM1B1 WGM11   non inverted pwm

Diese Schreibweise ist uncool - man blickt ja gar nicht durch, was nun 
gesetzt wird.
Schreib lieber
1
TCCR1A |= (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
ALs nächstes musst du PB1 (OC1A) noch auf Ausgang setzen, sonst passiert 
da gar nichts. An PB1 sollte dann das PWM Signal auftauchen.

Almir J. schrieb:
> Der Motor müsste sich jetzt eigentlich im Uhrzeigersinn drehen.

Das Servo fährt dann aber nur die Stelle an und bleibt dann stehen. Erst 
wenn du mit OCR1A eine andere Pulslänge angibst, fährt das Servo die 
neue Position an.

Almir J. schrieb:
> Ein Servomotor hängt jetzt bei mir am Arduino UNO am Pin 5.
> Das ist der PD5.

Das ist aber OC0A und ist für Timer 0. Du benutzt Timer 1, der OC1A und 
OC1B bedient, die befinden sich auf PB1 und PB2.

: Bearbeitet durch User
von STK500-Besitzer (Gast)


Lesenswert?

Almir J. schrieb:
> Der Motor müsste sich jetzt eigentlich im Uhrzeigersinn drehen. Der Code
> müsste mir mit einer Frequenz von 50 HZ ein 1.264ms PWM Signalerzeugen.

Dein Code wird einmal ausgeführt und dann macht der Controller 
irgendwas.

Bei einem Mikrocontroller musst du dich im Gegensatz zu einem 
Betriebsystem um alles selber kümmern.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Matthias S. schrieb:
> Das ist aber OC0A und ist für Timer 0.

Sorry, das ist Unsinn. An PD5 liegt OC0B, ist aber hier nicht so 
wichtig. Du brauchst für Timer 1 auf jeden Fall OC1A und evtl. für ein 
zweites PWM Signal OC1B.

: Bearbeitet durch User
von Almir J. (almir)


Lesenswert?

Matthias S. schrieb:
> Matthias S. schrieb:
>> Das ist aber OC0A und ist für Timer 0.
>
> Sorry, das ist Unsinn. An PD5 liegt OC0B, ist aber hier nicht so
> wichtig. Du brauchst für Timer 1 auf jeden Fall OC1A und evtl. für ein
> zweites PWM Signal OC1B.

Verstehe ich nicht ganz. Warum kann ich nicht den OC0B verwenden? Laut 
Arduino Schema ist das doch einer der Pins die für PWM genutzt werden.
PIN 3,5,6,9,10,11. daher auch der Pin D5


@ STK500-Besitzer (Gast)
Der Motor ist ein Spring SM S430 3R. Der bleibt nicht stehn.
Wenn du ihm ein PWM Signal zwischen 1 und 1,5 ms schickst, dann dreht 
der sich solange bis du ihm ein Signal von 1,5ms schickst.

Der Code ist ja als solches noch nicht ganz fertig. Sobald ich es 
schaffe ihm mal das Signal zwischen 1 . 1,5 zu schicken bringe ich ihn 
auch zum stehen. Leider klappt das bis jetzt noch nicht.

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Almir J. schrieb:
> Verstehe ich nicht ganz. Warum kann ich nicht den OC0B verwenden? Laut
> Arduino Schema ist das doch einer der Pins die für PWM genutzt werden.

Arduino hin oder her, aber die Hardware des Mega ist nun einmal so 
eingerichtet, das die OC Ausgänge für Timer 1 an PB1 (OC1A) und PB2 
(OC1B) liegen. Wenn du also Hardware PWM mit Timer 1 machen willst, und 
das ist ja der einzige 16-bit Timer des Mega328, dann wird die PWM eben 
nur an diesen Pins auftauchen.
Und PWM an OC0A und OC0B kommt ja tatsächlich an PD6 und PD5 raus, aber 
nur wenn Timer 0 benutzt wird. Das ist aber auch nur ein 8-bit Timer.

Also schalte PB1 auf Ausgang, und leg deinen Motor an diesen Pin - sonst 
gehts nicht.

von Almir J. (almir)


Lesenswert?

Endlich-

Habs zum laufen bekommen.

Hier der Code.

/*
 * GccApplication4.c
 *
 * Created: 17.03.2016 12:37:16
 * Author : user
 */
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>
#define F_CPU 16000000
int main( void )
{
DDRD |= (1<<PORTD5);
TCCR0A|= (1<<COM0A1)| (1<<COM0B1) | (1<<WGM01) | (1<<WGM00);
TCCR0B|=  (1<<CS02) | (1<<CS00);

  while (1)
  {
    OCR0A=15;
    _delay_us(3000);
    OCR0A=90;
    _delay_us(3000);
    OCR0A=50;
    _delay_us(3000);
    OCR0A=150;
    _delay_us(3000);
    OCR0A=250;
    _delay_us(3000);
  } // endlessly
  return(0);
}

leider dreht sich der Motor jetzt stur nur gegen Uhrzeigerrichtung.
Vielleicht jemand ne Idee?

Die verschiedenen OCR0A werte sollen bewirken dass er sich mit 
verschiedenen Geschwindigkeiten auch teils in verschiedene Richtungen 
dreht.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

> (1<<COM0A1)| (1<<COM0B1)

Erkläre mal, warum du diese Bits gesetzt hast. Warscheinlich fällt Dir 
dann schon selbst auf, woran es hakt.

Un dann noch was:
Du hast den Prescaler auf 64 gestellt. Bei 16MHz hast dein Timer also 
eine Taktfrequenz von 250kHz. Die teilt er durch 256 -> Macht 977 
Impulse Pro Sekunde.

R/C Servos erwarten aber 50 Impulse Pro Sekunde.

Vielleicht magst du mal von dem hier abgucken, da kannst du auch die I/O 
Pins beliebig zuordnen: 
http://stefanfrings.de/servocontroller/index.html

von Stefan F. (Gast)


Lesenswert?

> Was ich bis jetzt gefunden habe ist dass ich mit PWM's:
> 1 - 1,5 ms in Uhrzeigersinn drehen kann
> 1,5 ms = stop
> 1,5 - 2 ms gegen Uhrzeigersinn.

Das gilt nur für Gehackte Servos ohne Endanschlag. Normale Lenkservos 
fahren einen bestimmten Winkel an (je nach Pulsbreite) und verharren 
dann auf dieser Position.

Normalerweise gilt dies:

1-1,5ms: Nach links lenken
1,5ms: Geradeaus fahren
1,5-2ms: nach rechts lenken

von Almir J. (almir)


Lesenswert?

Stefan U. schrieb:
>> (1<<COM0A1)| (1<<COM0B1)
>
> Erkläre mal, warum du diese Bits gesetzt hast. Warscheinlich fällt Dir
> dann schon selbst auf, woran es hakt.
>
> Un dann noch was:
> Du hast den Prescaler auf 64 gestellt. Bei 16MHz hast dein Timer also
> eine Taktfrequenz von 250kHz. Die teilt er durch 256 -> Macht 977
> Impulse Pro Sekunde.
>
> R/C Servos erwarten aber 50 Impulse Pro Sekunde.
>
> Vielleicht magst du mal von dem hier abgucken, da kannst du auch die I/O
> Pins beliebig zuordnen:
> http://stefanfrings.de/servocontroller/index.html


TCCR0B|=  (1<<CS02) | (1<<CS00); der prescaler ist hier 1024

16.000.000 / (1024 * 256)  = 61,035.

Die 61 Hz waren fü mich halt die größte näherung an die 50Hz

von Almir J. (almir)


Lesenswert?

Stefan U. schrieb:
>> Was ich bis jetzt gefunden habe ist dass ich mit PWM's:
>> 1 - 1,5 ms in Uhrzeigersinn drehen kann
>> 1,5 ms = stop
>> 1,5 - 2 ms gegen Uhrzeigersinn.
>
> Das gilt nur für Gehackte Servos ohne Endanschlag. Normale Lenkservos
> fahren einen bestimmten Winkel an (je nach Pulsbreite) und verharren
> dann auf dieser Position.
>
> Normalerweise gilt dies:
>
> 1-1,5ms: Nach links lenken
> 1,5ms: Geradeaus fahren
> 1,5-2ms: nach rechts lenken

Dieser servo ist vno der Bauart her aber so. Der hat keinen Endanschlag.
Hat sich jetzt gerade 5 mal im Kreis gedreht.

von Stefan F. (Gast)


Lesenswert?

> der prescaler ist hier 1024
Gut, dann habe ich mich da verguckt. Ich hatte CS01 gelesen, statt CS02.

> Hat sich jetzt gerade 5 mal im Kreis gedreht.
Na dann kann es ja eigentlich nur noch am Timing liegen.

Wir haben also einen Timer-Takt von 16Khz. Dass heisst, 16 Takte wären 
1ms, 32 Takte wären 2ms. In diesem bereich solltest du erstmal bleiben.

> OCR0A=15;
> OCR0A=90;
> OCR0A=50;
> OCR0A=150;
> OCR0A=250;

Die meisten deiner Vergleichswerte sind ganz andere außerhalb dieses 
Bereiches.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Mit dem 8-Bit Timer 0 bekommst du nur sehr wenig Auslösung in dem 
interessierenden Bereich von 1-2ms.
Deswegen ja der Vorschlag, den 16-bit Timer, den du oben ja fast fertig 
konfiguriert hattest, zu benutzen.
Dessen PWM Ausgänge sind aber nun mal auf PB1 und PB2. Es hat auch keine 
Sinn, mir deswegen PMs zu schicken, denn ich kann auch nur das 
Datenblatt zitieren.

von Axel R. (Gast)


Lesenswert?

while (1)
  {
    OCR0A=15;
    _delay_us(3000);
    OCR0A=16;
    _delay_us(3000);
    OCR0A=17;
    _delay_us(3000);
..
..
    OCR0A=31;
    _delay_us(3000);
    OCR0A=32;
    _delay_us(3000);

  } // endlessly


probier mal so
Axelr.
DG1RTO

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.