Forum: Mikrocontroller und Digitale Elektronik Attiny861a PWM Poti Problem


von hari (Gast)


Angehängte Dateien:

Lesenswert?

Ich möchte über Poti eine PWM (Tastgrad zwischen 0-100%) steuern. Macht 
aber nicht! Ich habe mal meinen Code gepostet.

Ich benutze Fast Pwm Modus. Den Poti habe ich in  Reihe mit eine 1k 
Widerstand geschaltet. Das Problem liegt bei der ADC Wandlung. Das 
Tastverhältnis ändert sich gar nicht, wenn ich den Poti drehe.

1
/*
2
 * GccLibrary1.c
3
 *
4
 * Created: 30.11.2014 17:31:17
5
 *  Author: **** *****
6
 * Tiefsetzsteller
7
 */ 
8
9
#include <avr/io.h>
10
#include <inttypes.h>
11
12
#define F_CPU 8000000UL
13
14
uint16_t readADC(double x) {
15
  uint8_t i;
16
  uint16_t result = 0;
17
  
18
  // Den ADC aktivieren und Teilungsfaktor auf 64 stellen
19
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
20
21
  // VCC als Referenzspannung verwenden (also VCC=5V)
22
  // ADC8, PB5
23
  ADMUX = (1<<MUX3); 
24
  
25
  // Den ADC initialisieren und einen sog. Dummyreadout machen
26
  ADCSRA |= (1<<ADSC);
27
  while(ADCSRA & (1<<ADSC));
28
  
29
  // Jetzt 3x die analoge Spannung and Kanal channel auslesen
30
  // und dann Durchschnittswert ausrechnen.
31
  for(i=0; i<3; i++) {
32
    // Eine Wandlung
33
    ADCSRA |= (1<<ADSC);
34
    // Auf Ergebnis warten...
35
    while(ADCSRA & (1<<ADSC));
36
    
37
    result += ADCW;
38
  }
39
  
40
  // ADC wieder deaktivieren
41
  ADCSRA &= ~(1<<ADEN);
42
  
43
  result /= 3;
44
  
45
  result=x*(double)result;
46
  return result;
47
}
48
49
//Timer 1 (PWM) initialisieren
50
void timer1_pwm(uint16_t result){
51
  PORTB=0;
52
  DDRB=(1<<PB0);
53
  OCR1A=0; 
54
  
55
  //Timer1 Konfigurieren
56
  TCCR1A=(1<<COM1A1) | (1<<PWM1A); //PWM, OC1A
57
  TCCR1B=(1<<CS10); //F_CPU ohne Prescaler
58
  TCCR1D=(0<<WGM11) | (0<<WGM10); //Fast PWM
59
  OCR1A=444-result; //default
60
  
61
  //TOP Setzen, 18kHz
62
  TC1H=444 >> 8;
63
  OCR1C=444 & 0xFF;
64
}
65
66
int main(void)
67
{
68
  double x=0.867;
69
  
70
    //uint16_t readADC();  //Auslesen der analogen Spannungen an PB5,
71
    // also ADC8. In result steht das Ergebnis.
72
  
73
  while(1){          
74
    timer1_pwm(readADC(x));  
75
    return 0;
76
}
77
}

von Steffen (Gast)


Lesenswert?

Du musst schon das Poti am ADC anschliesen.

von hari (Gast)


Lesenswert?

Steffen schrieb:
> Du musst schon das Poti am ADC anschliesen.


Ich habe ja schon angeschlossen. PB5 ist ja ein adc eingang.

von Thomas E. (thomase)


Lesenswert?

hari schrieb:
> Den Poti habe ich in  Reihe mit eine 1k
> Widerstand geschaltet.

Welchen Sinn soll das haben?

Warum initialisierst du alles jedes mal wieder neu?

ADC und Timer werden einmal initialisiert und im Programmlauf wird nur 
noch das OCR-Register entsprechend dem ADC-Wert aktualisert.

mfg.

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


Lesenswert?

Bei der derzeitigen Beschaltung wirst du übrigens nicht über VCC/2 am 
ADC Eingang hinauskommen. Entweder ersetzt du den 1k Widerstand durch 
eine Brücke oder benutzt die interne 2,56V Referenz des Tiny.

von ariba (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> hari schrieb:
>> Den Poti habe ich in  Reihe mit eine 1k
>> Widerstand geschaltet.
>
> Welchen Sinn soll das haben?
>
> Warum initialisierst du alles jedes mal wieder neu?
>
> ADC und Timer werden einmal initialisiert und im Programmlauf wird nur
> noch das OCR-Register entsprechend dem ADC-Wert aktualisert.
>
> mfg.

Ich habe den Code nochmal verändert. Das Problem ist, Tastverhältnis 
bleibt immer gleich. Irgendwas stimmt mit der ADC Wandlung nicht. Ich 
drehe den Poti aber alles bleibt gleich. Ich kann die Signale 
Oszilloskopieren.
1
/*
2
 * GccLibrary1.c
3
 *
4
 * Created: 30.11.2014 17:31:17
5
 *  Author: **** *****
6
 * Tiefsetzsteller
7
 */ 
8
9
#include <avr/io.h>
10
#include <inttypes.h>
11
12
#define F_CPU 8000000UL
13
14
uint16_t readADC(double x) {
15
  uint8_t i;
16
  uint16_t result = 0;
17
  
18
  // Den ADC aktivieren und Teilungsfaktor auf 64 stellen
19
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
20
21
  // VCC als Referenzspannung verwenden (also VCC=5V)
22
  // ADC8, PB5
23
  ADMUX = (1<<MUX3); 
24
  
25
  // Den ADC initialisieren und einen sog. Dummyreadout machen
26
  ADCSRA |= (1<<ADSC);
27
  while(ADCSRA & (1<<ADSC));
28
  
29
  // Jetzt 3x die analoge Spannung and Kanal channel auslesen
30
  // und dann Durchschnittswert ausrechnen.
31
  for(i=0; i<3; i++) {
32
    // Eine Wandlung
33
    ADCSRA |= (1<<ADSC);
34
    // Auf Ergebnis warten...
35
    while(ADCSRA & (1<<ADSC));
36
    
37
    result += ADCW;
38
  }
39
  
40
  // ADC wieder deaktivieren
41
  ADCSRA &= ~(1<<ADEN);
42
  
43
  result /= 3;
44
  
45
  result=x*(double)result;
46
  return result;
47
}
48
49
int main(void)
50
{
51
    PORTB=0;
52
    DDRB=(1<<PB1);
53
    
54
    //Timer1 Konfigurieren
55
    TCCR1A=(1<<COM1A1) | (1<<PWM1A); //PWM, OC1A
56
    TCCR1B=(1<<CS10); //F_CPU ohne Prescaler
57
    TCCR1D=(0<<WGM11) | (0<<WGM10); //Fast PWM
58
    OCR1A=0; //default
59
    
60
    //TOP Setzen, 18kHz
61
    TC1H=444 >> 8;
62
    OCR1C=444 & 0xFF;
63
    
64
    double x=0.867;
65
  
66
    //uint16_t readADC();  //Auslesen der analogen Spannungen an PB5,
67
    // also ADC8. In result steht das Ergebnis.
68
  
69
  while(1){          
70
    OCR1A=readADC(x);  
71
    return 0;
72
}
73
}

von ariba (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> hari schrieb:
>> Den Poti habe ich in  Reihe mit eine 1k
>> Widerstand geschaltet.
>
> Welchen Sinn soll das haben?
>
> Warum initialisierst du alles jedes mal wieder neu?
>
> ADC und Timer werden einmal initialisiert und im Programmlauf wird nur
> noch das OCR-Register entsprechend dem ADC-Wert aktualisert.
>
> mfg.

Nur beim Einschalten nimmt er den ADC Wert von Poti und danach nicht 
mehr!

von Axel Z. (axel_z)


Lesenswert?

Nimm mal das return 0 aus der while-Schleife heraus. Dann hat das 
Programm wenigstens die Chance mehr als einmal zu laufen.

Gruß

von ariba (Gast)


Lesenswert?

Axel Z. schrieb:
> Nimm mal das return 0 aus der while-Schleife heraus. Dann hat das
> Programm wenigstens die Chance mehr als einmal zu laufen.
>
> Gruß

Das habe ich übersehen. Funktioniert jetzt.

Ich möchte ein PWM Signal (Fast PWM, 10bit) erzeugen. PWM Frequenz soll 
ca. 18Khz betragen. Das Problem ist, dass nur ca. 2,5khz signal erzeugt 
wird. Wo mache ich fehler?

Mein (Teil)Code:
1
#include <avr/io.h>
2
#include <inttypes.h>
3
4
#define F_CPU 8000000UL
5
6
uint16_t readADC(double x) {
7
  blabla
8
}
9
10
int main(void)
11
{
12
    PORTB=0;
13
    DDRB=(1<<PB1);
14
    
15
    //Timer1 Konfigurieren
16
    TCCR1A=(1<<COM1A1) | (1<<PWM1A); //PWM, OC1A
17
    TCCR1B=(1<<CS10); //F_CPU ohne Prescaler
18
    TCCR1D=(0<<WGM11) | (0<<WGM10); //Fast PWM
19
    
20
    OCR1A=0; //default
21
    
22
    //TOP Setzen, 18kHz
23
    TC1H=444 >> 8;
24
    OCR1C=444 & 0xFF;
25
    
26
    double x=0.4333;
27
  
28
    //uint16_t readADC();  //Auslesen der analogen Spannungen an PB5,
29
    // also ADC8. In result steht das Ergebnis.
30
  
31
  while(1){  
32
    TC1H=readADC(x) >> 8;        
33
    OCR1A=readADC(x) & 0xFF;  
34
}
35
return 0;
36
}

von MArtin (Gast)


Lesenswert?

ISt bestimmt noch die /8 FUse aktiviert, dein Tiny läuft auf 1MHz

von ariba (Gast)


Angehängte Dateien:

Lesenswert?

MArtin schrieb:
> ISt bestimmt noch die /8 FUse aktiviert, dein Tiny läuft auf 1MHz

Ich habe ein Screenshot hinzugefügt. Was meinst du mit "/8 FUse"?

von Udo S. (urschmitt)


Lesenswert?

ariba schrieb:
> #define F_CPU 8000000UL

Das ist nicht zum Einstellen des Prozessortaktes, sondern dient nur dazu 
dass dein Programm weiss wie schnell dein Prozessor tatsächlich taktet. 
Die tatsächliche Taktfrequenz musst du entsprechend konfigurieren 
(Fuses) bzw. über einen Quarz oder externen Oszillator festlegen.

von Maik S. (yellowbird)


Lesenswert?

Stimmen alle Bezeichnungen oder hast du den Teil für die PWM Erzuegung 
kopiert, von einem "älteren" Attiny / Mega ?

von ariba (Gast)


Lesenswert?

Maik S. schrieb:
> Stimmen alle Bezeichnungen oder hast du den Teil für die PWM
> Erzuegung
> kopiert, von einem "älteren" Attiny / Mega ?

Ich habe nichts kopiert. Ich habe anhand Datenblatt konfiguriert.

von ariba (Gast)


Lesenswert?

ariba schrieb:
> Maik S. schrieb:
>> Stimmen alle Bezeichnungen oder hast du den Teil für die PWM
>> Erzuegung
>> kopiert, von einem "älteren" Attiny / Mega ?
>
> Ich habe nichts kopiert. Ich habe anhand Datenblatt konfiguriert.

Wo liegt der Fehler?

von Ingo (Gast)


Lesenswert?

Nimm mal das Häkchen bei "DIV8" weg

von Ingo (Gast)


Lesenswert?

CKDIV8 meinte ich

von ariba (Gast)


Lesenswert?

Ingo schrieb:
> CKDIV8 meinte ich

hat funktioniert. danke

von ariba (Gast)


Lesenswert?

Ingo schrieb:
> CKDIV8 meinte ich

Er erzeugt aber jetzt ca. 15khz. Theoretisch sollte 18khz raus kommen. 
Ist soviel abweichung normal?

fpwm=1/((1/8mhz)*444)

von Maik S. (yellowbird)


Lesenswert?

Ich hatte mal ein Problem, dass die Bezeichnungen anders hießen bei den 
"neueren" Tinys. Hab mich anhand von Tutorials totgesucht.

Scheint hier aber zu passen.


    TC1H=readADC(x) >> 8;
    OCR1A=readADC(x) & 0xFF;

TC1H ist IIRC 2 Bit groß
OCR1A ist IIRC 8 Bit groß

Ich verstehe nicht, was hier passieren soll.

von Ingo (Gast)


Lesenswert?

Nein ist nicht normal

von ariba (Gast)


Lesenswert?

Maik S. schrieb:
> Ich hatte mal ein Problem, dass die Bezeichnungen anders hießen
> bei den
> "neueren" Tinys. Hab mich anhand von Tutorials totgesucht.
>
> Scheint hier aber zu passen.
>
>     TC1H=readADC(x) >> 8;
>     OCR1A=readADC(x) & 0xFF;
>
> TC1H ist IIRC 2 Bit groß
> OCR1A ist IIRC 8 Bit groß
>
> Ich verstehe nicht, was hier passieren soll.

Ich möchte ja 10bit Fast PWM programmieren. OCR1A ist 8 Bit groß. Die 
anderen 2 bits liegen im Register TC1H. Wenn der Timer diesen Wert 
erreich, soll den Pegel von 5V auf 0V setzen. So habe ich verstanden.
Der Timer zählt von 0 bis 444.

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.