Forum: Mikrocontroller und Digitale Elektronik PWM mit ATMega8 - Potentiometer zum verändern der Frequenz und Pulsweite


von Patrick W. (yellow_dog)


Lesenswert?

Hallo liebes Forum,

ich hoffe es kennt sich jemand ein bisschen mit der Programmierung eines 
Mikrocontrollers aus. Ich habe bereits eine PWM erzeugen können.
Hier die Source-Datei:

Quellcode
1
/* ***************************************************************/
2
/* Programm: PWM auf AVR-Board mit ATMega8         */
3
/* Name: Patrick Willenshofer               */
4
/* Datum: 18.12.2011                   */
5
/* ***************************************************************/
6
7
#include <avr/io.h>
8
int main (void)
9
 {
10
  DDRB = (1 << PB1 ); 
11
  // Freischalten des Ausganges PB1(OC1A) am PortB
12
13
  TCCR1A = (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0);
14
  //Um die PWM starten zu können müssen Parameter für das Controll Register A (TCCR1A) 
15
  //laut Tabellen gesetzt werden hier handelt es sich um eine 8-Bit, invertierende PWM 
16
 
17
  TCCR1B = (1<<CS12);
18
  //Das Controllregister B (TCCR1B) ist für den Takt zuständig und kann ebenfalls 
19
  //durch Parameter aus den Tabellen bestimmt bzw. eingestellt werden.
20
 
21
  OCR1A = 200;                                                                                                                     
22
  // Das Output Compare Register (OCR1A) gibt den Vergleichswert an.
23
 }


Achja. mein Mikrocontroller ist ein ATMEL ATMega8.

Nun stehe ich vor folgender Aufgabe: Ich will an ADC0 und ADC1 (Port C) 
Potentiometer ranhängen, um mit ADC0 die Frequenz - und mit ADC1 die 
Pulsweite - modulieren.
Ich habe mich schon tief in das Analog-Digital-Wandler-Thema eingelesen. 
Ich kann auch schon ziemlich gut die Zusammenhänge verstehen.
Nur: Wie müsste der Code im endeffekt aussehen? Kann mir jemand 
Bruchteile posten, würde gern von selber draufkommen :)
Ich tu mir nur schwer, zu verstehen, wie ich das modulieren kann. Ich 
hab schon viel gehört, PWM ist sehr einfach und kann jeder. Nun, stimm 
ich zu, aber ich denk grad viel zu kompliziert..

Mein Ansatz ist ja folgender:
*) Mit ADC0 möchte ich die Frequenz verändern. Die Werte, die der ADC 
als Ergebnis bekommt, werden ins ADCL und ins ADCH geschrieben.
Ich habe eine Auflösung von 10Bit, also würd es so aussehen:
x = ACDL; // die Variable x bekommt die 8Bit vom ADCL zugewiesen - mit 
uint16_t für x
x += ACDH; // der Inhalt (2Bits) werden zur Variable x addiert.

die Variable x wird danach dem im ADC SRA (ADC Status Register A) den 
Bits 0,1,2 zuweisen. Die sind ja schließlich für den Takt zuständig?
Also hier ist im MUX der ADC0 ausgewählt. Nachdem er hier gemessen hat, 
würde er im nächsten Schritt zum ADC1 wechseln und dort wieder messen 
und auswerten.

Immer wenn ich mich weiter darin vertiefen will, verlier ich den 
Überbrlick. Ich hoff, mir kann jemand weiterhelfen.
Sind meine Ansätze richtig? Ich hoffe es jedenfalls. :)

Vielen Dank schon einmal!
von Karl H. (kbuchegg)


Lesenswert?

Patrick Willenshofer schrieb:


> Nur: Wie müsste der Code im endeffekt aussehen? Kann mir jemand
> Bruchteile posten, würde gern von selber draufkommen :)

Schau ins AVR-GCC-Tutorial
Da gibt es ein ganzes Kapitel über den ADC, inklusive Routinen
von Karl H. (kbuchegg)


Lesenswert?

> x = ACDL; // die Variable x bekommt die 8Bit vom ADCL zugewiesen - mit
uint16_t für x
> x += ACDH; // der Inhalt (2Bits) werden zur Variable x addiert.

Nein.

8 + 2 ergibt 10 und nicht 28

aber 8 + 2 * 10  macht 28

ANalog:  x = ADCL + ADCH * 256
oder     x = ADCL + (ADCH<<8);

oder aber die simpelste Variante:

         x = ADCW;

dann macht der Compiler für dich das Zusammensetzen der Einzelteile über 
das Pseudoregister ADCW
von Karl H. (kbuchegg)


Lesenswert?

> die Variable x wird danach dem im ADC SRA (ADC Status Register A)
> den Bits 0,1,2 zuweisen. Die sind ja schließlich für den Takt
> zuständig?

Das eben gewonnene x wird doch nicht dem ADCSRA zugewiesen. Wozu soll 
das gut sein? x ist doch der Messwert vom ADC. Den ADC konfigurierst du 
einmal auf eine Taktfrequenz und gut ists.

> Also hier ist im MUX der ADC0 ausgewählt. Nachdem er hier gemessen
> hat, würde er im nächsten Schritt zum ADC1 wechseln und dort wieder
> messen und auswerten.

Yep.

> Immer wenn ich mich weiter darin vertiefen will, verlier
> ich den Überbrlick.

Es wird Zeit, dass du real programmierst und nicht nur liest. Lesen ist 
gut aber manchmal muss man dann auch einfach zur Tat schreiten.
1
int main (void)
2
 {
3
  DDRB = (1 << PB1 ); 
4
  // Freischalten des Ausganges PB1(OC1A) am PortB
5
6
  TCCR1A = (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0);
7
  //Um die PWM starten zu können müssen Parameter für das Controll Register A (TCCR1A) 
8
  //laut Tabellen gesetzt werden hier handelt es sich um eine 8-Bit, invertierende PWM 
9
 
10
  TCCR1B = (1<<CS12);
11
  //Das Controllregister B (TCCR1B) ist für den Takt zuständig und kann ebenfalls 
12
  //durch Parameter aus den Tabellen bestimmt bzw. eingestellt werden.
13
14
  ADC_Init();
15
 
16
  while( 1 ) {
17
    OCR1A = ADC_Read( 0 ) / 4;
18
19
    // und wenn du dann rausgefunden hast, was du beim Timer machen musst
20
    // um die Freuqenz zu ändern, dann kriegst du den entsrechenden
21
    // Wert durch AUfruf von
22
    //  .... = ADC_Read( 1 );
23
  }
24
}
von Karl H. (kbuchegg)


Lesenswert?

Schau

Das hier
1
  TCCR1B = (1<<CS12);
2
  //Das Controllregister B (TCCR1B) ist für den Takt zuständig und kann ebenfalls 
3
  //durch Parameter aus den Tabellen bestimmt bzw. eingestellt werden.
ist ein sinnloser Kommentar.
Erstes stimmt er nicht (im TCCR1B Register sind auch noch andere Dinge 
untergebracht) und zweitens sagt er mir nix neues. Wenn ich wissen will, 
was das TCCR1B Register alles macht, dann schau ich im Datenblatt nach. 
Das ist beim Programmieren sowieso immer offen.

Aber was mich an dieser Stelle interessieren würde, ist das was du so 
verschämt mit 'aus den Tabellen bestimmt bzw. eingestellt werden' 
umschrieben hast. DAS interessiert mich! WAS hast du mit dem CS12 Bit 
eingestellt. Welcher Teilerfaktor ist das?

Den Beginn deines Progammes wird man sinnvollerweise so kommentieren.
1
int main (void)
2
{
3
  DDRB = (1 << PB1 );      // OC1A Pin auf Ausgang
4
5
  TCCR1A = (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0);  // 8 Bit PWM - phase correct, OC1A: set on up, clear on down
6
  TCCR1B = (1<<CS12);     // Prescaler 256


Jetzt stehen im Code die wichtigen Informationen, die ich zum Verstehen 
und für eventuelle Berechnungen brauche.
von Patrick W. (yellow_dog)


Lesenswert?

Vielen Dank! Ich bin immer offen für konstruktive Kritik!

Damit hast du auch Recht, die Doku dazu war etwas Lau. Ich habe bis 
vorige Woche nur SPS, C und HTML programmiert. Jetzt hat der 
Mikrocontroller meine volle Aufmerksamkeit bekommen - und es ist etwas 
anderes als C mit, ich sag mal, LabView. Muss mich damit erst mal näher 
beschaffen. Hab auch alles soweit mit ADC verstanden und PWM.. nur in 
der Umsetzung will es noch nicht klappen.
Werde, sobald das Programm nach meinen Vorstellungen läuft, die Doku 
überarbeiten :)

------------------------------------
ADC_Init();

  while( 1 ) {
    OCR1A = ADC_Read( 0 ) / 4;

    // und wenn du dann rausgefunden hast, was du beim Timer machen 
musst
    // um die Freuqenz zu ändern, dann kriegst du den entsrechenden
    // Wert durch AUfruf von
    //  .... = ADC_Read( 1 );

------------------------------------

ORC1A liest den ADC Wert ein und gibt ihn am Pin 1 des Ports B aus?

Angenommen, die Frequenz ist nur über das Poti steuerbar - dasselbe 
(oder Ähnlich) wirds dann mit der Impulsdauer funktionieren, richtig?
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.