Ich sehe keinerlei "sei()".Hat jemand eine Idee wo da der Hund begraben sein könnte?
Hallo Leute,
ich habe miraus der Wiki dieses Beispiel herausgesucht und versucht in meinen Aufbau zu integrieren: Taster-Abfrage in C
Nur leider tut das ganze nicht so wie es soll.
Mein Beispiel sieht folgendermaßen aus:
Bei einem Tastendruck passiert leider nichts.Code://---------------------------------------- // Titel : Arcade Tastenprogrammierung //---------------------------------------- #include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include <avr/eeprom.h> #include "taster.h" typedef unsigned char BYTE; typedef unsigned int WORD; BYTE bPortB; BYTE nKeyPress; uint8_t eeFooByte; volatile uint8_t gKeyCounter; volatile signed char taster = NO_TASTER; taste_t tasten[NUM_TASTER]; const unsigned char Tabelle[] PROGMEM = {249, 164, 176, 153, 146, 130, 248, 128, 144}; SIGNAL (SIG_OVERFLOW0) { static unsigned char count_ovl0; unsigned char ovl0 = count_ovl0+1; if (ovl0 >= 39) { get_taster (1, PINB & (1<<PB4)); ovl0 = 0; } count_ovl0 = ovl0; } void ioinit() { PORTB |= 1 << PB4; DDRD = 0xFF; TCCR0 = 1 << CS00; TIMSK |= (1 << TOIE0); } int main (void) { ioinit(); bPortB = 1; nKeyPress = 0; // nKeyPress = eeprom_read_byte(&eeFooByte); gKeyCounter = 0; tasten[0].mode = TM_SHORT; tasten[1].mode = TM_LONG; tasten[2].mode = TM_REPEAT; while(1) { signed char tast = taster; PORTD = pgm_read_byte(&Tabelle[nKeyPress]); switch (tast) { default: case NO_TASTER: break; case 1: if (nKeyPress < 8) { nKeyPress++; } else { nKeyPress = 0; } break; case 1+TASTER_LONG: eeprom_write_byte(&eeFooByte, nKeyPress); break; } if (tast != NO_TASTER) taster = NO_TASTER; } return 0; } void get_taster (const unsigned char num, unsigned char tast) { const taste_t * const ptast = & tasten[num]; const unsigned char taster_old = ptast->old; unsigned char pressed, press, release, mode, delay; #if TASTER_LEVEL tast = !!tast; #else tast = !tast; #endif /* Taster bleibt gedrueckt */ pressed = taster_old & tast; /* Taster neu gedrueckt */ press = ~taster_old & tast; /* Taster losgelassen */ release = taster_old & ~tast; *((unsigned char *) & ptast->old) = tast; tast = NO_TASTER; mode = ptast->mode; delay = ptast->delay; if (press) { if (mode != TM_LONG) tast = num; delay = 0; } else if (pressed) { if (delay < 0xfe) delay++; } else if (release) { if (mode == TM_LONG && delay != 0xff) tast = num; } if (mode == TM_LONG) { if (delay == TASTER_DELAY_LONG) { tast = TASTER_LONG + num; delay = 0xff; } } else if (mode == TM_REPEAT) { if (delay == TASTER_REPEAT_DELAY) { tast = num; delay = TASTER_REPEAT_DELAY - TASTER_REPEAT; } } if (taster == NO_TASTER) taster = tast; *((unsigned char *) & ptast->delay) = delay; }
Hat jemand eine Idee wo da der Hund begraben sein könnte?
Ich sehe keinerlei "sei()".Hat jemand eine Idee wo da der Hund begraben sein könnte?
MfG
Stefan
Du hast recht!Zitat von sternst
Habs ergänzt.
Leider wars das jedoch noch nicht.
Hat vielleicht jemand ein einfacheres Beispiel für mich?
Im Grunde möchte ich nur abfragen ob der Taster kurz oder lan(ca. 2 Sek) gedrückt wurde.
Und je nachdem entweder eine Variable um 1 hochzählen oder den aktuellen Wert im EEPROM speichern.
Hallo DerSchatten,
da ich kein C beherrsche, werde ich mal versuchen, dir ein einfaches Beispiel (also die Funktionsweise) zu erklären:
Wenn der Taster gedrückt worden ist, geht das Programm in eine kleine Schleife, in welcher 1ms lang gewartet wird und dann wird eine Variable erhöht. Wenn der Taster wieder losgelassen wurde, verlässt der µC die Schleife. Nun wird die Variable abgefragt, ob sie größer als 2000 (also 2000ms entspricht 2s) ist. Anschließend soll der µC darauf reagieren und die Variable muss wieder auf 0 gesetzt werden. Allerdings ist das ganze nicht gerade "schnell", da der µC ziemlich lange in der Schleife feststecken kann. Außerdem musst du aufpassen, dass die Variable nicht überläuft.
Hier mal ein Pseudocode:
Hier mal das ganze in BASCOM, ist meiner Meinung nach leicht verständlich:Code:wenn taster1 = gedrückt dann solange taster1 gedrückt 1ms warten variable xy um 1 erhöhen wenn nicht mehr gedrückt, schleife verlassen wenn variable xy >= 2000 taster = mindestens 2s lang gedrückt allenfalls taster = maximal 2s lang gedrückt ende wenn varaible xy = 0 ende wenn
Ich hoffe, ich konnte dir helfen.Code:if t1 = 0 then while t1 = 0 waitms 1 xy = xy + 1 wend if xy >= 2000 taster = 2 else taster = 1 endif xy = 0 endif
Wenn du das ganze allerdings schneller programmieren möchtest, solltest du einen timer so einstellen, dass er jede millisekunde (am besten) überläuft und dann das ganze in die ISR packen.
Gruß
Chris
eine aufbau möglich keit wäre
do
wenn taster=gedrückt dann gedrückt dauer+1
wenn nicht dann wenn gedrück dauer >10 dann variable+1
wenn gedrückt dauer>20 dann in eepromspeichern
dedrückt dauer=0
warte 100ms
müsste so gehen
loop
Hm, wo ist der Fehler?
Code:while(1) { PORTD = pgm_read_byte(&Tabelle[nKeyPress]); if (bit_is_clear (PINB, PINB0)) { if (bPortB) // wenn Taster gedrückt { dauer++; } else // wenn nicht gedrückt { if (dauer > 10) { if (nKeyPress < 8) { nKeyPress++; bPortB = 0; } else { nKeyPress = 0; bPortB = 0; } } if (dauer > 20) // wenn länger gedrückt { eeprom_write_byte(&eeFooByte, nKeyPress); dauer = 0; Warte (100); } } } else { bPortB = 1; } } return 0;
Mit meinen bescheidenen Kenntnissen in C tue ich mir immer schwer, daher auch meine Unfähigkeit (und Abneigung), Codebruchstücke auf Fehler zu durchleuchten. Vor allem bei minimalistischen Kommentaranteilen.Zitat von DerSchatten
Bei mir gibt es Tasten, die beim Drücken den zugehörigen Eingang - mit internem PullUp - einfach auf GND legen. Ich habe mir für die Tastenverwaltung eine Timerroutine geschrieben, die mit 100 Hz eine ISR aufruft. Darin wird u.a. dies gemacht:
So - damit kann ich im main oder sonstwo bequem feststellen, ob und wie lange eine Taste gedrückt wurde - alles über 2,5 sec ist eben "ewig". Ausserdem ist damit auch feststellbar, wie lange die Taste nach dem letzten Drücken gelöst wurde - auch hier beginnt die Ewigkeit schon bei 2,5 sec. Läuft problemlos - und ist recht resistent gegen Spikes und so.Code:// Globale Deklarationen und so: #define rLED 3 // Rote LED auf PB3 #define TAU 1 // Taster "Aufwärts", PB1 #define TAB 2 // Taster "Abwärts", PB2 = "Start"Taste volatile uint8_t TABsts; // Status derTaste TAB // = 0 <=> nicht gedrückt, =1 <=> gedrückt volatile uint8_t TAUsts; // Status derTaste TAU, wie oben volatile uint8_t TABcnt; // Counter für Taste TAB volatile uint8_t nTABcnt; // Counter für Taste notTAB volatile uint8_t TAUcnt; // Counter für Taste TAU, wie oben volatile uint8_t nTAUcnt; // Counter für Taste notTAU, wie oben // // ================================================================================ // === Nicht unterbrechbare ISR für timer1 ======================================= // Interrupt mit ca. 100 Hz/10 ms. Diese ISR wird benutzt // A zum Auslesen der Tasten // Nach Ende der Routine sind die Tastenstati in den Statusbytes // ... // ISR(TIM1_COMPA_vect) // Vektor 4 (1 ... 4 !!!) doc S 50 { ... // - - Zuerst für TAB - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TABsts = (!(PINB & (1<<TAB))); // Status von Taste TAB holen if (TABsts) // Taste TAB gedrückt? { if (TABcnt < 254) // Wenn counter < 250 { TABcnt ++; // dann hochtackern nTABcnt = 0; // und Nicht-TABcount auf Null setzen } } else // Taste TAB ist nicht gedrückt { if (nTABcnt < 254) // Wenn Not-counter < 250 { nTABcnt ++; // dann hochtackern TABcnt = 0; // und TABcount auf Null setzen } } // .... und so weiter // ================================================================================ // ================================================================================ // === Initialisierung fuer Timer1 tiny85 ======================================== // === Interner Oszillator, 8 MHz mit CKDIV8 ================================= void TC1TMR_init(void) // Init Tmr/Cntr1, 8-Bit auf ca. 100 Hz = 10 ms { TCCR1 |= (1<<CTC1); // Timer im CTC-Mode, Top=OCRA doc S 92 TCCR1 |= (1<<CS12)|(1<<CS11)|(1<<CS10); // Prescaler Clock1/64 doc S 93 OCR1C = 152; // Preset/Preload = 152 => getestet ca. 0,010s @ 1,0Mhz TIMSK |= (1<<OCIE1A); // Tmr/Cntr1 CompareA interrupt enabled } // ================================================================================
Ob das für Dich nun einfach(er) ist, weiß ich natürlich nicht.Zitat von DerSchatten
Ciao sagt der JoeamBerg
Hi, vielen dank!
Ich bin jedoch langsam am verzweifeln.
Ich blick hier nicht ganz durch.
So wie ich das verstanden habe machst du alles mit Interrupts, oder?
AVRStudio meckert bei mir fast bei jeder Zeile wenn ich den Code 1:1 reinkopiere.
Was macht dieses Teil hier:
ISR(TIM1_COMPA_vect)
Wo gehört da die zugemachte Klammer hin?
Bei TCCR1 meint er das die Variable nicht definiert ist.
Verzweifel!
Du machst einen beliebten Anfängerfehler: Du programmierst irgendwo zusammenkopierte Codeteile ohne jeden Peil, was da passiert - und wir sollns richten.Zitat von DerSchatten
1. Du hast nirgendwo genannt, welchen Controller Du verwendest, Takt, etc.
2. Du hast möglicherweise ein älteres AVRStudio/AVRGCC. Ich denke dass als ISR-Aufruf die Form "ISR(TIM1_COMPA_vect)" üblich ist. Die Form "SIGNAL (SIG_OVERFLOW0)" ist doch schon etwas veraltet, oder nicht ? ?
3. Du hast nicht gemerkt, dass meine Codebeispiele für einen tiny85 steht - weil Du kopierst ohne zu lesen, was da steht.
4. Hast Du eine Dokumentation zu Deinem Controller (und GELESEN) ?
Gibt es in Deinem Controller denn ein Register namens TCCR1?
5. Dein Compiler stolpert spätestens über die Stelle, an der ich geschrieben hatte:
// .... und so weiter
denn mein Code ist ein BEISPIEL - kein vollständiges Programm für einen mir garnicht bekannten Controller.
6. Lern mal die Grundlagen der Programmierung von Mikrocontrollern in C - sonst wirst Du noch mehr verzweifeln. Zu Grundlagen der Programmierung von Mikrocontrollern gibts hier etliche Empfehlungen (klick).
Und warum das alles lesen?Damit Du weisst, was Du da gemacht hast.Zitat von DerSchatten
Viel Erfolg.
Ciao sagt der JoeamBerg
Lesezeichen