Forum: Compiler & IDEs Drehimpugeber am Atmega8 mit FSM


von Thomas R. (bester-21)


Angehängte Dateien:

Lesenswert?

Hallo ich bin Schüler und wir haben gerade mit der AVR Programmierung 
angefangen (in C).

Jeder hat sein eigenes Projekt bekommen und er soll es bis zu einem 
gewissen Datum fertig stellen.

Ich habe eine FSM Logic für den Drehimpulsgeber gemacht. Wir haben es 
letztes Schuljahr auf ein GAL gebrannt und es hat funktioniert.

Jetzt bekomme ich jedoch beim ATMEGA 8 ein paar Probleme.
Und zwar zählt er bei mir öfters rechts statt links egal in welche 
Richtung ich drehe. Ich bin schon am verzweifeln warum das so ist.

Ich füge mal mein C Quelltext ein um es zu zeigen. Ich habe schon 
geguckt aber ich habe es ncht hinbekommen das es funktioniert. Ich habe 
schon im Forum geguckt aber das habe ich alles nicht verstanden, weil es 
auf Atmega 16 oder auch auf anderen Mikrokontrollern für gemacht worden 
ist. Und irgendwie muss ich das auch erklären können, deswegen hab ich 
das mit der FSM gemacht.

Ich hoffe das jemand mir helfen kann.

1
#include <avr\io.h>
2
#include "libbko_lcd.h"
3
#include <util\delay.h>
4
#include <avr/interrupt.h>
5
6
  unsigned int iZahl=20;
7
  int time;
8
9
int main (void)
10
{
11
  DDRD = 0x00;    //Auf Eingang setzten (B)
12
  DDRC = 0xFF;    //Auf Ausgang setzten (C)
13
    
14
  
15
  //PORTC   = 0xFF;  //Pull ups aktivieren 
16
          //Bei 0xFF ist Pull up aktiviert
17
          //Bei 0x00 ist Pull up deaktiviert
18
19
  int tempA;//= 0x00;
20
  int tempB;//= 0x00;  
21
  int tempC;//= 0x00;
22
23
  int iDreh = 20;
24
25
///ZUSTÄNDE
26
  int ruhe    = 0;   //RUHE
27
  int links1  = 1;  //Links 1
28
  int links2  = 2;  //Links 2
29
  int rechts1 = 3;  //Rechts 1
30
  int rechts2 = 4;  //Rechts 2
31
32
  
33
34
   //NEU
35
  // Timer 0 konfigurieren
36
    TCCR0 = (1<<CS01); // Prescaler 8
37
38
 
39
    // Overflow Interrupt erlauben
40
    TIMSK |= (1<<TOIE0);
41
  
42
  // Global Interrupts aktivieren
43
    sei();
44
45
  lcd_init();
46
  
47
  int zustand = 0;  //Aktueller Zustand
48
49
  PORTC = 0xFF;
50
51
  while(1)
52
  {  
53
  
54
    tempA = PIND & 1;    //0b0000000X
55
  tempB = PIND & 1<<1; //0b000000X0 
56
  tempC = PIND & 1<<2; //0b00000X00 
57
  
58
  if(iDreh == 23)
59
  {
60
    iZahl++;
61
62
    iDreh=20;
63
64
    lcd_reset();
65
    _delay_ms(50);
66
    lcd_ausgabe(iZahl);
67
  }
68
  
69
  if(iDreh == 17)
70
  {
71
    iZahl--;
72
73
    iDreh=20;
74
75
    lcd_reset();
76
    _delay_ms(50);
77
    lcd_ausgabe(iZahl);
78
  }       
79
  
80
  switch (zustand)
81
  {
82
    case 0: //Ruhe
83
      //lcd_puts("ruhe = 0");
84
      PORTC = 0b00000001;
85
      if((PIND & 1)==0b00000000 && (PIND & 1<<1)==0b00000010)  //A=0 B=1
86
      {
87
        //Links 1
88
        zustand = links1;
89
      }
90
      else if((PIND & 1)==0b00000001 && (PIND & 1<<1)==0b00000000)  //A=1 B=0
91
      {
92
        //Rechts 1
93
        zustand = rechts1;
94
      }
95
      else
96
      {
97
        //Ruhe
98
        zustand = ruhe;
99
      }
100
101
      
102
103
    break;
104
    case 1: //Links 1
105
      //lcd_puts("links1 = 1");
106
      PORTC = 0b00000010;
107
      if((PIND & 1)==0b00000001 && (PIND & 1<<1)==0b00000000)  //A=1 B=0
108
      {
109
        //Links 2
110
        zustand = links2;
111
      }
112
      else if((PIND & 1)==0b00000000 && (PIND & 1<<1)==0b00000010)  //A=0 B=1
113
      {
114
        //Links 1
115
        zustand = links1;
116
      }
117
      else if((PIND & 1)==0b00000000 && (PIND & 1<<1)==0b00000000)  //A=0 B=0
118
      {  
119
        //Links 1
120
        zustand = links1;
121
      }
122
      else
123
      {
124
        //Ruhe
125
        //zustand=links1;
126
        zustand = ruhe;
127
      }
128
            
129
    break;
130
    case 2:  //Links 2
131
      //lcd_puts("links2 = 2");
132
      PORTC = 0b00010011;
133
      
134
      //Ruhe
135
      zustand = ruhe;
136
    
137
      iDreh --;
138
    /*  
139
      lcd_reset();
140
      _delay_ms(50);
141
      lcd_ausgabe(iZahl);
142
    */
143
      //_delay_ms(100);
144
      //lcd_puts("links");
145
      //_delay_ms(500);
146
147
    break;
148
    case 3: //Rechts 1
149
      PORTC = 0b00000100;
150
      //lcd_puts("rechts1 = 3");
151
      
152
      if((PIND & 1)==0b00000000 && (PIND & 1<<1)==0b00000010)  //A=0 B=1
153
      {
154
        //Rechts 2
155
        zustand = rechts2;
156
      }
157
      else if((PIND & 1)==0b00000001 && (PIND & 1<<1)==0b00000000)  //A=1 B=0
158
      {
159
        //Rechts 1
160
        zustand = rechts1;
161
      }
162
      else if((PIND & 1)==0b00000000 && (PIND & 1<<1)==0b00000000)  //A=0 B=0
163
      {
164
        //Rechts 1
165
        zustand = rechts1;
166
      }
167
      else
168
      {
169
        //Ruhe
170
        //zustand = rechts1;
171
        zustand = ruhe;
172
      }
173
174
    break;
175
    case 4:  //Rechts 2
176
      //lcd_puts("rechts2 = 4");
177
      PORTC = 0b00001100;
178
      
179
      //Ruhe
180
      zustand = ruhe;
181
182
      iDreh ++;
183
    /*  
184
      lcd_reset();
185
      _delay_ms(50);
186
      lcd_ausgabe(iZahl);
187
    */  
188
      //_delay_ms(100);
189
      //lcd_puts("rechts");
190
      //_delay_ms(500);
191
    
192
    break;
193
    default:
194
      ///lcd_reset();      
195
196
      PORTC = 0xFF;
197
      //_delay_ms(1000);
198
      ///lcd_puts("ERREOR");
199
      _delay_ms(500);
200
201
    break;  
202
  }
203
  }
204
  return 1;                   
205
}
206
207
208
#ifndef TIMER0_OVF_vect
209
// Für ältere WinAVR Versionen z.B. WinAVR-20071221 
210
#define TIMER0_OVF_vect TIMER0_OVF0_vect
211
#endif
212
 
213
ISR (TIMER0_OVF_vect)
214
{
215
   //time++;  
216
}

von Noname (Gast)


Lesenswert?

>Und irgendwie muss ich das auch erklären können, ...

Mache bitte selbst erstmal eine Fehleranalyse. Ziel sollte sein 
festzustellen, an welcher Stelle des Programmes eine Abweichung vom 
gewollten Verhalten auftritt.
Dann eine "Untersuchung" warum der Unterschied existiert.
Da Du das lernen willst, können wir das nicht für Dich machen.

Formatierung könnte besser sein. Und Du solltest auch in der Lage sein 
besser zu verbalisieren.

Ansonsten sieht das schon recht nett aus für einen Anfänger. Nur Mut. 
Das packst Du schon.

von Peter D. (peda)


Lesenswert?

Daß diese FSM auf einem GAL funktioniert haben soll, kann ich nicht so 
richtig glauben. Sie sieht jedenfalls völlig anders aus, als die 
üblichen Lösungen. Auch wird nirgends der Zustand "11" ausgewertet.

Ein Encoder hat 4 Zustände, wovon 2 aufeinander folgen, je nach rechts 
oder links:
00 -> 01: n = n+1
01 -> 11: n = n+1
11 -> 10: n = n+1
10 -> 00: n = n+1
bzw. andersrum:
00 -> 10: n = n-1
10 -> 11: n = n-1
11 -> 01: n = n-1
01 -> 00: n = n-1

Dann muß man noch unterscheiden, hat der Encoder eine Rastung und wenn 
ja, nach wieviel Phasenwechseln.
Will man die Rastungen zählen, wird der Zählerstand zur Auswertung /2 
bzw. /4 geteilt.
Der Zähler muß intern aber immer alle Phasenwechsel zählen, sonst 
funktioniert die Entprellung nicht.


Peter

von Peter D. (peda)


Lesenswert?

Nochn Tip:
Auf dem MC sollte die Auswertung im Interrupt erfolgen, z.B. im 
Pin-Change-Interrupt.
Die Darstellung kann dann im Main erfolgen, ohne daß irgendein Ereignis 
verloren geht.

Ansonsten macht Dir nämlich das _delay_ms(500) alles zunichte. In der 
Zeit ist der MC quasi tot und kann nicht weiter abtasten.

Den GAL hast Du bestimmt auch nicht für 500ms angehalten.


Peter

von Michael D. (etzen_michi)


Lesenswert?

Ich würde das weniger per Pin-Change machen, mehr mit Polling der Ports 
(hatte vor kurzem ziemlich genau das gleiche Problem).

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.