Attiny861a PWM Poti Problem

Gast #3910933
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
}
Angehängte Dateien:
Gast #3911911
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
}
Gast #3911992
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!
Gast #3912039
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
}
#3912134
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.
Gast #3912153
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren