Forum: Compiler & IDEs Code Optimierung Stepper mit ADC und Taster Debounce


von Tom C. (palmodos)


Lesenswert?

Hallo erstmal mein Name ist Tom, bin schon länger passiver Leser dieses 
Forums und bin gerade bei meinem ersten Projekt.
Ich steuere mit meinem Atmega8 die L297/298 Kombination an, an der ein 
kleiner Schrittmotor hängt. Das Signal erzeuge ich indem ich mit dem 
Timer Overflowflag ein Bit Toggle. Der Motor wird über ein Poti, welches 
an PC0 hängt über einen ADC in der Drehzahl verändert.Hierzu übergebe 
ich vom ADC einen Wert Für den Timer Reload. Jetzt brauche ich einen 
entprellten Taster mit dem ich die ganze Sache ein und ausschalten kann. 
Die Schalter Entprellung funzt separat, aber nicht in  Kombination mit 
meiner ISR. Es wär echt cool, wenn mir jemand ein paar Tips zur 
Entwurschtellung meines Codes geben könnte. Der Ablauf meines Motor 
Signals in der ISR scheint mir nicht optimal, aber ich hab kein Plan, 
wie ich das anders realisieren kann.

Grüße

Tom
1
/*myheader.h*/
2
#include<avr/io.h>
3
#ifndef F_CPU
4
#define F_CPU 3686400UL     
5
#endif 
6
#include <util/delay.h>
7
8
9
/****************************Define**************************************************/
10
#define BUTTON_PORT PORTD       /* PORTx - Register für Taster Output */
11
#define BUTTON_PIN PIND         /* PINx - Register für Taster Input */
12
#define BUTTON_BIT PD2          /* bit für Taster input/output */
13
14
15
#define DEBOUNCE_TIME 25        /* Debounce Zeit */
16
#define LOCK_INPUT_TIME 250     /* Wartezeit nachdem Taster gedrückt wurde*/
17
18
19
#define LOW 0
20
#define HIGH 1
21
#define INPUT(port,pin)   DDR ## port &= ~(1<<pin)
22
#define OUTPUT(port,pin)  DDR ## port |= (1<<pin)
23
#define CLEAR(port,pin)   PORT ## port &= ~(1<<pin)
24
#define SET(port,pin)     PORT ## port |= (1<<pin)
25
#define TOGGLE(port,pin)  PORT ## port ^= (1<<pin)
26
#define READ(port,pin)   (PIN ## port & (1<<pin)) 
27
28
29
30
31
/*********************Funktions Prototypen*****************************************/
32
33
34
int button_is_pressed();
35
void delay_ms(uint16_t ms);
36
int button_is_pressed();
37
int read_adc(void);
38
39
40
41
42
43
44
/********************Stepper mit ADC.c*****************************/
45
46
#include <avr/interrupt.h>
47
#include <stdint.h>
48
#include "myheader.h"
49
50
51
52
53
54
55
volatile uint8_t reload=0;
56
57
58
59
60
61
62
int main (void)
63
{
64
     
65
66
    while (button_is_pressed(1))
67
        {
68
                
69
                  
70
              read_adc();
71
                 
72
                
73
        }
74
  
75
   
76
   
77
   
78
   
79
}
80
81
82
ISR(ADC_vect)
83
{
84
85
  OUTPUT(B,0);       //PORT B Pin 0 als Ausgang schalten
86
      
87
  TCCR0=(0<<CS02|1<<CS01|0<<CS00);  //Prescaler einstellen 1/8
88
  
89
  SET(B,0);   // PORT B Pin 0 auf 1 setzen
90
  
91
for (;;)
92
  {    
93
  
94
    if ( (bit_is_set (TIFR,0)))  //Abfrage des Timer Flags
95
    {   
96
      
97
      
98
       reload=ADCH;   
99
      reload=reload/2;       // Reloadwert zu groß
100
      TCNT0= reload; 
101
      TOGGLE(B,0);         // Ausgang Togglen
102
      TIFR=0x01;        //Timer Overflow Flag löschen mit 1
103
    
104
105
    }
106
    
107
    
108
  
109
  
110
  }
111
}
112
113
/**************buttondebounce.c***********************/
114
115
#include "myheader.h"
116
117
118
/*delay_ms - Verzögerungsschleife.*/ 
119
  void delay_ms(uint16_t ms) 
120
  {
121
        while ( ms ) 
122
        {
123
                _delay_ms(1);
124
                ms--;
125
        }
126
  }
127
128
/* Funktion um zu checken ob der Taster gedrückt wurde
129
   Gibt eine 1 zurück wenn der Taster gedrückt wurde ansonsten 0*/ 
130
  int button_is_pressed()
131
  {
132
        /* Der Taster ist gedrückt wenn er gegen Masse gezogen wird */
133
        if (bit_is_clear(BUTTON_PIN, BUTTON_BIT))
134
        {
135
                delay_ms(DEBOUNCE_TIME);
136
                
137
          if (bit_is_clear(BUTTON_PIN, BUTTON_BIT)) 
138
          return 1;
139
        }
140
        
141
        return 0;
142
  }
143
144
/*********************read_adc.c******************************/
145
#include <avr/interrupt.h>
146
#include <stdint.h>
147
148
149
int read_adc(void)
150
{
151
152
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Setze ADC prescaler von 128 - 125KHz sample rate @ 3,6864 Mhz
153
154
   ADMUX |= (1 << REFS0); // Setze ADC Vref auf externen Pin AVCC(4,6V)
155
   ADMUX |= (1 << ADLAR); // ADCH wird als erstes Nibble gestellt
156
   // Mux muss nicht eingestellt werden, da Pin 1 default  ist
157
158
   ADCSRA |= (1 << ADFR);  // Setze Free-Running Mode
159
   ADCSRA |= (1 << ADEN);  // Aktiviere ADC
160
161
   ADCSRA |= (1 << ADIE);  // Aktiviere ADC Interrupt
162
   sei();   //  Globalen Interrupt aktivieren
163
164
   ADCSRA |= (1 << ADSC);  // Starte A2D Conversion
165
   
166
  
167
168
   for(;;)  // Loop Forever
169
   {
170
     
171
   }
172
173
return(0);
174
}

von ... .. (docean) Benutzerseite


Lesenswert?

was sollen die zwei for(;;) Schleifen? Das kann nicht gehen...

EINE Endlos Schleife in der MAIN!!!

von Tom C. (palmodos)


Lesenswert?

Ich hab die Module einzeln getestet und etwas den Überblick verloren.
Danke für den Tip, werd da mal etwas dran rumspielen.

von Karl H. (kbuchegg)


Lesenswert?

Tom Cee schrieb:
> Ich hab die Module einzeln getestet und etwas den Überblick verloren.

Fang als erstes damit, die überzähligen Leerzeilen rauszuwerfen.
Wenn du mehr als eine Leerzeile hintereinander machst um etwas 
abzusetzen, dann hat es sich der nächste Code-Abschnitt verdient, dass
  * er nur mit 1 Leerzeile eingeleitet wird
  * dafür aber ein Blockkommentar vor dem Block beschreibt, was
    an dieser Stelle im Code, global gesehen, passieren wird.


So was
1
#define TOGGLE(port,pin)  PORT ## port ^= (1<<pin)
2
#define READ(port,pin)   (PIN ## port & (1<<pin)) 
3
4
5
6
7
/*********************Funktions Prototypen*****************************************/
8
9
10
int button_is_pressed();
11
void delay_ms(uint16_t ms);
12
int button_is_pressed();
13
int read_adc(void);
14
15
16
17
18
19
20
/********************Stepper mit ADC.c*****************************/
21
22
#include <avr/interrupt.h>
23
#include <stdint.h>
24
#include "myheader.h"
25
26
27
28
29
30
31
volatile uint8_t reload=0;
32
33
34
35
36
37
38
int main (void)
39
{
40
     
41
42
    while (button_is_pressed(1))
43
        {
44
                
45
                  
46
              read_adc();
47
                 
48
                
49
        }
50
  
51
   
52
   
53
   
54
   
55
}

erhöht keine Übersicht, sindern verringert sie, weil es den Code 
unnötigerweise einfach nur in die Länge zieht und man so auf dem 
Bildschirm weniger Nutzinformation sieht.
1
#define TOGGLE(port,pin)  PORT ## port ^= (1<<pin)
2
#define READ(port,pin)   (PIN ## port & (1<<pin)) 
3
4
/*********************Funktions Prototypen*****************************************/
5
int button_is_pressed();
6
void delay_ms(uint16_t ms);
7
int button_is_pressed();
8
int read_adc(void);
9
10
/********************Stepper mit ADC.c*****************************/
11
#include <avr/interrupt.h>
12
#include <stdint.h>
13
#include "myheader.h"
14
15
volatile uint8_t reload=0;
16
17
int main (void)
18
{
19
  while (button_is_pressed(1))
20
  {
21
    read_adc();
22
  }
23
}

Hmm. Die übliche logische Sequenz in main ist doch eher die
1
int main()
2
{
3
  ... die benutzte Hardware initialisieren
4
  ... das bedeutet zb die DDR richtig setzen
5
  ... Pullups einschalten, falls gebraucht
6
  ... Timer richtig einstellen, etc, etc
7
  ... kurz und gut: die Vorraussetzungen schaffen
8
  ... das der Prozessor richtig konfiguriert ist um
9
  ... überhaupt mit der eigentlichen Arbeit anfangen
10
  ... zu können
11
12
  sei();    // falls Interrupts benutzt werden
13
14
  while( 1 ) {
15
16
    .. Programmlogik
17
    .. zb. Wenn eine Taste gedrückt wird, mach etwas
18
19
  }
20
}

Jetzt vergleich einmal deinen Ansatz für main() mit dem Grundschema und 
versuche da die Entsprechungen zu finden. Du wirst keine finden :-)
Hinweis: Auch wenn deine read_adc() Funktion suggeriert, dass dort der 
ADC ausgelesen wird, so tut sie das eigentlich nicht. Deine 'read_adc' 
ist eigentlich mehr eine Initialisierungsfunktion, die den ADC in den 
Arbeitsmodus schaltet. Initialisierungsfunktion -> hat in der 
Hauptschleife nichts verloren, sondern wird vor die Hauptschleife 
gesetzt. Auch sehe ich nirgends, wo zb die Voraussetzungen für den 
Taster schaffst, oder braucht du keinen Pullup?

Und nimm auch den sei() aus der read_adc raus. Der hat dort drinnen auch 
nichts verloren. Eine derartige wichtige Entscheidung, 'ab jetzt können 
Interrupts auslösen', legt man nicht in eine Funktion die nur die 
Aufgabe hat ein Gerät zu initialisieren. Diese Entscheidung, Interrupts 
"ja bitte" macht man nachdem alles initialisiert ist und bevor die 
while-Hauptschleife loslegt. Das kann aber eine einzelne 
Initialisierungsfunktion nicht für sich entscheiden. Nach dem ADC könnte 
ja zb der Timer drann sein, initialisiert zu werden.

von Tom C. (palmodos)


Lesenswert?

Danke für die wertvollen Infos, Karl Heinz.
Ich hab wirklich noch große Probleme einen logischen Ablauf bei 
komplexeren Programmen hinzubekommen. Bei mir läuft das alles über Trial 
and Error und das ist ziemlich mühselig.

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.