mikrocontroller.net

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


Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :)

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{  

char status,data;
status=UCSRA;
notify=status;
.
.
.

//Taster auf A
PORTA=0xFF;
DDRA=0x00;

// LED auf B
PORTB=0xFF;
DDRB=0xFF; 

//main
.
.
.

while (1){

     // solange notify kleiner 128: Taster Modus 
     // d.h. abfrage ob erstes Bit in UCSRA gesetzt ist (Daten empfangen)
     while (notify<0x80){ 
        PORTB=PINA; 
     } 

     // solange kein Taster gedrückt wird: PC Modus
     while (PINA==0xFF){
        PORTB=getchar();
     }

     notify=0x00;
};

.
.
.


MfG

Daniel

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
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

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nagut dann hier nochmal der gesamte code:
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.1 Standard
Automatic Program Generator
© Copyright 1998-2006 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Chip type           : ATmega8515L
Program type        : Application
Clock frequency     : 4,000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 128
*****************************************************/

#include <mega8515.h>   
#include <stdio.h>
                                   
// Initialisierung Senden & Empfangen über USART-Schnittstelle
//------------------------------------------------------------------------
#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)


// USART Receiver buffer
#define RX_BUFFER_SIZE 8
char rx_buffer[RX_BUFFER_SIZE];

#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
unsigned char notify=0x00;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif

// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{  

char status,data;
status=UCSRA;
notify=status;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer[rx_wr_index]=data;   
   
   if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
   if (++rx_counter == RX_BUFFER_SIZE)
      {
      rx_counter=0;
      rx_buffer_overflow=1;
      };
   };
}

#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+ 



char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")   
return data;
}
#pragma used-
#endif
     


// USART Transmitter buffer
#define TX_BUFFER_SIZE 8
char tx_buffer[TX_BUFFER_SIZE];

#if TX_BUFFER_SIZE<256
unsigned char tx_wr_index,tx_rd_index,tx_counter;
#else
unsigned int tx_wr_index,tx_rd_index,tx_counter;
#endif
      



// USART Transmitter interrupt service routine
interrupt [USART_TXC] void usart_tx_isr(void)
{
if (tx_counter)
   {
   --tx_counter;
   UDR=tx_buffer[tx_rd_index];
   if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0;
   };
}

#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+      




void putchar(char c)
{
while (tx_counter == TX_BUFFER_SIZE);
#asm("cli")
if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
   {
   tx_buffer[tx_wr_index]=c;
   if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
   ++tx_counter;
   }
else
   UDR=c;
#asm("sei")
}
#pragma used-
#endif
//------------------------------------------------------------------------


// Declare your global variables here


void main(void)
{
// Declare your local variables here
unsigned char taster=0xFF; 
unsigned char led=0xFF;    
unsigned char led_alt=0xFF;


// Input/Output Ports initialization
PORTA=0xFF;
DDRA=0x00;

PORTB=0xFF;
DDRB=0xFF; 

// Timer/Counter 0 initialization
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// External Interrupt(s) initialization
MCUCR=0x00;
EMCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x00;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud rate: 9600
UCSRA=0x00;
UCSRB=0xD8;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x17; 

// Analog Comparator initialization
ACSR=0x80;

// Global enable interrupts
#asm("sei")


while (1)
      {     
      // B: LED         A: TASTER
     
     // solange notify kleiner 128: Board Modus 
     // d.h. abfrage ob erstes Bit in UCSRA gesetzt ist (Daten empfangen)
     while (notify<0x80){
      // LED: wenn änderung zum vorigen schleifendurchlauf wird LED status an PC geschickt
      led=PINB;    
      if (led_alt!=led){
        putchar(led);
      }   
      led_alt=led;   
        
    //Board mode
      PORTB=PINA; 
     } 
     

   // solange kein Taster gedrückt wird: PC Modus
     // hier kommt man nicht mehr raus! Idee: rauswurf durch tasterdruck am board...
     while (PINA==0xFF){
        // LED: wenn änderung zum vorigen schleifendurchlauf wird LED status an PC geschickt
      led=PINB;    
      if (led_alt!=led){
        putchar(led);
      }   
      led_alt=led;  

    //PC Mode
      PORTB=getchar();
     } 
     
     notify=0x00;

      };
}

Autor: Michael G. (linuxgeek) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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:

int main(void)
{

  init_stuff();

  for(;;){                // main loop

    if( taste_changed() ){
      handle_taste();
    }

    if( uart_receive() ){
      handle_uart();
    }
  }
}



Peter

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
PINA==0xFF

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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
>
>
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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:

// ...
volatile unsigned char rx_counter;
// ...

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{  
  char status, data;

  status = UCSRA;
  data = UDR;

  if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
  {
     rx_buffer[rx_wr_index] = data;   
     if (++rx_wr_index == RX_BUFFER_SIZE) 
       rx_wr_index=0;

     if (++rx_counter == RX_BUFFER_SIZE)
     {
       rx_counter=0;
       rx_buffer_overflow=1;
     }
  }
}

// ...
// Komplettersatz für die while(1)-Schleife:

  while(1)
  {
    unsigned char gui;
    unsigned char taster;
    unsigned char led;
    static unsigned char led_alt = PORTB;

    // Eingaben holen
    //   ggf. Eingabe UART, wenn Zeichen da sind
    if (rx_counter)
      gui = getchar();
    else 
      gui = 0;

    //   Eingabe Tastenstatus
    taster = ~PINA;      // wg. Active-low Eingangsstatus negieren

    // Ausgabewert aus Eingabewert berechnen
    led = taster | gui;  // Gui ODER Tasten

    // Ausgabe machen
    if (led_alt != led)
    {
      PORTB = led;
      putchar(led);
      led_alt = led;
    }
  }


Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter + Karl Heinz

erstmal danke für eure bemühungen

es geht mir nicht um eine bestimmte taste sondern um irgendeine... also:
while (1)
      { 

// if irgendeinen taster gedrückt:
       if (PINA!=0xFF){
          PORTB=PINA;
          notify=0;
       }

// if was vom USART kommt (DIESEN ZUSTAND BEIBEHALTEN, bis was
// neues vom USART oder bis irgendeinen taster gedrückt
      if (notify>127){
         PORTB=getchar();
      }
};

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... 
??

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel wrote:
>
> so meintet ihr das doch vom aufbau her oder?

Nein, so meinen wir das nicht.


Ungefähr so:

  ....


  while( 1 ) {

    if( Taste1Pressed )
      Funktionalität1();

    if( CharFromUART == 'A' )    // soll ebenfalls Funktionalität 1 auslösen
      Funktionalität1();

    if( Taste2Pressed )
      Funktionalität2();

    if( CharFromUART == 'B' )    // soll ebenfalls Funktionalität 2 auslösen
      Funktionalität2();
  }

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.

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
while (1){    

      // B: LED         A: TASTER

    //   wenn USART neuen Status von PC empfängt, wird gui aktualisiert
    if (rx_counter){
        gui=getchar(); 
    }   
    
  // LED Status zusammensetzen aus Taster am Board und GUI Tasten
    led= (taster & gui); // entspricht: ~(~taster | ~gui)
    PORTB=led;
    taster=PINA; 
     
    // LED Ausgabe an PC schicken wenn LED Zustand sich geändert hat
    if (led_alt != led){ 
        putchar(led);
        led_alt = led;
    }          
};

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.