Forum: Mikrocontroller und Digitale Elektronik Atmega 644 und PWM


von Trax X. (trax)


Lesenswert?

Ich habe ine kleines versändniss problem mit der bedienung der PWM 
kanäle

Dieses beispiel war im tutorial drin
1
 DDRD = (1 << PD5 ); //ATMega16
2
    //
3
    // Timer 1 einstellen
4
    //
5
    // Modus 14:
6
    //    Fast PWM, Top von ICR1
7
    //
8
    //     WGM13    WGM12   WGM11    WGM10
9
    //      1        1       1        0
10
    //
11
    //    Timer Vorteiler: 1
12
    //     CS12     CS11    CS10
13
    //       0        0       1
14
    //
15
    //  Steuerung des Ausgangsport: Set at BOTTOM, Clear at match
16
    //     COM1A1   COM1A0
17
    //       1        0
18
19
    TCCR1A = (1<<COM1A1) | (1<<WGM11);
20
    TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
21
22
    //
23
    //  den Endwert (TOP) für den Zähler setzen
24
    //  der Zähler zählt bis zu diesem Wert
25
26
    ICR1 = 0x6FFF;
27
28
    //
29
    // der Compare Wert
30
    // Wenn der Zähler diesen Wert erreicht, wird mit
31
    // obiger Konfiguration der OC1A Ausgang abgeschaltet
32
    // Sobald der Zähler wieder bei 0 startet, wird der
33
    // Ausgang wieder auf 1 gesetzt
34
    //
35
    // Durch Verändern dieses Wertes, werden die unterschiedlichen
36
    // PWM Werte eingestellt.
37
38
    OCR1A = 0x3FFF;

Wen ich jetzt eine funktion schreiben wo ich ein wert zwischen 0 und 
1023 angebe und der mir dann ein verhältniss ovn on/off liefert was 
diesem wert prozentuell entspricht also 0 ist 0% und 1023 ist 100%

Da müste ich nur dafür sorgen das ICR1 zu OCR1A diesem berhältniss 
entspricht, verstehe ich das richtig?
also das obige beispiel wäre 50%
beide auf 0x6FFF wäre 0%
und das obere auf 0x6FFF udn das untere auf 0 wären 100% ???

Wieso wird auch TCCR1B gesetzt ist das nicht füpr einen anderen kanal?

Was ich brauche ist eine funktion wo ich den kanal eines atmega 644 und 
das on/off verhältniss angebe und die das dan umsetzt, gibts da was 
fertiges?

von Trax X. (trax)


Lesenswert?

'n bisschen rat wäre schon hilfreich;)
 was da wer weiter?

von Trax X. (trax)


Lesenswert?

Über etwas Hilfe würde ich mich wirklich freuen.

von Karl H. (kbuchegg)


Lesenswert?

Trax Xavier wrote:

> Da müste ich nur dafür sorgen das ICR1 zu OCR1A diesem berhältniss
> entspricht, verstehe ich das richtig?

Richtig.

> also das obige beispiel wäre 50%

Nicht ganz 0x3FFF ist nicht die Hälfte von 0x6FFF

> beide auf 0x6FFF wäre 0%

eher 100%.
Das hängt ja davon ab, ob der Pin bei einem Timerwert von 0 auf 0 oder 
auf 1 gesetzt wird. Dafür zuständig ist das COM1A1 Flag.

> und das obere auf 0x6FFF udn das untere auf 0 wären 100% ???

Welches obere? Bitte benutze die Ausdrücke, so wie sie im Tutorial oder 
im Datenblatt benutzt werden und erfinde nicht deine eigene Sprache.

> Wieso wird auch TCCR1B gesetzt ist das nicht füpr einen anderen kanal?

Nein.
In Blick ins Datenblatt hätte dir verraten, dass einige der 
Konfigurationsbits im TCCR1A und einige im TCCR1B sind. Erst alle 
Konfigurationsbits zusammen (also die in TCCR1A und die in TCCR1B) 
bestimmen was der Timer macht.

> Was ich brauche ist eine funktion wo ich den kanal eines atmega 644 und
> das on/off verhältniss angebe und die das dan umsetzt, gibts da was
> fertiges?

Ah geh. Du wirst doch wohl einen simplen Dreisatz hinkriegen.

(0x6FFF sind dezimal 28671)

  100% sind    28671
   34% sind    x
  _________________


     x = .........

simples Prozentrechnen halt.

ICR1 lässt du auf 0x6FFF und OCR1A kriegt den errechneten Wert.

Was michverblüfft: Wenn du verstanden hast, wie so ein Timer 
funktioniert und wie da eine PWM daraus erzeugt wird, dann hast du ja eh 
nur ein einziges Register in dem du Werte verändern kannst um das 
Verhältnis einzustellen. Warum probierst du das nicht einfach aus? Das 
ist in 3 Minuten erledigt! Statt dessen wartest du 19(!) Stunden lang 
auf eine Antwort.

von Johannes M. (johnny-m)


Lesenswert?

Trax Xavier wrote:
> Wen ich jetzt eine funktion schreiben wo ich ein wert zwischen 0 und
> 1023 angebe und der mir dann ein verhältniss ovn on/off liefert was
> diesem wert prozentuell entspricht also 0 ist 0% und 1023 ist 100%
>
> Da müste ich nur dafür sorgen das ICR1 zu OCR1A diesem berhältniss
> entspricht, verstehe ich das richtig?
Möglicherweise verstehst Du selber nicht, was Du hier geschrieben 
hast...

> also das obige beispiel wäre 50%
> beide auf 0x6FFF wäre 0%
Nö, mit Deiner Einstellung (set at bottom, clear on compare) sind das 
100 %.

> und das obere auf 0x6FFF udn das untere auf 0 wären 100% ???
Wer ist "das obere" und "das untere"? Haben die auch Namen?

> Wieso wird auch TCCR1B gesetzt ist das nicht füpr einen anderen kanal?
Bitte schau Dir die Bits in den TCCRs an und überlege, was die für eine 
Bedeutung haben und ob das irgendwas mit den einzelnen Compare-Kanälen 
zu tun hat. Überlege v.a., was passiert, wenn die CS-Bits in TCCR1B 
nicht setzt...

Hast Du jemals einen Blick ins AVR-GCC-Tutorial geworfen? Da steht 
eigentlich alles drin...

Es macht auch Sinn, sich bei solchen Sachen entweder für die 
Hexadezimal- oder für die Dezimaldarstellung zu entscheiden. Beides 
durcheinander verwirrt vermutlich v.a. Dich. Und gerade bei Dingen, wo 
es um Prozent und Ähnliches geht, ist die Dezimaldarstellung oft 
sinnvoller...

von Trax X. (trax)


Lesenswert?

> Hast Du jemals einen Blick ins AVR-GCC-Tutorial geworfen?
Jo das code sample aus meinem ersten post stammt ja da her ;)
leider fand ich das ganze eher verwirrent da nihct für alle register 
geschrieben steht was die machen.

Also es gibt 1 Timer der alle 6 PWM Kanäle der Atmega644 versorgt der 
mit
TCCR1A, TCCR1B ,ICR1 bedient wird,

und für die einzelnen Kanäle gibt es OC0A OC0B OC1A OC1B OS2A OC2B,
also das PWM für ein Kanal wird dadurch aktiviert das der wert da > 0 
ist, also ums auszuschalten muss ichs einfach wieder auf 0 setzen, oki, 
soweit sogut. oder?

Was machen die bits WGM13 und WGM12 steht im tutorial nicht drin


Also noch was ich jetzt machen werde:
beim start des programms den Timer initialisieren:
TCCR1A = (1<<WGM11) | (1<<WGM10) | (1<<COM1A1); // 10 bi nihct 
invertiert
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10); // ?? ??, Clock divider 1

ICR1 = 0x6FFF; // bis zu diesem wert zählt der timer die ticks der CPu 
und dan wieder runter

Dan für jeden kanal wen ich ihn einstellen will
OCRxy = n*0x1C (für n=0 ist alles 0 und de pin ist aus und nciht im PWM 
modus, oder? für n=0x3FF also 1023 ist der wert 0x6FFF und der pin ist 
an und auf 100%, für n=0xFF also ~25% ist der wert 0x1BE4)

Ist das soweit alles korrent?
1
uint8_t PWMon = 0;
2
void InitPWM()
3
{
4
  //
5
  // Timer 1 einstellen
6
  //
7
  // Modus 14:
8
  //    Fast PWM, Top von ICR1
9
  //
10
  //     WGM13    WGM12   WGM11    WGM10
11
  //      1        1       1        1
12
  //
13
  //    Timer Vorteiler: 1
14
  //     CS12     CS11    CS10
15
  //       0        0       1
16
  //
17
  //  Steuerung des Ausgangsport: Set at BOTTOM, Clear at match
18
  //     COM1A1   COM1A0
19
  //       1        0
20
  
21
  TCCR1A = (1<<WGM11) | (1<<WGM10) | (1<<COM1A1);
22
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
23
  
24
  //
25
  //  den Endwert (TOP) für den Zähler setzen
26
  //  der Zähler zählt bis zu diesem Wert
27
  
28
  ICR1 = 0x6FFF;
29
  
30
  PWMon = 1;
31
}
32
33
void SetVal(int Port, uint16_t Val)
34
{
35
  if(PWMon == 0)
36
    InitPWM();
37
    
38
  if(!(*g_Gpio[Port].pDdr >> g_Gpio[Port].nBit) & 1)
39
    *(g_Gpio[Port].pDdr) |= (1<<g_Gpio[Port].nBit);
40
  
41
  // der Compare Wert
42
  // Wenn der Zähler diesen Wert erreicht, wird mit
43
  // obiger Konfiguration der OC1A Ausgang abgeschaltet
44
  // Sobald der Zähler wieder bei 0 startet, wird der
45
  // Ausgang wieder auf 1 gesetzt
46
  //
47
  // Durch Verändern dieses Wertes, werden die unterschiedlichen
48
  // PWM Werte eingestellt.
49
50
  uint16_t PWMcmp = Val*0x1C;
51
  
52
  if(g_Gpio[Port].nPWM == 0x1B)
53
    OCR1B = PWMcmp;
54
  if(g_Gpio[Port].nPWM == 0x1A)
55
    OCR1A = PWMcmp;
56
  if(g_Gpio[Port].nPWM == 0x2B)
57
    OCR2B = PWMcmp;
58
  if(g_Gpio[Port].nPWM == 0x2A)
59
    OCR2A = PWMcmp;
60
  if(g_Gpio[Port].nPWM == 0x0A)
61
    OCR0A = PWMcmp;
62
  
63
  // pin auf 0 nur so zur sicherheit
64
  if(PWMcmp == 0)
65
    *g_Gpio[Port].pPort &= ~(1<<g_Gpio[Port].nBit);
66
}

von Karl H. (kbuchegg)


Lesenswert?

Trax Xavier wrote:
>
> Was machen die bits WGM13 und WGM12 steht im tutorial nicht drin

Schau ins Datenblatt. Das Tutorial ist nur ein Auszug des Datenblatts.
(Sonst könnten wir ja gleich das Datenblatt als Tutorial hier 
reinstellen).

Für Details, die du im Tutorial nicht findest, ist IMMER das Datenblatt 
deine nächste Anlaufstelle. Es schadet auch nichts, das im Tutorial 
gelesene mit dem Datenblatt kreuzzuvergleichen. Im Laufe der Zeit wird 
sich das dann umdrehen. Deine erste Informationsquelle wird das 
Datenblatt und wenn du dort was nicht verstehst, schaust du im Tutorial 
nach, ob hier vielleicht jemand eine nähere Erläuterung geschrieben hat. 
Bist du irgendwann das Tutorial nicht mehr brauchst und nur noch mit dem 
Datenblatt arbeitest.

Aber egal worum es geht: Es ist immer das Datenblatt, welches 
Gesetzeskraft hat. Es und nur es gilt. Wenn sich Datenblatt und Tutorial 
widersprechen, gilt das Datenblatt. Wenn was im Tuorial steht, was so 
nicht im Datenblatt steht, gilt das Datenblatt. Wenn im Tutorial etwas 
nicht steht was im Datenblatt steht, gilt das Datenblatt.


> OCRxy = n*0x1C (für n=0 ist alles 0 und de pin ist aus und nciht im PWM
> modus, oder?

Ob der Pin im PWM Modus ist oder nicht, entscheidet doch nicht das 
Puls/Pause Verhältnis. Natürlich ist der Pin weiterhin im PWM Modus. Er 
ist halt nur dauern Low (oder dauern High)

von Karl H. (kbuchegg)


Lesenswert?

> Ist das soweit alles korrent?

Schon wieder einer, der Unmengen an Code schreibt, ohne kleinere 
Codeteile auch nur ein einziges mal getestet zu haben.

Häng eine Led an einen der PWM Pins an und weise dem zugehörigen OCR 
Register einfach mal ein paar verschiedene Werte zu. Dann weist du obs 
nicht funktioniert oder aber, wenn die Led reagiert, dass du so daneben 
nicht liegen wirst.
Und das beste daran: Es geht schneller als hier die Frage einzutippen 
und macht auch noch Spass.

von Johannes M. (johnny-m)


Lesenswert?

Trax Xavier wrote:
> Also es gibt 1 Timer der alle 6 PWM Kanäle der Atmega644 versorgt
Nein! Es gibt drei Timer, von denen jeder zwei PWM-Kanäle hat!

> TCCR1A, TCCR1B ,ICR1 bedient wird,
Das ist Timer 1! Der hat zwei PWM-Ausgänge.

> und für die einzelnen Kanäle gibt es OC0A OC0B OC1A OC1B OS2A OC2B,
OC heißt Output Compare. Dann kommt die Nummer des Timers. Und dann der 
Buchstabe, der den Kanal bezeichnet. OC0A und OC0B gehören also zu Timer 
0, OC1A und B zu Timer 1 usw. Zu jeder Compare-Einheit (also zu jedem 
OCnx-Pin) gehört ein Compare-Register, in das der jeweilige 
Vergleichswert reinkommt.

> also das PWM für ein Kanal wird dadurch aktiviert das der wert da > 0
> ist, also ums auszuschalten muss ichs einfach wieder auf 0 setzen, oki,
> soweit sogut. oder?
Bitte arbeite an Deiner Formulierung! Das versteht keiner, vielleicht 
nicht mal Du selbst!

> Was machen die bits WGM13 und WGM12 steht im tutorial nicht drin
Aber im Datenblatt. Das Tutorial bezieht sich ja auch auf einen ATMega8.

Den Rest hat Karl heinz ja schon weitgehend erläutert...

von Trax X. (trax)


Lesenswert?

So jetzt aber:
1
void SetVal(int Port, uint16_t Val)
2
{
3
  if(!(*g_Gpio[Port].pDdr >> g_Gpio[Port].nBit) & 1)
4
    *(g_Gpio[Port].pDdr) |= (1<<g_Gpio[Port].nBit);
5
6
  if(g_Gpio[Port].nPWM == 0x1A) //OC1A // PD5
7
  {
8
    TCCR1A = (1<<WGM11) | (1<<WGM10) | (1<<COM1A1);
9
    TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10) | (0<<CS11) | (0<<CS12);
10
11
    OCR1A = Val;
12
  }
13
  else if(g_Gpio[Port].nPWM == 0x1B) //OC1B // PD4
14
  {
15
    TCCR1A = (1<<WGM11) | (1<<WGM10) | (1<<COM1B1);
16
    TCCR1B = (0<<WGM13) | (1<<WGM12) | (1<<CS10) | (0<<CS11) | (0<<CS12);
17
18
    OCR1A = Val;
19
  }
20
  else if(g_Gpio[Port].nPWM == 0x2A) //OC2A //PD7
21
  {
22
    TCCR2A = (0<<WGM11) | (1<<WGM10) | (1<<COM2A1);
23
    TCCR2B = (0<<WGM13) | (1<<WGM12) | (1<<CS10) | (0<<CS11) | (0<<CS12);
24
25
    OCR2A = Val/4;
26
  }
27
  else if(g_Gpio[Port].nPWM == 0x2B) //OC2B //PD6
28
  {
29
    TCCR2A = (0<<WGM11) | (1<<WGM10) | (1<<COM2B1);
30
    TCCR2B = (0<<WGM13) | (1<<WGM12) | (1<<CS10) | (0<<CS11) | (0<<CS12);
31
32
    OCR2B = Val/4;
33
  }
34
}

Noch ne frage zur Sicherheit, sie ports sind den timern fest 
zugeschrieben, oder? also man könnte nicht zB PD5 und PD4 mit timer 0 
anstelle von timer 1 berteiben, doer?

von Dibo D. (Firma: FH) (duspol)


Lesenswert?

#include <avr/io.h>



int main(){

  unsigned int x;


  TCCR1A = (1<<COM1A1) | (1<<WGM11);
  TCCR1B = (1<<WGM13) | (0<<WGM12) | (1<<CS10) |(1<<CS11);

  //Phase Correct Prescaler 8

  ICR1 = 1000;


  while(1)

  //Ad Wandler liefert den Wert x

  OCR1A = x;


}


Meine frage ist.Mein Atmega16 befindet sich im STK500.Ich benutze den 
Software generierten Takt.Ich habe den Clock generator im AVRStudio auf 
3,686000 Mhz eigenstellt.

Heisst das also mein Pwm frequnz:

Fpwm = F_clock/2.N.TOP  (TOP wird dann ICR1)

Am Ausgang soll denn 230 Hz anliegen oder?

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.