PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATTiny13A Schalter abfragen/entprellung mit Variablen



Denn Is
10.06.2014, 23:19
Hallo liebe Community!

Seit einigen Tagen bin ich "stiller" Leser hier und habe mir schon einige Tipps und Anregungen geholt :)

Leider sitze ich noch immer an einem kleinen Problem:

Ich habe einen ATTiyn13A auf einem Versuchsboard aufgebaut. Als Programm nutze ich das AtmelStudio 6.1

-Die Anschlüsse PB0 und PB1 sind jeweils mit einer LED verbunden.

-Die Anschlüsse PB3 und PB4 jeweils mit einem Taster der mit der anderen Seite auf GND liegt.

Das Endergebnis soll einmal so Aussehen das eine gewisse Reihenfolge und Häufigkeit einiger Taster gedrückt werden muss um z.B. eine Segmentanzeige zu Aktivieren. (Klar das der Tiny13 da schnell ausgelastet ist mit Ports aber ich habe auch noch einen 2313A da. Der Tiny13 ist erstmal für den Test gedacht)

Z.B. wenn Taster 1 5mal betätigt wurde und danach Taster 2 3mal soll auf der Segmentanzeige eine 8 aufleuchten.


Angefangen habe ich mit einem Taster der wenn er gehalten wurde eine LED leuchten lies. Dies funktionierte auch.

Wenn ich jedoch statt der LED eine Variable hochzählen will und zb wenn die Variable 5 erreicht die LED anschalten soll geht sie gar nicht an. Egal wie schnell oder häufig man die Taste drückt.

Dann habe ich versucht mit jedem Tastendruck die LED zu invertieren. dh. 1.Druck an, 2.Druck aus usw... Jetzt geht die LED allerdings mal an und mal wieder aus, mal bleibt sie einfach an... Sehr unkontrolliert...

Da habe ich an eine Entprellung gedacht die wie unten eingebaut ist. Jedoch flackert die LED jetzt nur währen die Taste gedrückt ist und die Schaltzustände sind weiterhin sehr unkontrolliert....

Vielleicht kann mir jemand einen Denkanstoß geben?

Hier das aktuelle Programm:

/*
* LED_Anzeige.c
*
* Created: 18.05.2014 19:27:56
* Author: Dennis
*/
#define F_CPU 9000000UL
#include <util/delay.h>
#include <avr/io.h>

unsigned char Taster1;
unsigned char Taster2;

void entprellung( volatile uint8_t *port, uint8_t maske ) {
uint8_t port_puffer;
uint8_t entprellungs_puffer;

for( entprellungs_puffer=0 ; entprellungs_puffer!=0xff ; ) {
entprellungs_puffer<<=1;
port_puffer = *port;
_delay_us(150);
if( (*port & maske) == (port_puffer & maske) )
entprellungs_puffer |= 0x01;
}
}


int main (void)
{
DDRB=0x03; //Ein /Ausgänge ;
PORTB = 0x18; //Pullup aktivieren (PB3+PB4)
Taster1 = 0;
Taster2 = 0;
while(1)
{
entprellung( &PINB, (1<<PINB3) ); // ggf. Prellen abwarten
if(!(PINB & (1 << PB3)))
{
Taster1++;
PORTB^=0x02; //PB1 invertieren

}
entprellung( &PINB, (1<<PINB4) ); // ggf. Prellen abwarten
if(!(PINB & (1 << PB4)))
PORTB^=0x01; //PB0 invertieren
//PORTB&=~(1<<PB0); //PB0 ausschalten
}
}

Vielen Dank für eure Mühe im Voraus!

Gruß
Dennis

oberallgeier
11.06.2014, 08:07
Hallo Dennis, willkommen im Forum!

... Vielleicht kann mir jemand einen Denkanstoß geben? ...Zuerst kurz und schnell zum Problem (bei mir kommen Prellprobleme ohne Entprellen fast nicht vor - seltsam). Eine pfiffige Lösung zum Entprellen ist es, die Taste mehrfach abzufragen (vielleicht quick´n-dirty ...) :

if ( (taste-an) || (taste-an) || (taste-an) ) { irgendwas(); }
das steht irgendwo in den Tiefen des Forums als :
while((PollSwitch() == 0) || (PollSwitch() == 0) || (PollSwitch() == 0))

So ne Lösung läuft auf meinem Pacer total problemlos (https://www.roboternetz.de/community/threads/48271-ISP-zum-Aufklippen-f%C3%BCr-THT-Controller) - der Pacer hatte anfangs auch nen tiny13.

Noch ein bisschen wie ich mir die Tastenbedienung zurecht gestrickt habe :

// ...
#define IsBitSet(ADDR,BIT) (((ADDR) & (1<<BIT))?1:0) // Fragt Bit = 1?
#define IsBitClr(ADDR,BIT) (!((ADDR) & (1<<BIT))?1:0) // Fragt Bit = 1?
// ...
#define PrtTAST PIND //
#define Tst_1 6 //
#define Tst_2 7 //
// ...
#define Taste1_an IsBitClr (PrtTAST, Tst_1) // Taster 1 gedrückt ??
#define Taste1_aus IsBitSet (PrtTAST, Tst_1) // Taster 1 gelöst ??
#define Taste2_an IsBitClr (PrtTAST, Tst_2) // Taster 2 gedrückt ??
#define Taste2_aus IsBitSet (PrtTAST, Tst_2) // Taster 2 gelöst ??
//... oder mit Buchstaben (verwende ich mittlerweile bei Tasten lieber) :
#define TasteA_an IsBitClr (PRTtstLCD, Tst_A) // Taster A gedrückt ??
#define TasteA_aus IsBitSet (PRTtstLCD, Tst_A) // Taster A gelöst ??
#define TasteB_an IsBitClr (PRTtstLCD, Tst_B) // Taster B gedrückt ??
#define TasteB_aus IsBitSet (PRTtstLCD, Tst_B) // Taster B gelöst ??
// ... und das geht NOCH deutlich kürzer in dieser Form :
#define TAan IsBitClr (PRTtstLCD, Tst_A) // Taster A gedrückt ??
#define TAaus IsBitSet (PRTtstLCD, Tst_A) // Taster A gelöst ??
#define TBan IsBitClr (PRTtstLCD, Tst_B) // Taster B gedrückt ??
#define TBaus IsBitSet (PRTtstLCD, Tst_B) // Taster B gelöst ??
// - - - - - - - - - - - - - - -
// Da dies keine Funktion ist, erfolgt der Aufruf so (NUR beispielsweise) :
// - - - - - - - - - - - - - - -
// ...
if ( TAan ) off = 99; // Taste A gedrückt ?? Ausgangsflag setzen
while ( TAan ) {} // Weiter nur mit gelöster Taste
if ( off == 99 ) //
{ //
off = 0; //
break; //
} //

Hoffentlich hilfts Dir bei Deiner Tastendrückerei.

Nachtrag: Dein 150µs-wait für die Entprellung ist schon ok, beim Tastendrücken hat der Controller sozusagen alle Zeit der Welt. Ich orientiere mich bei Mehrfach-Tastendruck am Zeitschema meiner TV-IR-Fernbedienungen. Die senden bei gedrückter Taste etwa alle 100ms - 150ms (MILLI-) ein Signal, wenn man mehrere, unterschiedliche Tasten drückt werten die auch ein Toggelbit aus (wurde die Taste zwischendurch gelöst?) und lassen einem z.T über zwei Sekunden Zeit für ein Mehrfachtasten-Telegramm.

Denn Is
11.06.2014, 11:21
Mhh hilft mir noch nicht wirklich weiter. Die einfachen "Entprellung" durch die || in der Abfrage löst das Problem leider nicht das weiterhin die LEDs unkontrolliert anschalten oder anbleiben bei Tastendruck etc... Vielleicht liegt das Problem auch gar nicht am entprellen sondern an meiner Port invertierung?

Mit deinem Code habe ich folgendes zusammengestrickt, da funktioniert jedoch gar nichts mehr :D


#define F_CPU 9000000UL
#include <util/delay.h>
#include <avr/io.h>

#define IsBitSet(PINB,PINB3) (((PINB) & (1<<PINB3))?1:0) // Fragt Bit = 1?
#define IsBitClr(PINB,PINB3) (!((PINB) & (1<<PINB3))?1:0) // Fragt Bit = 1?
// ...
#define PrtTAST PINB //
//#define PrtLED PORTB //
#define Tst_1 PB3 //
#define Tst_2 PB4 //
//#define Led1
//#define Led2

#define Taste1_an IsBitClr (PrtTAST, Tst_1) // Taster 1 gedrückt ??
#define Taste1_aus IsBitSet (PrtTAST, Tst_1) // Taster 1 gelöst ??
#define Taste2_an IsBitClr (PrtTAST, Tst_2) // Taster 2 gedrückt ??
#define Taste2_aus IsBitSet (PrtTAST, Tst_2) // Taster 2 gelöst ??

int main (void)
{
DDRB=0x03; //Ein /Ausgänge ;
PORTB = 0x18; //Pullup aktivieren (PB3+PB4)
// Taster1 = 0;
// Taster2 = 0;
while(1)
{
if ( Taste1_an ) off = 99; // Taste A gedrückt ?? Ausgangsflag setzen

while ( Taste1_an ) {} // Weiter nur mit gelöster Taste
if ( off == 99 ) //
{ //
PORTB^=0x02; //PB1 invertieren
off = 0; //
//
} //
}
}

- - - Aktualisiert - - -

So folgendes Programm ist der "Aktuelle" Stand:


// Definitionen //

#define F_CPU 9000000UL
#include <util/delay.h>
#include <avr/io.h>

// Variablen //

unsigned char True;
unsigned char False;
unsigned char Taster1;
unsigned char Taster2;



// Hauptprogramm //

int main (void)
{
DDRB=0x06; // I/O Ports PB1+PB2;
PORTB = 0x18; //Pull up aktivieren (PB3+PB4)
True = 1; //Startwert zuweisung
False = 0; //Startwert zuweisung
Taster1 = 0; //Startwert zuweisung
Taster2 = 0; //Startwert zuweisung

while(1)
{
// Taster abfragen //

if(!(PINB & (1 << PB3))||!(PINB & (1 << PB3))||!(PINB & (1 << PB3))) //Tasterabfrage PB3
{
Taster1++; //Taster inkrementieren

}
if(!(PINB & (1 << PB4))||!(PINB & (1 << PB4))||!(PINB & (1 << PB4))) //Tasterabfrage PB4
{
Taster2=True; //Taster 2 gedrückt
}

// LED Anzeige //

if (Taster1>=5) //Wenn Taster1 größer gleich 5 erreicht
{
PORTB|=(1<<PINB2); //PB2 an
PORTB&=~(1<<PINB1); //PB1 aus
Taster1=False; //Taster 1 zurücksetzen
}
if (Taster2==True) //Wenn Taster 2 gedrückt
{
PORTB&=~(1<<PINB2); //PB2 aus
PORTB|=(1<<PINB1); //PB1 an
Taster2=False; //Taster 2 zurücksetzen
}
}
}

Das Programm SOLLTE nach fünfmaliger Betätigung des Taster1 die LED 2 anschalten und LED 1 aus. Sowie (derzeit) nach einmaliger Betätigung des Taster 2 die LED 1 anschalten und LED 2 aus.

Das Programm schaltet jedoch die LED 2 bereits beim ERSTEN betätigen des Taster1 ein und wartet nicht bis der Wert größer fünf wird. Hat da jemand einen Rat?

Grüße

Denn Is
12.06.2014, 16:48
Mhh hat dazu keiner eine Idee? Oder nutzen alle das gute Wetter? :)

Ich habe jetzt durch den Debug wohl einen Fehleransatz gefunden...

Solange der Taster "gedrückt" ist zählt die Variable hoch, was bedeuten könnte ich kann den Taster nicht schnell genug los lassen eh das Programm 5 mal an der Stelle vorbei kommt.

Kann man irgendwie nur die steigende oder fallende Flanke des Tasters abfragen so das zwischen zwei inkrementierungen neu gedrückt werden muss?

Wsk8
12.06.2014, 21:17
Du musst den letzten Wert immer speichern und nur wenn LastValue != CurrentValue && Currentvalue == Gedrückt, dann +1.

mfg

Denn Is
16.06.2014, 10:30
Danke! Das hat schon mal ein ganzes Stück weiter gebracht :)

Hatte heute leider erst Zeit zum testen. Wenn ich zwischen zwei Tastendrücken nun 1-2 sekunden Warte klappt es wunderbar! Leider noch nicht ganz wenn ich die Taste mehrfach schnell hintereinander drücke. Dann leuchtet die LED teilweise schon beim dritten oder vierten druck.

Hat da jemand noch einen Verbesserungsvorschlag?

Hier der aktuelle Code:


// Definitionen //

#define F_CPU 9000000UL
#include <util/delay.h>
#include <avr/io.h>




// Variablen //

unsigned char True;
unsigned char False;
unsigned char Taster1;
unsigned char Taster2;
unsigned char Zustand1aktuell;
unsigned char Zustand1alt;
unsigned char Zustand2aktuell;
unsigned char Zustand2alt;

// Hauptprogramm //

int main (void)
{
DDRB = 0x06; // I/O Ports PB1+PB2;
PORTB = 0x18; //Pull up aktivieren (PB3+PB4)
True = 1; //Startwert zuweisung
False = 0; //Startwert zuweisung
Taster1 = 0; //Startwert zuweisung
Taster2 = 0; //Startwert zuweisung
Zustand1aktuell = 0;
Zustand1alt = 0;
Zustand2aktuell = 0;
Zustand2alt = 0;

while(1)
{
// Taster abfragen //

if(!(PINB & (1 << PINB3))||!(PINB & (1 << PINB3))||!(PINB & (1 << PINB3))) //Tasterabfrage PB3
{
Zustand1aktuell=1;
Zustand1alt=1;
}
else
{
Zustand1aktuell=0;
}

if(!(PINB & (1 << PINB4))||!(PINB & (1 << PINB4))||!(PINB & (1 << PINB4))) //Tasterabfrage PB4
{
Zustand2aktuell=1;
Zustand2alt=1;
}
else
{
Zustand2aktuell=0;
}

if (Zustand1aktuell!=Zustand1alt)
{
Taster1++; //Taster inkrementieren
Zustand1alt=0;
}

if (Zustand2aktuell!=Zustand2alt)
{
Taster2=True; //Taster 2 gedrückt
Zustand2alt=0;
}

// LED Anzeige //

if (Taster1>=5) //Wenn Taster1 größer gleich 5 erreicht
{
PORTB|=(1<<PINB2); //PB2 an
PORTB&=~(1<<PINB1); //PB1 aus
Taster1=False; //Taster 1 zurücksetzen
}
if (Taster2==True) //Wenn Taster 2 gedrückt
{
PORTB&=~(1<<PINB2); //PB2 aus
PORTB|=(1<<PINB1); //PB1 an
Taster2=False; //Taster 2 zurücksetzen
}
}
}

Sisor
16.06.2014, 15:00
Hat da jemand noch einen Verbesserungsvorschlag?
Erstmal etwas vereinfachen und lesbarer machen;):


// Programm 'Taster abfragen'
#define F_CPU 9000000UL
#include <util/delay.h>
#include <avr/io.h>

// Definitionen
typedef uint8_t byte; // bzw. unsigned char

// Abfrage-Funktion eines Tasters
// mit Software-Entprellung
byte isPressed(byte pin, byte pinNr) {
return (pin & (1 << pinNr)) || (pin & (1 << pinNr)) || (pin & (1 << pinNr));
}

// Hauptprogramm
int main (void) {
DDRB = 0x06; // I/O Ports PB1+PB2;
PORTB = 0x18; // Pull up aktivieren (PB3+PB4)

// Variablen
enum btn_states {not_pressed, pressed, checked};
byte btn1 = not_pressed;
byte btn2 = not_pressed;
byte btn1_counter = 0;

while(1) {
// Taster1 abfragen
if (isPressed(PINB, PINB3)) // Taster1 (PB3) gedrückt?
if (btn1 == not_pressed) { // erste Abfrage im Schaltmoment?
btn1_counter++;
btn1 = pressed;
}
else btn1 = not_pressed;

// Taster2 abfragen
if (isPressed(PINB, PINB4)) // Taster2 (PB4) gedrückt?
if (btn2 == not_pressed) // erste Abfrage im Schaltmoment?
btn2 = pressed;
else btn2 = not_pressed;

// LED Anzeige steuern
if (btn1_counter == 5 && btn1 == pressed) {// Taster 1 5x gedrückt?
PORTB |= (1 << PINB2); // PB2 an
PORTB &= ~(1 << PINB1); // PB1 aus
btn1 = checked;
}
else if (btn2 == pressed) { // Wenn Taster 2 gedrückt
PORTB |= (1<<PINB1); // PB1 an
PORTB &= ~(1<<PINB2); // PB2 aus
btn1_counter = 0; // Zähler für Taster 1 zurücksetzen
btn2 = checked;
}
}
}

Denn Is
23.06.2014, 16:55
Sorry das ich jetzt erst antworte aber war über das lange WE im Urlaub :)

Soo habe jetzt deinen Code mal so 1zu1 in mein Atmelstudio übertragen und auf den Tiny13 gespielt.

Leider leuchtet LED 1 nun dauerhaft(LED2 aus) bis Taster 2 gedrückt wird dann wechselt die LED (LED1 aus LED2 an) bis der Taster wieder losgelassen wurde (LED1 wieder an)
Taster 1 zeigt gar keine reaktion...

Leider habe ich deine "Vereinfachung" auch noch nicht ganz durchschaut...

wäre:

if (btn1 == not_pressed) { // erste Abfrage im Schaltmoment?
nicht eigentlich die Funktionsschleife wenn der Taster NICHT gedrückt ist?

Was verursacht der btn zustand "checked" zb bei:
btn1 = checked; ?

Ich bekomme auch beim Compilieren zwei Warnings:

Warning 1 suggest explicit braces to avoid ambiguous 'else' [-Wparentheses] C:\Users\Dennis\Documents\Geocaching Programme\Taster\Taster\Taster\Taster_org.c 28 6 Taster
Warning 2 suggest explicit braces to avoid ambiguous 'else' [-Wparentheses] C:\Users\Dennis\Documents\Geocaching Programme\Taster\Taster\Taster\Taster_org.c 36 6 Taster

Sisor
23.06.2014, 21:07
Ok, ich geb zu viel leichter ist das auch nicht zu verstehen...


Ich bekomme auch beim Compilieren zwei Warnings...

Grund:
else btn2 = not_pressed;

mit Klammern:

else {
btn2 = not_pressed;
}


Was verursacht der btn zustand "checked" ?
Wenn die Taste gedrückt wird, aber der counter schon ein hochgezählt hat, brauche ich einen weiteren Zustand, damit der Counter erst nach Loslassen und erneutem Drücken wieder hochzäht. 'checked' wie 'bereits geprüft'

Ich hatte eine Klammer vergessen, die die Logik verändert hatte.
Hier korrigert:


#define F_CPU 9000000UL
#include <util/delay.h>
#include <avr/io.h>
typedef uint8_t byte;

byte isPressed(byte pin, byte pinNr) {
return (pin & (1 << pinNr)) || (pin & (1 << pinNr)) || (pin & (1 << pinNr));
}

// Hauptprogramm
int main (void) {
DDRB = 0x06; // I/O Ports PB1+PB2;
PORTB = 0x18; // Pull up aktivieren (PB3+PB4)

// Variablen
enum btn_states {not_pressed, pressed, checked};
byte btn1 = not_pressed;
byte btn2 = not_pressed;
byte btn1_counter = 0;

while(1) {
// Taster1 abfragen
if (isPressed(PINB, PINB3)) { // Taster1 (PB3) gedrückt?
if (btn1 == not_pressed) { // erste Abfrage im Schaltmoment?
btn1_counter++;
btn1 = pressed;
}
}
else {
btn1 = not_pressed;
}

// Taster2 abfragen
if (isPressed(PINB, PINB4)) // Taster2 (PB4) gedrückt?
if (btn2 == not_pressed) { // erste Abfrage im Schaltmoment?
btn2 = pressed;
}
else {
btn1 = not_pressed;
}

// LED Anzeige steuern
if (btn1_counter == 5 && btn1 == pressed) {// Taster 1 5x gedrückt?
PORTB |= (1 << PINB2); // PB2 an
PORTB &= ~(1 << PINB1); // PB1 aus
btn1 = checked;
}
else if (btn2 == pressed) { // Wenn Taster 2 gedrückt
PORTB |= (1<<PINB1); // PB1 an
PORTB &= ~(1<<PINB2); // PB2 aus
btn1_counter = 0; // Zähler für Taster 1 zurücksetzen
btn2 = checked;
}
}
}

Das sollte keine fertige Lösung sein, sondern nur ein Ansatz, wie man das Tasterproblem auch anders angehen kann.
Pick dir das raus, was du gut findest / gebrauchen kannst;).

Sisor
24.06.2014, 23:26
Ich hab mir mal 2 Std Zeit genommen und ein Programm geschrieben, dass deine Anforderungen erfüllen sollte.:p

Ist getestet und arbeitet einwandfrei. Es werden 4 verschiedene Codes (Tasterfolgen) abgefragt. Kann aber fast beliebig erweitert werden. Es wurden 4 Taster auf den Pins 4 bis 7 benutzt.

Leider ist es für Arduino. Aber sollte mit wenig Aufwand für den Tiny angepasst werden können.;)


// button pins
// 4 is pin of button1
// 5 is pin of button2
// 0 means end of buttons
byte buttons[] = {4, 5, 6, 7, 0};
// first 0 is for counting in function
// 1,1,2,1 is code (press Button1, 2, 2, 1 for activating)
// last 0 is end of code
byte code1[] = {0, 1, 2, 2, 1, 0};
byte code2[] = {0, 2, 1, 2, 2, 0};
byte code3[] = {0, 3, 3, 3, 0};
byte code4[] = {0, 1, 2, 3, 4, 3, 2, 1, 0};
byte* codes[] = {code1, code2, code3, code4, 0};


byte initButtons(byte buttons[]) {
// setup button pins for reading
byte counter = 0;
while(buttons[counter]) pinMode(buttons[counter++], INPUT);
}

byte checkButtons(byte* pressed_btn, byte* codes[], byte buttons[]) {
static byte last_pressed = 0;
if (last_pressed) {
if(!digitalRead(buttons[last_pressed-1])) return 0; // Button still pressed? -> return
else { last_pressed = 0; } // else: not pressed anymore -> go on
}
*pressed_btn = 0;
byte btn_counter = 0; // iterate over all buttons
byte code_counter = 0; // iterate over all codes
while(buttons[btn_counter]) {
byte is_pressed = !digitalRead(buttons[btn_counter]); // check buttons one after another
if(is_pressed) {
last_pressed = btn_counter+1; // store pressed button number
*pressed_btn = last_pressed; // write pressed button number to external variable pressed_btn
while(codes[code_counter]) { // check all codes one after another
if(codes[code_counter][(codes[code_counter][0])+1] == btn_counter + 1) { // is the pressed button nr equal to next button nr in code?
codes[code_counter][0]++;
if(!codes[code_counter][(codes[code_counter][0])+1]) { // code veryfied?
byte i = 0; while(codes[i]) { *codes[i++] = 0; } // reset all counters
return code_counter+1; // returns number of detected code
}
}
else { codes[code_counter][0] = 0; }
code_counter++;
}
code_counter = 0;
}
btn_counter++;
}
return 0; // 0 means no code veryfied
}

void setup() {
initButtons(buttons);
Serial.begin(57600);
}

void loop() {
byte btn;
byte detected_code = checkButtons(&btn, codes, buttons);
//if (btn) { Serial.print("Button pressed: "); Serial.println(btn); }
if (detected_code) { Serial.print("Code detected: ");Serial.println(detected_code); }
}

Ausgabe nach dem Drücken der Taster 1,2,2,1 (in dieser Reihenfolge):

Code detected: 1
---
Ausgabe nach dem Drücken der Taster 1, 2, 3, 4, 3, 2, 1 (in dieser Reihenfolge):

Code detected: 4

Denn Is
25.06.2014, 16:46
Vielen Dank erstmal für deine Bemühung!

Leider ist das zweite Beispiel von dir weitaus zu kompliziert für meine C und uC Kenntnisse :D

Daher werde ich erstmal versuchen mit dem davor weiter zu arbeiten und das irgendwie zum laufen zu bekommen :)

Hab schon wieder ein wenig rumprobiert aber noch keine zufriedenstellende Lösung gefunden :D

Gruß

Sisor
26.06.2014, 22:49
Na, dann will ich dich mal nicht im Regen stehen lassen:p.
Ich kann's nicht testen, weil ich die Hardware nicht besitze, aber das hier könnte klappen:


// prg: check buttons for codes

#define F_CPU 9000000UL
#include <util/delay.h>
#include <avr/io.h>
typedef uint8_t byte;


// button pins
// PINB3 is pin of button 1
// PINB4 is pin of button 2
// 0 means end of buttons
byte buttons[] = {PINB3, PINB4, 0};
// first 0 is for counting in function
// 1,1,2,1 is code
// last 0 is end of code
byte code1[] = {0, 1, 2, 2, 1, 0};
byte code2[] = {0, 2, 1, 2, 2, 0};
byte code3[] = {0, 2, 1, 1, 2, 2, 0};
byte* codes[] = {code1, code2, code3, 0};

// prototypes
byte isButtonPressed(byte pinNr);
void resetInput();
byte checkButtons(byte* button, byte* codes[], byte buttons[]);


// main
int main (void) {
DDRB = 0x06; // I/O ports PB1+PB2;
PORTB = 0x18; // activate pull up (PB3+PB4)
byte btn; // if a button is pressed this variable will know

while(1) {
byte code_nr = checkButtons(&btn, codes, buttons);
// codes switch LEDs
if (code_nr == 1) {
PORTB |= (1 << PINB2); // PB2 on
PORTB &= ~(1 << PINB1); // PB1 off
}
else if (code_nr == 2) {
PORTB |= (1<<PINB1); // PB1 on
PORTB &= ~(1<<PINB2); // PB2 off
}
else if (code_nr == 3) {
PORTB &= ~(1<<PINB1); // PB1 off
PORTB &= ~(1<<PINB2); // PB2 off
}
}
}

// functions

byte isButtonPressed(byte pinNr) {
byte pin = PINB;
return (pin & (1 << pinNr)) || (pin & (1 << pinNr)) || (pin & (1 << pinNr));
}

void resetInput() {
byte i = 0; while(codes[i]) { *codes[i++] = 0; }
}

byte checkButtons(byte* button, byte* codes[], byte buttons[]) {
static byte last_pressed_button = 0;
if (last_pressed_button) { // was button pressed last time?
if(isButtonPressed(buttons[last_pressed_button-1])) // is button still pressed?
return 0; // -> return
else {
last_pressed_button = 0; // else: not pressed anymore -> go on
}
}
*button = 0;
byte button_iterator = 0; // iterate over all buttons
byte code_iterator = 0; // iterate over all codes
while(buttons[button_iterator]) {
if(isButtonPressed(buttons[button_iterator])) { // check buttons one after another
*button = button_iterator + 1; // write pressed button number to external variable pressed_btn
last_pressed_button = *button; // store pressed button number
while(codes[code_iterator]) { // check all codes one after another
byte* code_pos_ptr = codes[code_iterator]; // first byte of codes array is for current position
if(codes[code_iterator][(*code_pos_ptr)+1] == button_iterator + 1) { // is the pressed button nr equal to next button nr in code?
(*code_pos_ptr)++; // -> next position
if(!codes[code_iterator][(*code_pos_ptr)+1]) { // code veryfied
resetInput(); // reset all counters
return code_iterator + 1; // returns number of detected code
}
}
else { *code_pos_ptr = 0; }
code_iterator++;
}
code_iterator = 0; // prepare for next button check
}
button_iterator++;
}
return 0; // 0 means no code veryfied
}

Denn Is
30.06.2014, 12:27
Vielen Dank für deine Hilfe!

Leider macht der uC nach dem Programmieren gar nichts.

Außerdem kommt folgendes Warning:

Warning 1 passing argument 1 of 'checkButtons' from incompatible pointer type [enabled by default] C:\Users\Dennis\Documents\GccApplication2\GccAppli cation2\GccApplication2.c 35 3 GccApplication2
Message 2 expected 'byte *' but argument is of type 'byte **' C:\Users\Dennis\Documents\GccApplication2\GccAppli cation2\GccApplication2.c 25 6 GccApplication2


Kann es sein das ich die Buttons vllt. mit einem Interrupt abfragen muss da das Programm das sonst nicht rechtzeitig merkt? Oder das Programm gerade an einer "falschen" Stelle ist und daher einen Tastendruck nicht mitbekommt?

Sisor
30.06.2014, 15:22
Dann muß wohl die Zeile:
byte checkButtons(byte* button, byte* codes[], byte buttons[]);
in:
byte checkButtons(byte*, byte**, byte*);
geändert werden.

Wsk8
01.07.2014, 09:09
Nein, die Funktion würde schon passen. Das Problem ist der Aufruf


byte* btn;
byte code_nr = checkButtons(&btn, codes, buttons);
btn ist bereits ein Pointer und kann ohne & übergeben werden. Hier wird ein Pointer auf einen Pointer übergeben!

mfg

Denn Is
01.07.2014, 10:20
Dann muß wohl die Zeile:
byte checkButtons(byte* button, byte* codes[], byte buttons[]);
in:
byte checkButtons(byte*, byte**, byte*);
geändert werden.

Da bleiben beide Warnings identisch zu vorher.


Wsk8

Nein, die Funktion würde schon passen. Das Problem ist der Aufruf
Code:

byte* btn;
byte code_nr = checkButtons(&btn, codes, buttons);

btn ist bereits ein Pointer und kann ohne & übergeben werden. Hier wird ein Pointer auf einen Pointer übergeben!

mfg



Wenn ich das "&" entferne kommt ein neues Warning:


Warning 1 'btn' is used uninitialized in this function [-Wuninitialized] C:\Users\Dennis\Documents\GccApplication2\GccAppli cation2\GccApplication2.c 35 8 GccApplication2

Wsk8
01.07.2014, 10:41
Junge, Junge, ...
Lern doch bitte erstmal überhaupt programmieren, bevor du dich an Sachen wie µC wagst, sonst wird das nie was.
Ein einfacheres Warning als das gibts in C vermutlich nicht. Man muss es eh nur auf Deutsch übersetzen und dann hat man schon die Lösung.

Dieses Forum dient als Anlaufstelle für Probleme. Aber das Problem, dass man nicht programmieren kann, wird hier keiner außer du selbst lösen können!

mfg

Denn Is
01.07.2014, 10:58
Junge, Junge, ...
Lern doch bitte erstmal überhaupt programmieren, bevor du dich an Sachen wie µC wagst, sonst wird das nie was.
Ein einfacheres Warning als das gibts in C vermutlich nicht. Man muss es eh nur auf Deutsch übersetzen und dann hat man schon die Lösung.

Dieses Forum dient als Anlaufstelle für Probleme. Aber das Problem, dass man nicht programmieren kann, wird hier keiner außer du selbst lösen können!

mfg

Dieser freundliche Umgangston hier wieder...

Tut mir echt Leid das ich noch kein "Programmier-Profi" bin wie hier andere vielleicht. Ich habe auch eine Seite zuvor geschrieben das ich dieses Programm mit meinen Kenntnissen noch nicht verstehe!

Da mir hier dennoch von einem sehr freundlichen Mitglied Lösungsvorschläge und Programme geschrieben werden wird es mir doch hoffentlich erlaubt sein diesem Mitglied oder anderen zu "zeigen" was mein Compiler ausspuckt.

Das Warning auf deutsch übersetzten kann ich wohl aber danke für den Tipp. Dennoch weiß ich nun mal nicht wie die Variable in diesem Fall initialisiert werden muss. Zumal das Programm auf dem Testboard halt auch noch nicht funktioniert.

Tut mir leid das ich noch in den "Anfängen" von C stecke und mit Pointern und sowas noch nicht perfekt umgehen kann....

Grüße
Dennis

Wsk8
01.07.2014, 11:11
Ich will hier sicher keinen Beleidigen, aber was denkst du warum hier so gut wie niemand schreibt?? Weil eben keiner Lust hat, jeden Anfänger immer wieder aufs neue die Basics von C zu sagen wo sich überall im Internet finden. Es gibt so viiiiieeele Tutorials wo einem alles erklärt wird und im Zweifelsfall hat bisher Google immer noch geholfen.

C auf µC ist halt nun mal etwas schwerer als auf dem PC, vor allem weil oft die Möglichkeit zum debuggen fehlt. In vielen Programmiersprachen sind Pointer nicht mal vorhanden, da man sie als zu gefährlich ansieht und das sind sie auch! Am PC stürzt halt mal ein Programm ab, auf einem µC stürzt der ganze µC ab und macht gar nichts.

Bevor man auf einem µc mit C arbeiten kann, muss man zuerst die Basics von C verstehen und dazu gehören unter anderem Compilermeldungen, Pointer, Variablen, Funktionen etc....

Bevor du ein Rennfahrer werden kannst, musst du auch erst einmal lernen wie man überhaupt Auto fährt!

Und solange du das nicht verinnerlicht hast, kann ich nur viel Spaß beim scheitern wünschen und früher oder später wirst du dadurch die Lust an der Materie verlieren.

mfg

Sisor
01.07.2014, 11:21
Nein, die Funktion würde schon passen. Das Problem ist der Aufruf


byte* btn;
byte code_nr = checkButtons(&btn, codes, buttons);
btn ist bereits ein Pointer und kann ohne & übergeben werden. Hier wird ein Pointer auf einen Pointer übergeben!

mfg

Klar, es muss stehen (ohne Stern):
byte btn;

Die Adresse von btn soll der Funktion übergeben werden, damit die Nummer der gedrückten Taste zusätzlich zur Codenummer zurückgegeben werden kann.