Forum: Mikrocontroller und Digitale Elektronik STK500 Taster + Taster über GUI


von Daniel (Gast)


Lesenswert?

Hallo,

Ich hab ne GUI gebaut mit der ich die Taster bedienen kann. Taster 
sollen von GUI UND Board aus bedienbar sein! mit dem folgenden Code kann 
ich zu beginn die original taster bedienen. wenn ich dann in der GUI 
klicke springt er auch schön aus der ersten schleife raus, geht in die 
zweite (PC Modus) und bleibt dann für immer in dieser stecken... sprich 
ab dann funzt nur noch GUI taster...

aber wie kann es sein das während ich auf den tastern am board rumdrücke 
PINA==0xFF immer wahr ist??

bitte um Nachsicht, bin anfänger :)

1
// USART Receiver interrupt service routine
2
interrupt [USART_RXC] void usart_rx_isr(void)
3
{  
4
5
char status,data;
6
status=UCSRA;
7
notify=status;
8
.
9
.
10
.
11
12
//Taster auf A
13
PORTA=0xFF;
14
DDRA=0x00;
15
16
// LED auf B
17
PORTB=0xFF;
18
DDRB=0xFF; 
19
20
//main
21
.
22
.
23
.
24
25
while (1){
26
27
     // solange notify kleiner 128: Taster Modus 
28
     // d.h. abfrage ob erstes Bit in UCSRA gesetzt ist (Daten empfangen)
29
     while (notify<0x80){ 
30
        PORTB=PINA; 
31
     } 
32
33
     // solange kein Taster gedrückt wird: PC Modus
34
     while (PINA==0xFF){
35
        PORTB=getchar();
36
     }
37
38
     notify=0x00;
39
};
40
41
.
42
.
43
.


MfG

Daniel

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Hast du einen Hund zu Hause, der dir den Sourcecode so zerfressen hat?

Ich habe ehrlich versucht, einen Fehler zu finden (es sind genug 
vorhanden) aber genau der, der zu deiner Beschreibung passt, ist nicht 
dabei. Ich kann mir das nur so erklären, dass in dem fehlenden 
Sourcecode auch ein oder mehrere Fehler (die essentiellen) stecken.

von Daniel (Gast)


Lesenswert?

na also ich hab ja nur die relevanten stellen rausgeholt... alles andere 
wurde vom AVRWizard generiert... standart werte... das einzigste was ich 
am generierten code geändert bzw. hinzugefügt habe ist diese eine zeile 
in der USART ISR:
1
notify=status;

ansonsten läuft das prog ja bis auf die tatsache das ich 
unerklärlicherweise nicht aus dieser 2. while schleife rauskomme...

pullups sind ja an und die taster funzen ja auch solange ich nich in der 
GUI taster drücke...

ist übrigens ein ATmega8515L drauf

von Daniel (Gast)


Lesenswert?

nagut dann hier nochmal der gesamte code:
1
/*****************************************************
2
This program was produced by the
3
CodeWizardAVR V1.25.1 Standard
4
Automatic Program Generator
5
© Copyright 1998-2006 Pavel Haiduc, HP InfoTech s.r.l.
6
http://www.hpinfotech.com
7
8
Chip type           : ATmega8515L
9
Program type        : Application
10
Clock frequency     : 4,000000 MHz
11
Memory model        : Small
12
External SRAM size  : 0
13
Data Stack size     : 128
14
*****************************************************/
15
16
#include <mega8515.h>   
17
#include <stdio.h>
18
                                   
19
// Initialisierung Senden & Empfangen über USART-Schnittstelle
20
//------------------------------------------------------------------------
21
#define RXB8 1
22
#define TXB8 0
23
#define UPE 2
24
#define OVR 3
25
#define FE 4
26
#define UDRE 5
27
#define RXC 7
28
29
#define FRAMING_ERROR (1<<FE)
30
#define PARITY_ERROR (1<<UPE)
31
#define DATA_OVERRUN (1<<OVR)
32
#define DATA_REGISTER_EMPTY (1<<UDRE)
33
#define RX_COMPLETE (1<<RXC)
34
35
36
// USART Receiver buffer
37
#define RX_BUFFER_SIZE 8
38
char rx_buffer[RX_BUFFER_SIZE];
39
40
#if RX_BUFFER_SIZE<256
41
unsigned char rx_wr_index,rx_rd_index,rx_counter;
42
unsigned char notify=0x00;
43
#else
44
unsigned int rx_wr_index,rx_rd_index,rx_counter;
45
#endif
46
47
// This flag is set on USART Receiver buffer overflow
48
bit rx_buffer_overflow;
49
50
// USART Receiver interrupt service routine
51
interrupt [USART_RXC] void usart_rx_isr(void)
52
{  
53
54
char status,data;
55
status=UCSRA;
56
notify=status;
57
data=UDR;
58
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
59
   {
60
   rx_buffer[rx_wr_index]=data;   
61
   
62
   if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
63
   if (++rx_counter == RX_BUFFER_SIZE)
64
      {
65
      rx_counter=0;
66
      rx_buffer_overflow=1;
67
      };
68
   };
69
}
70
71
#ifndef _DEBUG_TERMINAL_IO_
72
// Get a character from the USART Receiver buffer
73
#define _ALTERNATE_GETCHAR_
74
#pragma used+ 
75
76
77
78
char getchar(void)
79
{
80
char data;
81
while (rx_counter==0);
82
data=rx_buffer[rx_rd_index];
83
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
84
#asm("cli")
85
--rx_counter;
86
#asm("sei")   
87
return data;
88
}
89
#pragma used-
90
#endif
91
     
92
93
94
// USART Transmitter buffer
95
#define TX_BUFFER_SIZE 8
96
char tx_buffer[TX_BUFFER_SIZE];
97
98
#if TX_BUFFER_SIZE<256
99
unsigned char tx_wr_index,tx_rd_index,tx_counter;
100
#else
101
unsigned int tx_wr_index,tx_rd_index,tx_counter;
102
#endif
103
      
104
105
106
107
// USART Transmitter interrupt service routine
108
interrupt [USART_TXC] void usart_tx_isr(void)
109
{
110
if (tx_counter)
111
   {
112
   --tx_counter;
113
   UDR=tx_buffer[tx_rd_index];
114
   if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0;
115
   };
116
}
117
118
#ifndef _DEBUG_TERMINAL_IO_
119
// Write a character to the USART Transmitter buffer
120
#define _ALTERNATE_PUTCHAR_
121
#pragma used+      
122
123
124
125
126
void putchar(char c)
127
{
128
while (tx_counter == TX_BUFFER_SIZE);
129
#asm("cli")
130
if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
131
   {
132
   tx_buffer[tx_wr_index]=c;
133
   if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
134
   ++tx_counter;
135
   }
136
else
137
   UDR=c;
138
#asm("sei")
139
}
140
#pragma used-
141
#endif
142
//------------------------------------------------------------------------
143
144
145
// Declare your global variables here
146
147
148
void main(void)
149
{
150
// Declare your local variables here
151
unsigned char taster=0xFF; 
152
unsigned char led=0xFF;    
153
unsigned char led_alt=0xFF;
154
155
156
// Input/Output Ports initialization
157
PORTA=0xFF;
158
DDRA=0x00;
159
160
PORTB=0xFF;
161
DDRB=0xFF; 
162
163
// Timer/Counter 0 initialization
164
TCCR0=0x00;
165
TCNT0=0x00;
166
OCR0=0x00;
167
168
// Timer/Counter 1 initialization
169
TCCR1A=0x00;
170
TCCR1B=0x00;
171
TCNT1H=0x00;
172
TCNT1L=0x00;
173
ICR1H=0x00;
174
ICR1L=0x00;
175
OCR1AH=0x00;
176
OCR1AL=0x00;
177
OCR1BH=0x00;
178
OCR1BL=0x00;
179
180
// External Interrupt(s) initialization
181
MCUCR=0x00;
182
EMCUCR=0x00;
183
184
// Timer(s)/Counter(s) Interrupt(s) initialization
185
TIMSK=0x00;
186
187
// USART initialization
188
// Communication Parameters: 8 Data, 1 Stop, No Parity
189
// USART Receiver: On
190
// USART Transmitter: On
191
// USART Mode: Asynchronous
192
// USART Baud rate: 9600
193
UCSRA=0x00;
194
UCSRB=0xD8;
195
UCSRC=0x86;
196
UBRRH=0x00;
197
UBRRL=0x17; 
198
199
// Analog Comparator initialization
200
ACSR=0x80;
201
202
// Global enable interrupts
203
#asm("sei")
204
205
206
while (1)
207
      {     
208
      // B: LED         A: TASTER
209
     
210
     // solange notify kleiner 128: Board Modus 
211
     // d.h. abfrage ob erstes Bit in UCSRA gesetzt ist (Daten empfangen)
212
     while (notify<0x80){
213
      // LED: wenn änderung zum vorigen schleifendurchlauf wird LED status an PC geschickt
214
      led=PINB;    
215
      if (led_alt!=led){
216
        putchar(led);
217
      }   
218
      led_alt=led;   
219
        
220
    //Board mode
221
      PORTB=PINA; 
222
     } 
223
     
224
225
   // solange kein Taster gedrückt wird: PC Modus
226
     // hier kommt man nicht mehr raus! Idee: rauswurf durch tasterdruck am board...
227
     while (PINA==0xFF){
228
        // LED: wenn änderung zum vorigen schleifendurchlauf wird LED status an PC geschickt
229
      led=PINB;    
230
      if (led_alt!=led){
231
        putchar(led);
232
      }   
233
      led_alt=led;  
234
235
    //PC Mode
236
      PORTB=getchar();
237
     } 
238
     
239
     notify=0x00;
240
241
      };
242
}

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

> Hallo,

> Ich hab ne GUI gebaut mit der ich die Taster bedienen kann. Taster
> sollen von GUI UND Board aus bedienbar sein!

Was soll man mit der Beschreibung anfangen koennen? Ich gehoere leider 
nicht zu den gluecklichen, die eine funktionierende Kristallkugel 
besitzen -- und die wenigsten anderen hier wohl auch.

Michael

von Peter D. (peda)


Lesenswert?

Du hängst in ner Schleife fest, wozu überhaupt die vielen Schleifen?

Behandle ein Ereignis (d.h. nicht einen Zustand), wenn es eintrifft und 
gut is:
1
int main(void)
2
{
3
4
  init_stuff();
5
6
  for(;;){                // main loop
7
8
    if( taste_changed() ){
9
      handle_taste();
10
    }
11
12
    if( uart_receive() ){
13
      handle_uart();
14
    }
15
  }
16
}


Peter

von Daniel (Gast)


Lesenswert?

@Peter

ja ok wenn ichs nach deinem schema aufbaue verschiebe ich ja das problem 
nur... klar hatte ich es auch schon mit 2 if abfragen, ging leider 
nicht, da hab ich aus verzweiflung schleifen gebaut... :)

aber das problem liegt ja daran das
1
PINA==0xFF

auch dann wahr ist wenn ich auf den tastern rumdrücke... (nachdem ich 
die GUI mal betätigt hab...

von Peter D. (peda)


Lesenswert?

Daniel wrote:

> ja ok wenn ichs nach deinem schema aufbaue verschiebe ich ja das problem
> nur

Nein, gerade das sollst Du eben nicht!

Du verschiebst nicht die Schleifen in ne Unterfunktion, sondern Du 
nimmst sie ganz raus.

Die Unterfunktionen dienen nur dazu, das Programm lesbarer zu machen.


Nochmal, Du mußt das Ereignis behandeln (Taste wechselt von Losgelassen 
auf Gedrückt), nicht den Zustand (jemand sitzt ständig auf der Taste).

Schau Dir mal den Artikel Tastenentprellung an.


Peter

von Karl H. (kbuchegg)


Lesenswert?

Daniel wrote:
> @Peter
>
> ja ok wenn ichs nach deinem schema aufbaue verschiebe ich ja das problem
> nur...

Nicht wirklich.

> klar hatte ich es auch schon mit 2 if abfragen, ging leider
> nicht, da hab ich aus verzweiflung schleifen gebaut... :)
>
> aber das problem liegt ja daran das
>
>
1
PINA==0xFF
>
> auch dann wahr ist

Das glaub ich nicht.
Ich glaub eher, dass du durch irgendwelche Umstände
sofort wieder in die Schleife hineinkommst.
Sprich: Die Schleife wird korrekterweise abgebrochen,
dann passiert irgendwas, deine Hauptschleife geht einmal rundum
und du landest sofoert wieder in dieser PINA==0xFF Schleife.


Ich bin ebenfalls Peters Meinung. Das Ganze ist falsch rum
aufgezogen.
Du hast irgendwelche Funktionalitäten.
Diese Funktionalitäten sind jeweils in eigenen Funktionen
gekapselt.
Auslöser einer Funktionalität kann ein Tastendruck oder ein
Kommando über die Serielle Schnittstelle sein.

-> Dann programmier das auch so:
In der Hauptschleife wird ausgewertet ob eine bestimmte Taste
gedrückt ist. Wenn ja -> Funktionalität ausführen
Weiters wird in der Hauptschleife ausgewertet ob von der USART
ein Kommando reingekommen ist. Wenn ja -> Funktionalität wird
ausgeführt.

Du musst gedanklich einfach nur den Auslösemechanismus von
der Funktionalität trennen. Viele verschiedene Auslösemechanismen
können dieselbe Funktionalität auslösen. Das ist dann auch schon
alles, um ein tastefeld parallel mit einer UART am Laufen zu haben.
Und zwar wirklich parallel. Der Benutzer kann nach Belieben zwischen
PC-Ansteuerung und Tastenfeld wechseln.

Mit diesem Status, Tasten sind jetzt aktiv bzw. USART ist jetzt
aktiv, verkomplizierst du die Dinge nur, ohne irgendeinen
Vorteil davon zu haben.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

@ Autor: Daniel (Gast) Datum: 09.01.2008 10:12

getchar() ist eine wartende Funktion. Sie wartet bis zum Nimmerleinstag, 
bis ein Zeichen an UART ankommt. Deine while-Schleifen sind da tückisch. 
Weil getchar einen Puffer hat, ist die Abfrage eines Einzelzustands per 
notify nicht prall.

notify ist auch komplett entbehrlich. Du hast bereits einen Zähler für 
empfangenen Zeichen: rx_counter. Der kann in main benutzt werden, wenn 
er volatile definiert ist.

Die if-Abfragen waren schon richtig, ich würde die Aufgabe in ertwa so 
programmieren:
1
// ...
2
volatile unsigned char rx_counter;
3
// ...
4
5
// USART Receiver interrupt service routine
6
interrupt [USART_RXC] void usart_rx_isr(void)
7
{  
8
  char status, data;
9
10
  status = UCSRA;
11
  data = UDR;
12
13
  if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
14
  {
15
     rx_buffer[rx_wr_index] = data;   
16
     if (++rx_wr_index == RX_BUFFER_SIZE) 
17
       rx_wr_index=0;
18
19
     if (++rx_counter == RX_BUFFER_SIZE)
20
     {
21
       rx_counter=0;
22
       rx_buffer_overflow=1;
23
     }
24
  }
25
}
26
27
// ...
28
// Komplettersatz für die while(1)-Schleife:
29
30
  while(1)
31
  {
32
    unsigned char gui;
33
    unsigned char taster;
34
    unsigned char led;
35
    static unsigned char led_alt = PORTB;
36
37
    // Eingaben holen
38
    //   ggf. Eingabe UART, wenn Zeichen da sind
39
    if (rx_counter)
40
      gui = getchar();
41
    else 
42
      gui = 0;
43
44
    //   Eingabe Tastenstatus
45
    taster = ~PINA;      // wg. Active-low Eingangsstatus negieren
46
47
    // Ausgabewert aus Eingabewert berechnen
48
    led = taster | gui;  // Gui ODER Tasten
49
50
    // Ausgabe machen
51
    if (led_alt != led)
52
    {
53
      PORTB = led;
54
      putchar(led);
55
      led_alt = led;
56
    }
57
  }

von Daniel (Gast)


Lesenswert?

@Peter + Karl Heinz

erstmal danke für eure bemühungen

es geht mir nicht um eine bestimmte taste sondern um irgendeine... also:
1
while (1)
2
      { 
3
4
// if irgendeinen taster gedrückt:
5
       if (PINA!=0xFF){
6
          PORTB=PINA;
7
          notify=0;
8
       }
9
10
// if was vom USART kommt (DIESEN ZUSTAND BEIBEHALTEN, bis was
11
// neues vom USART oder bis irgendeinen taster gedrückt
12
      if (notify>127){
13
         PORTB=getchar();
14
      }
15
};

so meintet ihr das doch vom aufbau her oder? so hatte ich es doch schon 
aber sobald ich mal die GUI benutzt habe sind die taster am board tot... 
??

von Karl H. (kbuchegg)


Lesenswert?

Daniel wrote:
>
> so meintet ihr das doch vom aufbau her oder?

Nein, so meinen wir das nicht.


Ungefähr so:
1
  ....
2
3
4
  while( 1 ) {
5
6
    if( Taste1Pressed )
7
      Funktionalität1();
8
9
    if( CharFromUART == 'A' )    // soll ebenfalls Funktionalität 1 auslösen
10
      Funktionalität1();
11
12
    if( Taste2Pressed )
13
      Funktionalität2();
14
15
    if( CharFromUART == 'B' )    // soll ebenfalls Funktionalität 2 auslösen
16
      Funktionalität2();
17
  }

Also keine Warteschleifen oder sontige Zustandsschleifen.
Sondern einfach nur die eine wahre Hauptschleife. Innerhalb
der Hauptschleife wird abgefragt, ob ein Ereignis (Taste wurde
gedrückt, Zeichen an der UART empfangen) eingetreten ist
und wenn ja, wird die entsprechende Funktionalität gestartet.

Hol dir aus der Codesammlung die berühmten PeDa Entprellroutinen.
Die helfen dir schon mal die Tastenauswertungen zu vereinfachen.
Denn dann brauchst du nicht mehr darüber Buch führen ob sich ein
Tastenzustand geändert hat oder nicht. Das machen die Routinen
schon selbstständig. Für dich in der Hauptschleife bedeuten die
PeDa Routinen einfach nur eine Funktion aufrufen und wenn die
entsprechende Taste gedrückt wurde, dann liefert die Funktion
einmal TRUE zurück und ansonsten immer FALSE. Und damit
kann man wunderbar solche Hauptschleifen aufbauen.

Edit: Sehe gerade, dass auch Stefan dazu ein Beispiel gebracht
hat. Das Beispiel schlägt in genau dieselbe Kerbe: Eine Hauptschleife,
Abfrage ob Ereignisse eingetreten sind (Taste gedrückt, UART hat
was empfangen) und wenn ein Ereignis eingetreten ist, dann Aktion
auslösen.
Ich würde allerdings trotzdem die PeDa Routinen als Einstiegspunkt
empfehlen. Die vereinfachen sowas extrem.

von Daniel (Gast)


Lesenswert?

@stefan

danke, kann ich leider erst morgen testen

@karl heinz

es sollen ja lediglich die led leuchten die zum taster gehören... warum 
kann man denn nicht pina direkt an portb durchschleifen? ich will ja 
nicht 256 funktionalitäten (jede bitkombination) da einbauen...

if (char==0x00)
  Funktion1
.
.
.
if (char==0xFF)
  Funktion256

der soll ja einfach den char ausm usart buffer nehmen solange nicht am 
board gedrückt wird.

und wenn am board gedrückt wird soll er PINA an PORTB durchschleifen bis 
was neues im usart buffer steht...

von Daniel (Gast)


Lesenswert?

@stefan
so hats leider nicht funktioniert, aber durch dich hab ich den 
endscheidenden denkanstoss bekommen...

nur falls es noch jemanden interessiert, so funzt es:
1
while (1){    
2
3
      // B: LED         A: TASTER
4
5
    //   wenn USART neuen Status von PC empfängt, wird gui aktualisiert
6
    if (rx_counter){
7
        gui=getchar(); 
8
    }   
9
    
10
  // LED Status zusammensetzen aus Taster am Board und GUI Tasten
11
    led= (taster & gui); // entspricht: ~(~taster | ~gui)
12
    PORTB=led;
13
    taster=PINA; 
14
     
15
    // LED Ausgabe an PC schicken wenn LED Zustand sich geändert hat
16
    if (led_alt != led){ 
17
        putchar(led);
18
        led_alt = led;
19
    }          
20
};

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.