STK500 Taster + Taster über GUI

Gast #745288
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
Gast #745641
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
Gast #745683
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
}
#745723
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
Gast #745742
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...
#745755
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
#745759
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.
Persönliche Seite #745810
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
  }
Gast #745833
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... 
??
#745847
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.
Gast #745899
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...
Gast #747101
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
};

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren