Forum: Compiler & IDEs timer, uart interupt und drehgeber


von heike (Gast)


Lesenswert?

Guten Tag,

ich habe hier gerade ein kleines Problem, bei dem mich hoffentlich
jemand in die richtige Richtung schubsen kann:

Das Programm (siehe unten) soll später mal dazu dienen, an einem AVR
Mega8 einen Wert per Drehgeber einstellen zu können.

Dafür soll der Benutzer am PC-terminal eintippen:
"Start" --> Drehgeber auslesen und das unendlich am PC-terminal ausgeben
"Stop" --> Ausgabe stop
"Weiter" --> Vom Letzer gespeicherte Wert wieder anfangen zu Zählen
"Reset" --> Vom null wieder anfangen zu zählen

- Wert auf PC-terminal ausgeben klappt Dazu habe ich den Code von Peter 
F.
benutzt (Danke!).
- Drehgeber auslesen: Klappt. Dazu habe ich den Code von Peter D.
benutzt (Danke!).
soweit funktioniert alles korrekt.

Jetzt das verbliebene Problem:
tippe ich "Start" ein, wird unendlich der ausgelesener Wert eingegeben. 
(Klar möchte ich es). Leider ist mir nicht mehr möglich etwas 
einzutippen.

Wie kann ich den Code schreiben um der Benutzer die möglichkeit geben, 
etwas anderen Befehlen einzutippen. ("Stop", "Weiter", "Reset")

Danke im Voraus!
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include <avr/interrupt.h>
4
#include <string.h>
5
6
#include "Drehgeber_uart.h"
7
8
#define PHASE_A (PINC & 0x01)  // PINC.0
9
#define PHASE_B (PINC & 0x02)  // PINC.1
10
#define LENGTH 7
11
12
13
static volatile long int  enc_delta;    // -2147483647 ... 2147483647
14
static char s[20];
15
char received[LENGTH+1];
16
unsigned char enter;
17
static volatile char enc_last;
18
19
20
SIGNAL (SIG_OVERFLOW0)
21
{
22
  //static char enc_last = 0x01;
23
  char i = 0;
24
25
  if( PHASE_A )
26
  i = 1;
27
28
  if( PHASE_B )
29
  i ^= 3;            // convert gray to binary
30
31
  i -= enc_last;       // difference new - last
32
33
  if( i & 1 )    // bit 0 = value (1)
34
  {    
35
    enc_last += i;      // store new as next last
36
    enc_delta += (i & 2) - 1;   // bit 1 = direction (+/-)
37
  }
38
}
39
40
41
void Timer_init( void )
42
{
43
  TCCR0 = 1<<CS00;            //No prescaling
44
  TIMSK = 1<<TOIE0;           //enable timer interrupt
45
}
46
47
//call this Function for initialisate the Port Output and Input
48
void port_init(void)
49
{
50
  
51
  DDRD = 0x02;    // Input-Port, except TxD
52
    PORTD = 0xFF;    // actiate Pull-Ups
53
54
  DDRC = 0x00;    // define as Input for the Rotary encoder
55
  PORTC = 0x03;      //enables Pull-Up on PC0 and PC1
56
  
57
  DDRB = 0xFF;    // outputs for LEDs
58
  PORTB = 0xFF;     // pullups
59
  
60
}
61
62
void encode_read( void )  // read single step encoders
63
{
64
  
65
    for(;;)              
66
  {  
67
    uart_gets(received, LENGTH);       // Receive data
68
    
69
    if(strcmp(received, "start") == 0)    
70
    { 
71
      do       // -2147483647 ... 2147483647
72
      {
73
        ltoa( enc_delta, s, 10 );   
74
        uart_puts("\r\n");  
75
        uart_puts( s );
76
        uart_puts("/");        
77
        PORTB = 0xFE;
78
      }while(strcmp(received, "start") == 0);
79
    }
80
    else if(strcmp(received, "stop") == 0)
81
    {
82
      cli();
83
                        PORTB = 0xFB;
84
    }
85
    else if(strcmp(received, "weiter") == 0)
86
    {  
87
      ltoa( enc_delta, s, 10 ); 
88
      uart_puts("\r\n");  
89
      uart_puts( s );
90
      uart_puts("/");
91
      PORTB = 0xFA;
92
    }
93
    else if(strcmp(received, "reset") == 0)
94
    {  
95
      enc_delta = 0x00;
96
      enc_last  = 0x00;
97
      ltoa( enc_delta, s, 10 ); 
98
      uart_puts("\r\n");
99
      uart_puts( s );
100
      uart_puts("/");
101
      PORTB = 0xF8;
102
    }
103
  }
104
}
105
106
int main( void )
107
{
108
109
  DDRD = 0x02;      // Input-Port, except TxD
110
  PORTD = 0xFF;      // actiate Pull-Ups
111
112
  Timer_init();
113
114
  port_init();
115
116
  // Initialize UART library, pass baudrate and AVR cpu clock
117
  uart_init();
118
   
119
  // Now enable interrupt, since UART library is interrupt controlled   
120
  sei(); 
121
122
  uart_puts("\r\n");
123
  uart_puts("Starting the measurement:");
124
  uart_puts("\r\n\n");
125
  _delay_ms(10);
126
  PORTB = 0xF0;
127
  
128
  for(;;)              // main loop
129
    encode_read();
130
 return 0;  
131
}

von Karl H. (kbuchegg)


Lesenswert?

Dein Problem besteht darin, dass hier
1
      do       // -2147483647 ... 2147483647
2
      {
3
        ltoa( enc_delta, s, 10 );   
4
        uart_puts("\r\n");  
5
        uart_puts( s );
6
        uart_puts("/");        
7
        PORTB = 0xFE;
8
      }while(strcmp(received, "start") == 0);

innerhalb der Schleife es für received keine Möglichkeit mehr gibt, 
einen anderen Wert zu erhalten.

Du musst deine komplette Systematik umstellen. So etwas wie eine 
Schleife die auf etwas wartet, darf es nicht mehr geben. Damit darfst du 
auch zb deine uart_gets Funktion nicht mehr weiter benutzen, solange die 
darauf wartet, dass eine Zeile komplett empfangen wurde.

Du musst die Logik in die Hauptschleife bringen:
Sieh dir nacheinander Dinge an, die man tun könnte, ob die 
Voraussetzungen dafür gegeben sind und mache sie, wenn die 
Voraussetzungen dafür gegeben sind. Bei einigen derartigen Aktionen wird 
es dann so sein, dass sie die Voraussetzungen für andere Aktionen 
schaffen oder vernichten

1
    while( 1 )
2
3
      if( Zeichen wurde empfangen ) {
4
        if( Zeichen ist ein '\n' ) {
5
          // Zeile ist komplett, merk dir das
6
          Zeile_komplett = TRUE;
7
        }
8
      }
9
10
      if( Zeile_komplett ) {
11
        Zeile_komplett = FALSE;
12
        if( Zeile ist "Start" )
13
          Merken dass ausgegeben werden soll
14
        else if( Zeile ist "Stop" )
15
          Den Merker für die Ausgabe zurücksetzen
16
        else if( Zeile ist "Weiter" )
17
          ...
18
      }
19
20
      if( Merker für Ausagbe ist gesetzt )
21
        mache 1 Ausgabe
22
23
    }

Ich hoffe man kann erkennen, wie das funktioniert. Du darfst nirgends 
warten. Stattdessen dreht die Haupt-while-Schleife ständig ihre Runden, 
sieht sich die einzelnen Sachen an und entscheidet anhand von Merkern 
(einfache Variablen die entweder 0 oder 1 sein können) ob eine Aktion 
gemacht werden soll oder nicht.

Du musst weg von einem sequentiellen Programmierstil (zuerst mach das, 
dann mach das, dann warte auf dieses und zum Schluss machst du noch 
jenes) hin zu einem ereignisorientierten Programmierstil: Ein Ereignis 
tritt auf, bearbeite es; in der Hauptschleife werden ständig alle 
möglichen Ereignisse überprüft ob sie vorliegen.

von heike (Gast)


Lesenswert?

viele dank für deine Tipps karl Heinz. Leider funnktioniert immer noch 
nicht, Bitte um weitere Tipps

so sieht der teil meiner Routine aus:
1
for(;;)                  // main loop
2
  {  
3
    enter = uart_getc();      
4
      if( enter != 0 )
5
    {
6
      do
7
        {
8
          enter = uart_getc();
9
            if(enter !='\r')  // = ENTER-Taste
10
        {
11
          *s=enter;
12
          s++;
13
            j++;
14
        }    
15
      }
16
        while( j!=LENGTH && enter!='\r');  
17
        *s = '\0';
18
      Zeile_komplett = TRUE;
19
    }    
20
    
21
    if( Zeile_komplett == TRUE ) 
22
    {
23
      if(strcmp(received, "start") == 0)
24
      {
25
        ltoa( enc_delta, s, 10 ); 
26
        Merker =1;
27
      }
28
      else if(strcmp(received, "stop") == 0)
29
      {
30
        Merker =0;
31
      }
32
      else if(strcmp(received, "weiter") == 0)
33
      {  
34
        Merker =1;
35
      }
36
      else if(strcmp(received, "reset") == 0)
37
      {  
38
        enc_delta = 0x00;
39
        enc_last  = 0x00;
40
        ltoa( enc_delta, s, 10 ); 
41
        Merker =1;
42
      }
43
    }
44
    if( Merker ==1 )
45
    {
46
          uart_puts("\r\n");
47
      uart_puts( s );
48
      uart_puts("/");
49
    }
50
51
    Zeile_komplett = FALSE;
52
  }

von Karl H. (kbuchegg)


Lesenswert?

heike schrieb:

>     enter = uart_getc();

Was macht uart_getc()?
Wartet die auf ein Zeichen, oder kommt die gleich zurück wenn kein 
Zeichen vorhanden ist?

Wenn ich mich recht erinnere benutzt du die UART Lib vom Peter Fleury. 
Sieh dir in seiner Demo an, wie man den Returnwert von uart_getc richtig 
auswertet.

Ich les mir den Code noch weiter durch

von Karl H. (kbuchegg)


Lesenswert?

1
      if( enter != 0 )
2
    {
3
      do
4
        {
5
          enter = uart_getc();
6
            if(enter !='\r')  // = ENTER-Taste
7
        {
8
          *s=enter;
9
          s++;
10
            j++;
11
        }    
12
      }
13
        while( j!=LENGTH && enter!='\r');  
14
        *s = '\0';
15
      Zeile_komplett = TRUE;
16
    }

NEIN!

Ich sagte doch: keine Warteschleifen.

Du holst ein Zeichen wenn eines da ist und hängst es an dein received 
Buffer an, das wars. Das nächste Zeichen wird bearbeitet, wenn die 
globale for(;;) Schleife das nächste mal zur Abfrage kommt "Ist ein 
Zeichen da?"
1
    if( enter != 0 )         // von der UART kommt wieder was
2
    {
3
      if( enter == '\r' )    // bei einem Newline ist die Zeile komplett
4
      {
5
        *s = '\0';
6
        Zeile_komplett = TRUE;
7
        s = received;        // s gleich wieder an den Anfang von received
8
                             // stellen, damit die nächsten Tastendrücke
9
                             // den nächsten String von vorne aufbauen
10
      } 
11
      else                   // ansonsten hänge das Zeichen hinten drann
12
      {
13
        *s = enter;
14
        s++;
15
      }
16
    }


Du denkst noch sequentiell:
Ich will eine Zeile komplett einlesen, also warte ich bis ich ein \r 
erhalte.
Der springende Punkt ist das Wörtchen 'warte'. Das musst du los werden.

Deine Denkweise muss sein:
Ich habe ein und nur ein Zeichen erhalten, was mache ich damit?
Hänge ich es hinten an das bisher empfangene drann oder ist mit diesem 
einen Zeichen eine Zeile vollständig und kann weiterbearbeitet werden.

(Das Ereignis ist: Ein Zeichen wurde empfangen
und der Rest ist die Reaktion auf dieses Ereignis)

von Karl H. (kbuchegg)


Lesenswert?

1
   if( Merker ==1 )
2
    {
3
          uart_puts("\r\n");
4
      uart_puts( s );
5
      uart_puts("/");
6
    }

Wieso s?

Woher weißt du wo s gerade hinzeigt?

von Karl H. (kbuchegg)


Lesenswert?

heike schrieb:

>     if( Zeile_komplett == TRUE )
>     {
>       if(strcmp(received, "start") == 0)
>       {
>         ltoa( enc_delta, s, 10 );
>         Merker =1;
>       }
>       else if(strcmp(received, "stop") == 0)
>       {
>         Merker =0;
>       }
>       else if(strcmp(received, "weiter") == 0)
>       {
>         Merker =1;
>       }
>       else if(strcmp(received, "reset") == 0)
>       {
>         enc_delta = 0x00;
>         enc_last  = 0x00;
>         ltoa( enc_delta, s, 10 );
>         Merker =1;
>       }
>     }
>     if( Merker ==1 )
>     {
>           uart_puts("\r\n");
>       uart_puts( s );
>       uart_puts("/");
>     }
>
>     Zeile_komplett = FALSE;
>   }


Nope. Das Rücksetzen von Zeile_komplett hat hier nichts verloren.
Das gehört logischerweise in den Zweig, in dem du das Ereignis 
Zeile_komplett == TRUE behandelst.
1
      if( Zeile_komplett == TRUE )
2
      {
3
        Zeile_komplett = FALSE;
4
        if(strcmp(received, "start") == 0)
5
        {
6
          ltoa( enc_delta, s, 10 );
7
8
          ...
9
10
      }

Hier gibt es auch noch ein anderes Problem. Wenn die Auswertung länger 
dauert und du schnell tippen kannst, dann kannst du klarerweise Zeichen 
in received 'einschmuggeln' ehe sie ausgewertet wurden.
Aber mach erst mal den Rest.

von heike (Gast)


Lesenswert?

Danke schön
ich kümmere mich weiter morgen
vielen dank nochmals

von Falk B. (falk)


Lesenswert?

Siehe Multitasking

von heike (Gast)


Lesenswert?

Lösung:
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include <avr/interrupt.h>
4
#include <string.h>
5
6
#define FALSE   0
7
#define TRUE    1
8
9
10
#ifndef F_CPU
11
/* In the new version of the WinAVR/Mfile Makefile guideline One can defined F_CPU in the Makefile, a repeated 
12
   definition here would lead to a compiler warning . therefore "prevention" through    #ifndef/#endif
13
14
   This "Prevention" can lead to Debugger, if AVRStudio use a another, not the hardware fitting Clock rate: 
15
   Then the    following definition doesn't use, but instead the default value (1 MHz?) of AVRStudio - hence 
16
   the Output of a warning if F_CPU yet does not define:*/ 
17
#warning "F_CPU was not defined yet, now make up with 3686400"
18
#define F_CPU 3686400L   // Systemtakt in Hz - define as  long>> Without errors in the computation 
19
#endif
20
21
#include <util/delay.h>
22
23
24
#define BAUD 9600L //38400L
25
#define UBRR_VAL ((F_CPU+BAUD * 8)/(BAUD*16)-1)     //clever round
26
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))         //real baud rate
27
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)     //Error per thousand
28
29
30
#if ((BAUD_ERROR>10)||(BAUD_ERROR<-10))
31
#error Systematic error in the baud rate more than 1% and thus too high!
32
#endif
33
34
#define PHASE_A (PINC & 0x01)  // PINC.0
35
#define PHASE_B (PINC & 0x02)  // PINC.1
36
37
void UART_Init() 
38
{
39
  
40
  UBRRH = (unsigned char)(UBRR_VAL>>8);  // Set baud rate
41
  UBRRL = (unsigned char)UBRR_VAL;
42
  
43
  UCSRB |= (1<<RXEN)|(1<<TXEN);// Enable receiver and transmitter
44
  
45
  UCSRC = (1<<URSEL) | (1<<UCSZ0)|(1<<UCSZ1);  // Set frame format: 8data, 1stop bit        
46
}//end uart_Init()
47
48
49
void UART_Putc(unsigned char c)
50
{
51
    while (!(UCSRA & (1<<UDRE)));// Do nothing until data have been transmited 
52
    
53
  UDR = c;                  // Put data into Buffer, sends the data
54
  _delay_ms(10);   
55
}//end uart_Putc()
56
57
58
void UART_Puts (char *string)
59
{
60
    while( *string != '\0' )          //as long as *string != '\0' so unlike the "stringer end-character"
61
    {  
62
        UART_Putc(*string);
63
        string++;
64
    }
65
}//end uart_Puts()
66
//////////////////////////////////////////////////////////////////////////
67
68
SIGNAL (SIG_OVERFLOW0)
69
{
70
  static char enc_last = 0x01;
71
  char i = 0;
72
73
  if( PHASE_A )
74
    i += 1;
75
76
  if( PHASE_B)
77
    i ^= 3;                // convert gray to binary
78
79
  i -= enc_last;             // difference new - last
80
81
  if( i & 1 )            // bit 0 = value (1)
82
  {    
83
    enc_last += i;          // store new as next last
84
    enc_delta += (i & 2) - 1;   // bit 1 = direction (+/-)
85
  }
86
}
87
88
89
void Timer_init( void )
90
{
91
  TCCR0 = 1<<CS00;            //No prescaling
92
  TIMSK = 1<<TOIE0;           //enable timer interrupt
93
}
94
95
96
97
//call this Function for initialisate the Port Output and Input
98
void port_init(void)
99
{
100
  
101
  DDRD = 0x02;      // Input-Port, except TxD
102
    PORTD = 0xFF;      // activate Pull-Ups
103
104
  DDRC = 0x00;  // define as Input for the Rotary encoder
105
  PORTC = 0x03;   //enables Pull-Up on PC0 and PC1
106
}
107
108
void encode_read0( void )// read single step encoders
109
{
110
  // Now enable the Timer interrupt
111
  sei();
112
  enc_delta = 0x00;
113
  //enc_last  = 0x00;
114
  
115
  ltoa( enc_delta, s, 10 );   //convert Ascii in  DEZ-Zahlen 
116
  UART_Puts( s );
117
  UART_Puts("/");
118
  UART_Puts("\r\n");
119
}
120
121
void encode_read( void )  // read single step encoders
122
{
123
  sei();
124
  
125
    ltoa( enc_delta, s, 10 ); //convert Ascii in  DEZ-Zahlen 
126
    UART_Puts( s );
127
    UART_Puts("/");  //So that it isn't leaves the cypher behind
128
    UART_Puts("\r\n");
129
}
130
///////////////////////////////////////////////////////////////////////////
131
132
unsigned char uart_lesen(void)
133
{
134
    uint8_t tmp;
135
    if((UCSRA & (1<<RXC)))
136
  {                // empfangenes Zeichen abholbereit im UART ?
137
        tmp = UDR;
138
        while (!(UCSRA & (1<<UDRE))); // Warte auf freien Sendepuffer vom UART
139
        UDR = tmp;
140
    }
141
  //return UDR;
142
}
143
144
int befehl_lesen(void)
145
{
146
  unsigned char received;
147
148
    received = uart_lesen();           // Receive data
149
  
150
  //Start --> 0
151
  //Stop --> 1
152
  //Weiter --> 2
153
  //Reset --> 3
154
  if(received == 0x30)
155
    return 0;
156
157
  else if(received == 0x31)
158
    return 1;
159
160
  else if(received == 0x32)
161
    return 2;
162
163
  else if(received == 0x33)
164
    return 3;
165
}
166
167
void Messwert_Ausgeben(int Befehl)
168
{
169
  if(Befehl == 0)
170
    encode_read();
171
172
  else if(Befehl == 1)
173
    cli();
174
175
  else if(Befehl == 2)    
176
    encode_read();
177
178
  else if(Befehl == 3)
179
    encode_read0();
180
}
181
182
int main( void )
183
{
184
  int befehl;
185
186
  DDRD = 0x02;      // Input-Port, except TxD
187
  PORTD = 0xFF;      // activate Pull-Ups
188
  PORTB = 0xF0;
189
190
  Timer_init();
191
192
  port_init();
193
194
  //  Initialize UART library, pass baudrate and AVR cpu clock
195
  UART_Init();
196
197
    while (1)                  // main loop
198
  {
199
    befehl = befehl_lesen();
200
    Messwert_Ausgeben(befehl);
201
  }
202
    return 0;
203
}

viele grüsse

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.