Forum: Mikrocontroller und Digitale Elektronik ATmega8 - Ausgabesignal per Taster toggeln


von Opto (Gast)


Lesenswert?

Hallo, ich habe ein Problem mit meinem Programm und komme nach mehreren 
Stunden rumprobieren nicht auf die Lösung. Es geht darum, dass der 
Controller bei gedrückthalten der Taste immer wieder den selben Befehl 
per IR-Diode sendet. Funktioniert auch wunderbar.

Wird die Taste aber nochmal gedrückt soll das Signal etwas abgeändert 
werden. Es soll das dritte Startbit getoggelt werden. Das passiert 
allerdings nicht. Es wird immer dasselbe Signal gesendet. Der Controller 
toggelt die Variable state nicht. Woran kann das liegen?

Taster ist mit einem Pulldown-Widerstand auf GND gezogen, parallel dazu 
ein Kondensator.
1
         5V
2
__       |  
3
   |      /-
4
µC |     |
5
   |     |
6
   |-------------
7
   |     |      |
8
   |    | |    _|_
9
   |    |R|    _C_
10
   |     |      |
11
         |______|
12
             |
13
            GND
1
#include <avr/io.h>
2
#define F_CPU 8000000UL                
3
#include <util/delay.h>
4
      
5
6
int main(void)
7
{  
8
9
  volatile uint8_t state = 0;  
10
  
11
  DDRB = (1 << PORTB1);              // PB1 als Ausgang
12
  DDRC &= ~(1<<PC5);                // PC5 als Eingang
13
  DDRC &= ~(1<<PC4);                // PC4 als Eingang
14
  DDRC &= ~(1<<PC3);                // PC3 als Eingang
15
  
16
  
17
  TCCR1A |= (1 << WGM12) | (1<<WGM11) ;      // Fast-PWM mit ICR1 als TOP
18
  TCCR1B |= (1<< CS10) |(1<<WGM13);        // Prescaler = 1
19
  
20
                          // ICR1 = F_CPU/(2*Prescaler*(F_PWM+1)
21
  ICR1 = 108;                    // Periode PWM => 38kHz
22
  OCR1A = 27;                    // ICRI/4  => 25% PWM
23
  
24
    while(1){
25
    
26
    if(PINC & ( 1<<PINC5)){            // wenn Taste gedrückt:
27
      if(state==1) state=0;          // toggle state
28
      else if(state==0) state=1;
29
                  
30
      while( (PINC & ( 1<<PINC5)) ){      // solange Taste 1 gedrückt: bleibe in Schleife
31
        if (state==1){sendStartSeq1();}    // wenn state == 1 => Startsequenz = 1 1 1
32
        else if (state==0) {sendStartSeq0();}  // wenn state == 0 => Startsequenz = 1 1 0 
33
        sendDevAddr();            // Sende Device-Adresse, hier: 0 0 0 0 0
34
        sendData1();            // Sende Daten, hier: 0 1 0 0 0 0  
35
        _delay_ms(114);            // warte 114ms = Pause für die Dauer von ca 64 Bits
36
      }
37
        
38
}      
39
  return 0;                    // wird nie erreicht
40
}
41
42
43
44
///////////////////////////////// FUNKTIONEN ////////////////////////////////////
45
46
void sendOne(void) {
47
  _delay_us(889);
48
  TCCR1A |= (1<< COM1A1);
49
  _delay_us(889);
50
  TCCR1A &= ~(1<< COM1A1);
51
}
52
53
void sendNull(void) {
54
  TCCR1A |= (1<< COM1A1);
55
  _delay_us(889);
56
  TCCR1A &= ~(1<< COM1A1);
57
  _delay_us(889);
58
}
59
60
61
void sendStartSeq1(void){
62
  sendOne();
63
  sendOne();
64
  sendOne();
65
}
66
void sendStartSeq0(void){
67
  sendOne();
68
  sendOne();
69
  sendNull();
70
}  
71
72
void sendDevAddr(void){
73
  sendNull();  
74
  sendNull();  
75
  sendNull();  
76
  sendNull();  
77
  sendNull();
78
}
79
80
void sendData1(void){
81
  sendNull();
82
  sendOne();
83
  sendNull();  
84
  sendNull();  
85
  sendNull();  
86
  sendNull();
87
  
88
}

von hufnala (Gast)


Lesenswert?

Hi,

da fallen mir mehrere Themen auf:

1) Entprellung?
2) Warum die 2 Abfragen mit dem while, irgendwie haengt er dann auch
   In der 2. Scleife.
3) Der Vergleich mit 1<<PC5 sieht seltsam aus, da bin ich mir nicht 
sicher, schau dir dass nochmal an.

//hufnala

von Easylife (Gast)


Lesenswert?

main() kann so nicht compilieren. Da fehlt irgendwo eine "}".
Bitte tatsächlichen Code posten.

von Opto (Gast)


Lesenswert?

Hallo,

der Kondensator war eigentlich zum Entprellen gedacht.

Es wird erst in die if-Abfrage gesprungen, wenn die Taste 1 tatsächlich 
gedrückt ist. Erst dann soll das state getoggelt werden. Wenn getoggelt 
wurde soll das Programm solange in der While-Schleife hängen wie die 
Taste gedrückt ist (permanenten Senden der gleichen Sequenz). Beim 
loslassen soll das Programm aus der while-Schleife raus, zurück in die 
main. Wird die Taste jetzt nochmal betätigt sollte die Variable state 
getoggelt werden, sodass eine andere Startsequenz als beim letzten 
drücken gesendet wird, jedoch passiert dies nicht.


Der auskommentierte Bereich ist nicht so von Interesse, es wurde viel 
ausprobiert... Der komplette Code ist:
1
#include <avr/io.h>
2
#define F_CPU 8000000UL                
3
#include <util/delay.h>
4
#include <stdbool.h>
5
6
7
8
9
int main(void)
10
{  
11
12
  
13
  volatile int state =0;  
14
  
15
  DDRB = (1 << PORTB1);              // PB1 als Ausgang
16
  DDRC &= ~(1<<PC5);                // PC5 als Eingang
17
  
18
  
19
  DDRC &= ~(1<<PC4);                // PC4 als Eingang
20
  DDRC &= ~(1<<PC3);                // PC3 als Eingang
21
  
22
  
23
  TCCR1A |= (1 << WGM12) | (1<<WGM11) ;
24
                       // Fast-PWM mit ICR1 als TOP
25
  TCCR1B |= (1<< CS10) |(1<<WGM13);  // Prescaler = 1
26
  
27
                          
28
                          // ICR1 = F_CPU/(2*Prescaler*(F_PWM+1)
29
  ICR1 = 108;                    // Periode PWM => 38kHz
30
  OCR1A = 27;                    // ICRI/4  => 25% PWM
31
  
32
    while(1){
33
    
34
    
35
    
36
    if(PINC & ( 1<<PINC5)){    
37
      if(state==1) state=0;
38
      else if(state==0) state=1;
39
                  
40
      while( (PINC & ( 1<<PINC5)) ){        // solange Taste 1 gedrückt: bleibe in Schleife
41
        if (state==1){sendStartSeq1();}      // wenn i == 1 => Startsequenz = 1 1 1
42
        if (state==0) {sendStartSeq0();}    // wenn i == 0 => Startsequenz = 1 1 0 
43
        sendDevAddr();            // Sende Device-Adresse, hier: 0 0 0 0 0
44
        sendData1();            // Sende Daten, hier: 0 1 0 0 0 0  
45
        _delay_ms(114);            // warte 114ms = Pause für die Dauer von ca 64 Bits
46
      }
47
    
48
      
49
    /*if(PINC & ( 1<<PINC4)){            // Prüfe ob Taste 2 (mitte) gedrückt
50
      if(state==1) state=0;
51
      else if(state==0) state=1;                
52
      
53
       while( PINC & ( 1<<PINC4)){        
54
        if (state==1){sendStartSeq1();}              
55
        if (state==0){sendStartSeq0();}                
56
        sendDevAddr();            
57
        sendData1();            // Sende Daten, hier: 0 1 0 0 0 0  
58
        _delay_ms(114);            
59
      }
60
    }    
61
    
62
    if(PINC & ( 1<<PINC3)){            // Prüfe ob Taste 3 (rechts) gedrückt
63
      //i=~i;                  
64
      while( PINC & ( 1<<PINC3)){        
65
        if (i){                
66
        sendStartSeq1();          
67
        } else sendStartSeq0();        
68
        sendDevAddr();            
69
        sendData1();            // Sende Daten, hier: 0 1 0 0 0 0  
70
        _delay_ms(114);            
71
      }
72
    }*/    
73
          
74
          
75
      
76
  }      
77
  return 0;                    // wird nie erreicht
78
}
79
80
81
82
///////////////////////////////// FUNKTIONEN ////////////////////////////////////
83
84
void sendOne(void) {
85
  _delay_us(889);
86
  TCCR1A |= (1<< COM1A1);
87
  _delay_us(889);
88
  TCCR1A &= ~(1<< COM1A1);
89
}
90
91
void sendNull(void) {
92
  TCCR1A |= (1<< COM1A1);
93
  _delay_us(889);
94
  TCCR1A &= ~(1<< COM1A1);
95
  _delay_us(889);
96
}
97
98
99
void sendStartSeq1(void){
100
  sendOne();
101
  sendOne();
102
  sendOne();
103
}
104
void sendStartSeq0(void){
105
  sendOne();
106
  sendOne();
107
  sendNull();
108
}  
109
110
void sendDevAddr(void){
111
  sendNull();  
112
  sendNull();  
113
  sendNull();  
114
  sendNull();  
115
  sendNull();
116
}
117
118
void sendData1(void){
119
  sendNull();
120
  sendOne();
121
  sendNull();  
122
  sendNull();  
123
  sendNull();  
124
  sendNull();
125
  
126
}

von Opto (Gast)


Lesenswert?

Es fehlt tatsächlich eine Klammer, die das erste if abschließt, sorry!
1
 if(PINC & ( 1<<PINC5)){    
2
      if(state==1) state=0;
3
      else if(state==0) state=1;
4
                  
5
      while( (PINC & ( 1<<PINC5)) ){        // solange Taste 1 gedrückt: bleibe in Schleife
6
        if (state==1){sendStartSeq1();}      // wenn i == 1 => Startsequenz = 1 1 1
7
        if (state==0) {sendStartSeq0();}    // wenn i == 0 => Startsequenz = 1 1 0 
8
        sendDevAddr();            // Sende Device-Adresse, hier: 0 0 0 0 0
9
        sendData1();            // Sende Daten, hier: 0 1 0 0 0 0  
10
        _delay_ms(114);            // warte 114ms = Pause für die Dauer von ca 64 Bits
11
      }
12
 }

von Karl H. (kbuchegg)


Lesenswert?

Deine Entprellung erinnert mich doch sehr an die Entprellung auf dem 
Pollin Board

http://www.mikrocontroller.net/articles/Diskussion:Pollin_ATMEL_Evaluations-Board

die dazu führen kann, dass der µC bei einem Tastendruck abschmiert. Was 
so ganz nebenbei und zwanglos dein Nicht-Toggeln erklären würde. Denn 
nach einem Reset geht alles wieder von vorne los.

: Bearbeitet durch User
von Easylife (Gast)


Lesenswert?

Deine schlechte Formatierung lässt es dich nicht erkennen:
es fehlt eine "}" (immer noch).

Ich habe mal etwas nachgeholfen:
1
int main(void)
2
{
3
  volatile int state =0;
4
5
  DDRB = (1 << PORTB1);              // PB1 als Ausgang
6
  DDRC &= ~(1<<PC5);                // PC5 als Eingang
7
8
9
  DDRC &= ~(1<<PC4);                // PC4 als Eingang
10
  DDRC &= ~(1<<PC3);                // PC3 als Eingang
11
12
13
  TCCR1A |= (1 << WGM12) | (1<<WGM11) ;
14
  // Fast-PWM mit ICR1 als TOP
15
  TCCR1B |= (1<< CS10) |(1<<WGM13);  // Prescaler = 1
16
17
18
  // ICR1 = F_CPU/(2*Prescaler*(F_PWM+1)
19
  ICR1 = 108;                    // Periode PWM => 38kHz
20
  OCR1A = 27;                    // ICRI/4  => 25% PWM
21
22
  while(1) {
23
    if(PINC & ( 1<<PINC5)) {
24
      if(state==1) state=0;
25
      else if(state==0) state=1;
26
27
      while( (PINC & ( 1<<PINC5)) ) {       // solange Taste 1 gedrückt: bleibe in Schleife
28
        if (state==1) {
29
          sendStartSeq1();   // wenn i == 1 => Startsequenz = 1 1 1
30
        }
31
        if (state==0) {
32
          sendStartSeq0();   // wenn i == 0 => Startsequenz = 1 1 0
33
        }
34
        sendDevAddr();            // Sende Device-Adresse, hier: 0 0 0 0 0
35
        sendData1();            // Sende Daten, hier: 0 1 0 0 0 0
36
        _delay_ms(114);            // warte 114ms = Pause für die Dauer von ca 64 Bits
37
      }
38
    }
39
    return 0;                    // wird nie erreicht
40
  }

von Opto (Gast)


Lesenswert?

Würde es was bringen einen Widerstand direkt hinter den Schalter zu 
klemmen um den Strom zu begrenzen?

Ich dachte eigentlich, dass der Eingang an sich schon ziemlich hochohmig 
ist und nicht viel hineinfließt.

Die Entprellschaltung besteht aus dem Pulldown von 10k und dem 22nF.

von Easylife (Gast)


Lesenswert?

Opto, was ist denn nun mit der Klammer?
Der Code compiliert so nicht, und wie du vielleicht siehst, steht
"return 0;"
in der while-schleife.
Was sollen also alle weiteren Fragen?

von Uwe (de0508)


Lesenswert?

Hallo,

Opto schrieb:

> Die Entprellschaltung besteht aus dem Pulldown von 10k und dem 22nF.

nein das ist falsch !

Eine R-C Entprellung besteht aus einem Tiefpass, das ist etwas anderes.

von Easylife (Gast)


Lesenswert?

Uwe S. schrieb:
>> Die Entprellschaltung besteht aus dem Pulldown von 10k und dem 22nF.
>
> nein das ist falsch !

Na, geht schon so.
Der Kondesator lädt schnell auf, und wird langsam entladen.
Ein Serienwiderstand von 100R würde dem Schaltkontakt allerdings ein 
längeres Leben bescheren.

Problem ist aber nach wie vor der Code... und ich höre nicht auf zu 
quengeln ;-)

von Karl H. (kbuchegg)


Lesenswert?

Easylife schrieb:
> Uwe S. schrieb:
>>> Die Entprellschaltung besteht aus dem Pulldown von 10k und dem 22nF.
>>
>> nein das ist falsch !
>
> Na, geht schon so.
> Der Kondesator lädt schnell auf

Das Problem ist, dass er zu schnell auflädt!
De facto schaltet man mit dem Taster einen kurz anliegenden Kurzschluss.

Die Leute, die das original Pollin Board mit genau dieser 
Hardware-Entprellung haben, bauen die nicht ohne Grund um.

: Bearbeitet durch User
von Easylife (Gast)


Lesenswert?

deswegen ja 100R in serie zum C...

von Karl H. (kbuchegg)


Lesenswert?

Easylife schrieb:
> deswegen ja 100R in serie zum C...

Ah. Den hab ich bei dir überlesen.
Ja klar. Der würde helfen
1
     Vcc
2
      |
3
       /
4
      |
5
  ----+--+---+
6
         |   |
7
        10k  100
8
         |   |
9
         |   C
10
         |   |
11
  -------+---+---- GND
(oder so ähnlich. Auf jeden Fall nicht den C per Taster direkt an Vcc 
schalten lassen)


Abgesehen von der Klammer, was hast du im Code sonst noch entdeckt? Ein 
paar Sachen könnte man einfacher schreiben, aber im grossen und ganzen 
sollte das funktionieren. D.h. wenn dann irgendwann mal der µC nicht bei 
einem Tastendruck abschmiert.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> Abgesehen von der Klammer,

die natürlich an der richtigen Stelle eingefügt werden muss.
Was wiederrum den Wert von sauberen Einrückungen mehr als deutlich 
unterstreicht!

von Opto (Gast)


Lesenswert?

Okay, also hier nochmal der gesamte Code, ohne Klammerfehler (compiliert 
bei mir zumindest ohne Probleme) und hoffentlich besserer Formatierung.


Wo würde der µC-Eingang sein? Kann es wirklich am C ohne Vorwiderstand 
liegen, dass der Controller abschmiert und sich resettet?

     Vcc
      |
       /
      |
  µC--+--+---+
  hier?  |   |
        10k  100
         |   |
         |   C
         |   |
  -------+---+---- GND


Danke schonmal :)

1
#include <avr/io.h>
2
#define F_CPU 8000000UL                
3
#include <util/delay.h>
4
5
6
void sendOne(void);
7
void sendNull(void);
8
void sendStartSeq1(void);
9
void sendStartSeq0(void);
10
void sendDevAddr(void);
11
void sendData1(void);
12
13
14
15
int main(void)
16
{  
17
  volatile int state =0;  
18
  
19
  DDRB = (1 << PORTB1);              // PB1 als Ausgang
20
  DDRC &= ~(1<<PC5);                // PC5 als Eingang
21
  DDRC &= ~(1<<PC4);                // PC4 als Eingang
22
  DDRC &= ~(1<<PC3);                // PC3 als Eingang
23
  
24
  
25
  TCCR1A |= (1 << WGM12) | (1<<WGM11) ;      // Fast-PWM mit ICR1 als TOP
26
                       
27
  TCCR1B |= (1<< CS10) |(1<<WGM13);        // Prescaler = 1
28
                            
29
                          // ICR1 = F_CPU/(2*Prescaler*(F_PWM+1)
30
  ICR1 = 108;                    // Periode PWM => 38kHz
31
  OCR1A = 27;                    // ICRI/4  => 25% PWM
32
  
33
    while(1)
34
  {
35
    
36
    if(PINC & ( 1<<PINC5))    
37
    {  
38
      if(state==1) {state=0;}
39
      else if(state==0) {state=1;}
40
                  
41
      while( (PINC & ( 1<<PINC5)) )        // solange Taste 1 gedrückt: bleibe in Schleife
42
      {        
43
        if (state==1){sendStartSeq1();}      // wenn i == 0xff => Startsequenz = 1 1 1
44
        if (state==0) {sendStartSeq0();}    // wenn i = 0x00 => Startsequenz = 1 1 0 
45
        sendDevAddr();              // Sende Device-Adresse, hier: 0 0 0 0 0
46
        sendData1();              // Sende Daten, hier: 0 1 0 0 0 0  
47
        _delay_ms(114);              // warte 114ms = Pause für die Dauer von ca 64 Bits
48
      }
49
    }  
50
    
51
    /*
52
    if(PINC & ( 1<<PINC4))              // Prüfe ob Taste 2 (mitte) gedrückt
53
    {           
54
      if(state==1) {state=0;}
55
      else if(state==0) {state=1;}              
56
      
57
      while( PINC & ( 1<<PINC4))
58
      {        
59
        if (state==1){sendStartSeq1();}              
60
        if (state==0){sendStartSeq0();}                
61
        sendDevAddr();            
62
        sendData1();              // Sende Daten, hier: 0 1 0 0 0 0  
63
        _delay_ms(114);            
64
      }
65
     }    
66
    
67
    if(PINC & ( 1<<PINC3))              // Prüfe ob Taste 3 (rechts) gedrückt
68
    {           
69
      if(state==1) {state=0;}
70
      else if(state==0) {state=1;}              
71
      
72
      while( PINC & ( 1<<PINC3))
73
      {        
74
        if (state==1){sendStartSeq1();}              
75
        if (state==0){sendStartSeq0();}                
76
        sendDevAddr();            
77
        sendData1();              // Sende Daten, hier: 0 1 0 0 0 0  
78
        _delay_ms(114);            
79
      }
80
     } */  
81
    
82
    
83
            
84
  }      
85
  return 0;                      // wird nie erreicht
86
}
87
88
89
90
///////////////////////////////// FUNKTIONEN ////////////////////////////////////
91
92
void sendOne(void) {
93
  _delay_us(889);
94
  TCCR1A |= (1<< COM1A1);
95
  _delay_us(889);
96
  TCCR1A &= ~(1<< COM1A1);
97
}
98
99
void sendNull(void) {
100
  TCCR1A |= (1<< COM1A1);
101
  _delay_us(889);
102
  TCCR1A &= ~(1<< COM1A1);
103
  _delay_us(889);
104
}
105
106
107
void sendStartSeq1(void){
108
  sendOne();
109
  sendOne();
110
  sendOne();
111
}
112
void sendStartSeq0(void){
113
  sendOne();
114
  sendOne();
115
  sendNull();
116
}  
117
118
void sendDevAddr(void){
119
  sendNull();  
120
  sendNull();  
121
  sendNull();  
122
  sendNull();  
123
  sendNull();
124
}
125
126
void sendData1(void){
127
  sendNull();
128
  sendOne();
129
  sendNull();  
130
  sendNull();  
131
  sendNull();  
132
  sendNull();
133
  
134
}

von Karl H. (kbuchegg)


Lesenswert?

Opto schrieb:

> Wo würde der µC-Eingang sein? Kann es wirklich am C ohne Vorwiderstand
> liegen, dass der Controller abschmiert und sich resettet?

Du kannst es ja mal ausprobieren. Mit einer anderen LED (aber nicht 
Infrarot), bei der du auch was siehst.
1
> int main(void)
2
> {
3
>   volatile int state =0;
4
> 
5
>   DDRB = (1 << PORTB1);              // PB1 als Ausgang
6
7
    DDRB |= ( 1 << PB2 );
8
9
    PORTB |= ( 1 << PB2 );
10
    _delay_ms( 500 );
11
    PORTB &= ~( 1 << PB2 );
12
    _delay_ms( 500 );
13
    PORTB |= ( 1 << PB2 );
14
    _delay_ms( 500 );
15
16
>   DDRC &= ~(1<<PC5);                // PC5 als Eingang
17
....

schliess eine LED an PB2 an (oder ändere um auf einen anderen noch 
freien Pin) und beobachte die LED. Wenn sie bei einem Tastendruck 
flackert, dann ist dein µC abgeschmiert und hat sich gerade resettet.

Mit so einer LED kann man ganz leicht Dinge sichtbar machen :-)

: Bearbeitet durch User
von Easylife (Gast)


Lesenswert?

Opto schrieb:
> Wo würde der µC-Eingang sein? Kann es wirklich am C ohne Vorwiderstand
> liegen, dass der Controller abschmiert und sich resettet?

Die Beschaltung des uC mit Taster ist OK so.

Dass "der Controller abschmiert und sich resettet" ist jetzt aber neu, 
oder?
Ursprünglich sagtest du:

Opto schrieb:
> Das passiert
> allerdings nicht. Es wird immer dasselbe Signal gesendet. Der Controller
> toggelt die Variable state nicht. Woran kann das liegen?

Poste bitte mal den Schaltplan und das Layout.
Ich vermute, dass du hier mit elektrischen Problemen kämpfst.
Den Code könnte man zwar optimieren, er müsste aber funktionieren.

von Opto (Gast)


Lesenswert?

Hallo, ihrlagt mit der Vermutung, der µC würde sich permanent resetten 
goldrichtig. Vielen Danke für den Tipp! Habe dann wie empfohlen einen 
390Ohm Widerstand (war kein anderer kleiner R da) in Reihe mit dem 
Kondensator gehängt und siehe da, es funktioniert genau wie es soll.

Jemand sagte man könnte noch optimieren. Wie genau? Es läuft zwar, aber 
muss auch demnächst mal präsentiert werden :)

von Karl H. (kbuchegg)


Lesenswert?

Opto schrieb:

> Jemand sagte man könnte noch optimieren.

Na ja.
'Optimieren' ist das falsche Wort. 'Weniger umständlich' trifft es eher.

Die Variable 'state' kann bei dir nur 2 Werte haben. Entweder sie ist 0 
oder sie ist 1.

Dann kannst du aber zb das hier
1
      if(state==1) state=0;          // toggle state
2
      else if(state==0) state=1;

durch das hier ersetzen
1
      state = 1 - state;

hat state den Wert 0, denn ergibt 1 - 0 den neuen Wert 1. Hat state den 
Wert 1, dann ergibt 1 - 1 den neuen Wert 0. Aus 0 wird 1, aus 1 wird 0. 
Genau wie gefordert.

Das hier
1
        if (state==1){sendStartSeq1();}
2
        if (state==0) {sendStartSeq0();}

state kann nur 0 oder 1 sein. Wenn es nicht den Wert 1 hat, dann muss 
daher state den Wert 0 haben.
1
        if( state == 1 )
2
          sendStartSeq1();
3
        else
4
          sendStartSeq0();

gewöhn dir schnell an, mit 'else' zu arbeiten. Du machst dir (und dem 
Prozessor) sonst eine Menge Mehrarbeit für nichts und wieder nichts

Gewieftere C Programmierer beherzigen auch, dass in C oft weniger gleich 
mehr ist und nutzen aus, dass in C ein Wert ungleich 0 (und 1 ist 
zweifellos ungleich 0) automatisch als logisch wahr gilt. D.h man muss 
gar nicht drauf bestehen, dass state den Wert 1 haben muss. Irgendein 
Wert ungleich 0 (und 1 ist das zweifellos) tut es auch
1
        if( state )
2
          sendStartSeq1();
3
        else
4
          sendStartSeq0();
Der Hintergrund ist der, dass man sich nämlich mit derart expliziten, 
unnötigen, Vergleichen oft ganz schön ins Knie schiessen kann, ohne es 
zu merken.
Verlangt man hier nicht mehr explizit den Wert 1, dann geht die 
Umschaltung in den anderen Zustand noch einfacher
1
       state = !state;

Eventuell könnte man beim Funktionsaufruf auch an den Einsatz des 
ternären Operators denken.
1
          state ? sendStartSeq1() : sendStartSeq0();
aber ich denke, so weit bist du noch nicht.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Formatiere den Quelltext erstmal ordentlich, ich mag da gar nicht mehr 
rein schauen!

von Karl H. (kbuchegg)


Lesenswert?

Zudem ist 'state' so ein herrlich nichtssagender Variablenname. Das 
Programm ist in einem Zustand. Ja. Und? Weiter! Was ist das füe ein 
Zustand, was beschreibt er, was hat es damit auf sich. All das spiegelt 
sich in einem gut gewählten Variablennamen wieder.

1
        if (state==1){sendStartSeq1();}      // wenn i == 0xff => Startsequenz = 1 1 1
fällt dir was auf?

Genau. Im Code steht die Abfrage auf 'state'. Im Kommentar ist da 
plötzlich von einem i die Rede. Im Code steht ein Verlgeich auf 1, im 
Kommentar steht ein Vergleich auf 0xFF

Grundregel: Ehe du einen derartigen Kommentar schreibst, überlege, wie 
du Variablen bzw. Funktionsnamen so umbenennen kannst, dass du den 
Kommentar ÜBERHAUPT NICHT BRAUCHST!

Der ideale Kommentar ist derjenige, der wegfallen kann, weil alles was 
mir der Kommentar erzählen könnte, bereits im Code selber steht. Denn so 
ein (weggefallener) Kommentar kann nie falsch sein.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> Der ideale Kommentar ist derjenige, der wegfallen kann, weil alles was
> mir der Kommentar erzählen könnte, bereits im Code selber steht. Denn so
> ein (weggefallener) Kommentar kann nie falsch sein.


Der hier zum Bleistift
1
  ICR1 = 108;                    // Periode PWM => 38kHz
2
  OCR1A = 27;                    // ICRI/4  => 25% PWM

ZUm einen: Warum stehen da die 108 direkt im Code?
Was ist, wenn sich die Taktfrequenz des Controllers ändert. oder die 
geforderte PWM Frequenz. WIllst du dann wirklich selber den neuen Wert 
ausrechnen? Händisch?

Du hast einen COmpiler. Und dein Compiler kann rechnen! WIe bist du auf 
die 108 gekommen? Genau die gleiche Berechnung kann auch der Compiler 
für dich übernehmen.
1
#define PWM_PERIOD_VALUE   ........... Berechnungsvorschrift für den TOP Wert .....

Und warum stellst du dann in OCR1A ein Viertel von diesem Wert wieder 
selbst händisch ausgerechnet rein
1
    ICR1 = PWM_PERIOD_VALUE;
2
    OCR1A = PWM_PERIOD_VALUE / 4;      // 25%

Der springende Punkt ist, dass sich bei einer notwendigen Änderung von 
Werten nur noch 1 Wert ändert. Den anderen passt der Compiler für dich 
an.
Die 25% im Kommentar lass ich dir, denn heutzutage ist das ja nicht mehr 
selbstverständlich, dass Leute 1 Viertel mit 25 Prozent assozieren 
können.

von Karl H. (kbuchegg)


Lesenswert?

Hmm
1
                       // Fast-PWM mit ICR1 als TOP
2
  TCCR1B |= (1<< CS10) |(1<<WGM13);  // Prescaler = 1
3
  
4
                          
5
                          // ICR1 = F_CPU/(2*Prescaler*(F_PWM+1)

bist du dir da sicher?

Warum 2*prescaler?
Und die +1 sind auch fraglich.

IMHO müsstes du am Ausgang mit deinen 108 eigentlich eine Frequenz von 
rund 73.3kHz haben. Hast du nachgemessen?

d.h. sofern die hier
1
#define F_CPU 8000000UL
korrekt sind

: Bearbeitet durch User
von Opto (Gast)


Lesenswert?

Jetzt geht's hier aber zur Sache.

Wegen dem i=0xFF. Wie gesagt, es wurde viel rumprobiert und nach 
mehreren Stunden ist man eben verzweifelt ;) Irgendwann wurde aus i 
state und aus i=~(i); diese blöden if-Abfragen. Wobei i natürlich auch 
nicht so vielsagend ist.

Der TOP Wert wurde ehrlich gesagt experimentell bestimmt. Die 8MHz 
passen, da die 889µs delays gut hinkommen (mit Oszi nachgemessen).

Zur Formatierung des Quelltextes: Im Atmel Studio sieht das ganz anders 
und ordentlich aus. Die Boardsoftware scheint die Kommentare aber 
irgendwie nicht zu mögen.

Das mit dem PWM_PERIOD_VALUE war mir eigentlich auch klar, dass man das 
oben einmal #defined und dann nicht mehr mit absoluten Werten arbeitet, 
aber das stammt noch aus den ersten Stunden, die in das Projekt 
geflossen sind. Habs jetzt überarbeitet.

von Karl H. (kbuchegg)


Lesenswert?

Opto schrieb:
> Jetzt geht's hier aber zur Sache.
>
> Wegen dem i=0xFF. Wie gesagt, es wurde viel rumprobiert und nach
> mehreren Stunden ist man eben verzweifelt ;) Irgendwann wurde aus i
> state und aus i=~(i); diese blöden if-Abfragen. Wobei i natürlich auch
> nicht so vielsagend ist.

Ja, das kennen wir alle.

Und genau deshalb sind derartige Kommentare gelinde gesagt scheisse.
Sie werden in guter Absicht geschrieben und nach 2 Stunden stimmen sie 
schon nicht mehr mit dem Code überein.
Genau deswegen ist es die beste Strategie, wenn der Code so geschrieben 
ist, dass er sein eigener Kommentar ist und man keinen expliziten 
Kommentar mehr braucht. Je mehr Kommentare du NICHT brauchst, desto 
besser wird dein Code.

von Karl H. (kbuchegg)


Lesenswert?

Opto schrieb:

> Der TOP Wert wurde ehrlich gesagt experimentell bestimmt.

Tja. rein rechnerisch kommt da aber eine Frequenz von rund 73kHz raus.
Denn in einem PWM Durchgang, wird der Ausgangspin ja von 0 auf 1 und von 
1 auf 0 gesetzt. D.h. in einem PWM Durchgang hast du einen kompletten 
Wellenzug. Pro Sekunde finden bei deinen Werten aber 73tausend - 3 
hundert - und irgendwas PWM Durchgänge statt. Von den versprochenen 
38kHz weit entfernt.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Ah. Hier liegt der Hund begraben
1
  TCCR1A |= (1 << WGM12) | (1<<WGM11) ;      // Fast-PWM mit ICR1 als TOP
2
                       
3
  TCCR1B |= (1<< CS10) |(1<<WGM13);        // Prescaler = 1

WGM12 ist beim Mega8 nicht im Register TCR1A sondern im Register TCR1B. 
Du hast in Wirklichkeit eine Phase Correct PWM eingestellt. Und dann 
sind deine Werte wieder plausibel.

Du musst noch viel sorgfältiger werden!

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.