Forum: Mikrocontroller und Digitale Elektronik 3 CH Pseudo Software PWM reagiert nicht auf Kanal 3.


von Marcel B. (gigi)


Lesenswert?

Huhu,

ich habe da ein kleines Programm zusammengeschrieben um 3 Kanäle per 
Pseudo PWM zu steuern.

Funktioniert soweit auch ganz gut, bis auf den Kanal 3, da tut sich 
garnichts. Der Tastendruck wird erkannt, allerdings ändert sich nichts 
an der Helligkeit.


Hat da jemand eine Idee ?

Hier der Code:
1
 
2
#define F_CPU 4800000UL
3
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include <avr/interrupt.h>
7
#include <stdint.h>
8
#include <avr/eeprom.h>
9
10
void pwmblau();
11
void pwmweiss();
12
void pwmluefter();
13
void delay_us();
14
void load();
15
16
uint16_t pwm_period = 500;  // *3 Kanäle  = 999
17
uint16_t EEMEM pwm_tB;    
18
uint16_t EEMEM pwm_tW;    
19
uint16_t EEMEM pwm_tL;
20
21
22
int main (void)
23
{
24
  
25
  GIMSK |= (1<< PCIE);
26
  PCMSK |= ((1<<PCINT2) | (1<<PCINT3) | (1<<PCINT5));
27
  DDRB |= ((1<<PB1) | (1<<PB0) | (1<<PB4));
28
  PORTB |=((1<<PB2) | (1<<PB3) | (1<<PB5));
29
  
30
  cli();
31
  load();
32
  _delay_ms(500);
33
  
34
  while( 1 )              // PWM Main - Routine
35
  {
36
    
37
    sei();
38
    pwmblau();
39
    pwmweiss();  
40
    pwmluefter();  
41
  }
42
43
  return 0;
44
}
45
46
47
ISR(PCINT0_vect)
48
{
49
  cli();
50
  PORTB |= (1<<PB1);
51
  PORTB |= (1<<PB0);
52
  PORTB |= (1<<PB4);
53
  _delay_ms(50);
54
    
55
    if (!(PINB & ( 1 << PINB2 )) )        //Check welcher Pin low
56
    {
57
    _delay_ms(250);  
58
    pwm_tB += 25;                // PulsDauer - Puls ON + 5%
59
      if (pwm_tB > 500)            // Wenn Puls ON > Periodendauer -> Puls On = 0;
60
        {
61
        pwm_tB = 0;  
62
        }  
63
        eeprom_write_word(&pwm_tB, pwm_tB);              //Speichert Wert von pwm_t[] an Adresse [n] im EEPROM
64
      }      
65
    
66
    if (!(PINB & ( 1 << PINB3 )) )        //Check welcher Pin low
67
    {
68
      _delay_ms(250);
69
      pwm_tW += 25;              // PulsDauer - Puls ON + 5%
70
      
71
      if (pwm_tW > 500)            // Wenn Puls ON > Periodendauer -> Puls On = 0;
72
      {
73
        pwm_tW = 0;
74
        }
75
      eeprom_write_word(&pwm_tW, pwm_tW);                  //Speichert Wert von pwm_t[] an Adresse [n] im EEPROM
76
      }
77
      
78
    if (!(PINB & ( 1 << PINB5 )) )        //Check welcher Pin low
79
    {
80
      _delay_ms(250);
81
      pwm_tL += 25;              // PulsDauer - Puls ON + 5%
82
      
83
      if (pwm_tL > 500)            // Wenn Puls ON > Periodendauer -> Puls On = 0;
84
      {
85
        pwm_tL = 0;
86
      }
87
      eeprom_write_word(&pwm_tL, pwm_tL);                  ///Speichert Wert von pwm_t[] an Adresse [n] im EEPROM
88
    }                  
89
  _delay_ms(50);      
90
  sei();
91
}
92
93
94
void pwmblau()
95
{
96
  PORTB &= ~(1<<PB1);
97
  delay_us(pwm_tB);          // Puls ON
98
  PORTB |= (1<<PB1);
99
  delay_us(pwm_period - pwm_tB);      // PulsDauer - Puls ON
100
}
101
102
103
void pwmweiss()
104
{
105
  PORTB &= ~(1<<PB0);
106
  delay_us(pwm_tW);           // Puls ON
107
  PORTB |= (1<<PB0);
108
  delay_us(pwm_period - pwm_tW);      // PulsDauer - Puls ON
109
}
110
111
112
void pwmluefter()
113
{
114
  PORTB &= ~(1<<PB4);
115
  delay_us(pwm_tL);          // Puls ON
116
  PORTB |= (1<<PB4);
117
  delay_us(pwm_period - pwm_tL);      // PulsDauer - Puls ON
118
}
119
120
121
122
void delay_us(int us )
123
{
124
  for (int i = 0; i < us; i++)
125
  {
126
    _delay_us(1);
127
  }
128
}
129
130
131
void load()
132
{
133
              
134
  pwm_tB = eeprom_read_word(&pwm_tB);    // Lesevorgang
135
                
136
  pwm_tW = eeprom_read_word(&pwm_tW);    // Lesevorgang
137
                
138
  pwm_tL = eeprom_read_word(&pwm_tL);    // Lesevorgang
139
}

LG,
Marcel

von Stefan F. (Gast)


Lesenswert?

Mir fällt sofort negativ auf, daß du große delays in der ISR benutzt. 
Das sollte man unterlassen, um Probleme zu vermeiden. Solange ich nicht 
weiß, wer denn Kanal 3 ist, prüfe ich das aber nicht weiter.

Welchen Mikrocontroller verwendest du?

Ich denke, dass du hier einen groben Designfehler hast. Du erzeugst 
nacheinander drei Impulse mit fester Dauer, wobei der Anteil von High 
und Low variiert wird. Jeder Impuls nimmt 33% der Gesamtzeit ein. Also 
ist die Pulsbreite 0% bis 33% (nicht 100%) war das so geplant?

von Stefan F. (Gast)


Lesenswert?

Noch was: Wenn du pwm_period als Variable definierst, solltest du das 
obere Limit für die drei PWM Werte nicht als Konstante in den Quelltext 
schreiben.

Stell Dir mal vor, was passiert, wenn ich pwm_period nur so zum Spaß auf 
400 ändere und dann ein paar mal auf die Tasten drücke.

von Stefan F. (Gast)


Lesenswert?

Ich glaube ich hab den Fehler gefunden, bin aber nicht ganz sicher:
1
uint16_t EEMEM pwm_tB;    
2
uint16_t EEMEM pwm_tW;    
3
uint16_t EEMEM pwm_tL;

Damit reservierst du drei Adressen im EEPROM. Nach dem Initialen 
Auslesen benutzt du sie aber wie Variablen im RAM. Du benutzt hier die 
drei Symbole doppelt. Meckert der Compiler da nicht? Benutze mal die 
Option -Wall (sollte man sie eh angewöhnen).

In Wirklichkeit brauchst du drei Plätze im EEPROM und drei Variablen im 
RAM, also 6 Symbole.

Ich denke, dass dein Code Schreibzugriffe ins RAM an zufällige Adressen 
generiert. Erstelle mal ein Assembler-Listing, da kann man das sicher 
gut sehen.

von Marcel B. (Gast)


Lesenswert?

Danke euch für die hilfreichen Antworten.

Der Designfehler kommt hin, da ist mir keine bessere Lösung in den Kopf 
gekommen.

Kann man das nicht auch besser lösen?

Mit dem dritten Kanal ist pwmluefter gemeint.

Die Eeprom Sache werde ich nochmal neu realisieren.Habe da etliche 
Lösungdansätze durch und bei diesert hier wird als einzige nicht 
gemeckert vom Compiler. Funktioniert auch soweit, nur die pwm luefter 
ändert sich bei keinem Tadtendruck.

von Carl D. (jcw2)


Lesenswert?


von Stefan F. (Gast)


Lesenswert?

Wie gesagt, wenn du Daten vom EEPROM ins RAM kopieren willst, brauchst 
du dazu Variablen, die im RAM liegen. Leuchtet ein, oder nicht?

von Marcel B. (gigi)


Lesenswert?

Stefanus F. schrieb:
> Wie gesagt, wenn du Daten vom EEPROM ins RAM kopieren willst, brauchst
> du dazu Variablen, die im RAM liegen. Leuchtet ein, oder nicht?

Ja aber selbstverständlich.

Ich bedanke mich für Eure Hilfe, habs mittlerweile hinbekommen. :)

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.