Forum: Mikrocontroller und Digitale Elektronik Wie am besten meine Taster Verriegeln ?


von Michael H. (h_m)


Lesenswert?

Guten Tag,

ich möchte mit jedem Taster einen Kanal Einschalten, wenn der jeweilige 
Kanal gewählt wird soll der zuletzt gewählte Kanal ausgeschaltet werden, 
das heisst es darf kein anderer eingeschaltet werden, wie kann ich hier 
am besten vorgehen um die fünf Taster gegenseitig zu verriegeln ??


vielleicht kann mir bitte jemand weiterhelfen ??


1
/*
2
 * Tasterverriegelung.c
3
 *
4
 * Created: 07.10.2018 12:01:59
5
 * Author : USER
6
 */ 
7
# define F_CPU 8000000
8
#include <avr/io.h>
9
#include <util/delay.h>
10
11
#define Taster1_Down !(PINB&(1<<PB6))
12
#define Taster2_Down !(PINB&(1<<PB7))
13
#define Taster3_Down !(PIND&(1<<PD5))
14
#define Taster4_Down !(PIND&(1<<PD6))
15
#define Taster5_Down !(PIND&(1<<PD7))
16
17
int Flag1 = 0;
18
int Flag2 = 0;
19
int Flag3 = 0;
20
int Flag4 = 0;
21
int Flag5 = 0;
22
23
#define Kanal1_HIGH   PORTC |= (1<<PC0)
24
#define Kanal2_HIGH   PORTC |= (1<<PC1)
25
#define Kanal3_HIGH   PORTC |= (1<<PC2)
26
#define Kanal4_HIGH   PORTC |= (1<<PC3)
27
#define Kanal5_HIGH   PORTC |= (1<<PC5)
28
29
#define Kanal1_LOW    PORTC &= ~(1<<PC0)
30
#define Kanal2_LOW    PORTC &= ~(1<<PC1)
31
#define Kanal3_LOW    PORTC &= ~(1<<PC2)
32
#define Kanal4_LOW    PORTC &= ~(1<<PC3)
33
#define Kanal5_LOW    PORTC &= ~(1<<PC5)
34
35
36
37
38
int main(void)
39
{    
40
  // EINGÄNGE Setzen
41
  DDRB = (1<<PB7)|(1<<PB6);
42
  DDRD = (1<<PD5)|(1<<PD6)|(1<<PD7);
43
  // Pullup
44
  PORTB = (1<<PB7)|(1<<PB6);
45
  PORTD = (1<<PD5)|(1<<PD6)|(1<<PD7);
46
  
47
    
48
    while (1) 
49
    {
50
    }
51
}

von npn (Gast)


Lesenswert?

Michael H. schrieb:
> um die fünf Taster gegenseitig zu verriegeln ??

indem du nur definiert 1 Bit in PORTC setzt...

Umständlicher kann man es machen, wenn man beim Setzen eines Bits 
gezielt die anderen Bits rücksetzt.

von H.Joachim S. (crazyhorse)


Lesenswert?

Erstmal ist es natürlich ganz einfache: wird eine Taste erkannt wird das 
entsprechende Bitmuster auf den Port geschrieben, was nur eine 1 hat.

Interessanter werden dann die Randbedingen. Was passiert wenn mehrere 
Tasten "gleichzeitig" gedrückt werden? Gar nichts? Die zuerst gedrückte 
gewinnt? oder die zuletzt losgelassene? Schöner ist es, wenn direkt beim 
Drücken was passiert und nicht erst beim loslassen. Also muss in der 
Zeit, in der eine Taste noch gedrückt ist, die weitere 
Abfrage/Auswertung unterbleiben. Neu geht erst wieder, wenn alle 
losgelassen wurden.

von Michael H. (h_m)


Lesenswert?

npn schrieb:
> Michael H. schrieb:
>> um die fünf Taster gegenseitig zu verriegeln ??
>
> indem du nur definiert 1 Bit in PORTC setzt...

das ist das, was ich ausprobieren möchte, nur kann ich mir gerade 
überhaupt nicht vorstellen wie das aussehen soll, kann mir  bitte hier 
jemand einen Ansatz zeigen

von Karl M. (Gast)


Lesenswert?

Hallo,

Wichtiger ist noch, dass man alle Taster sauber abfragt (entprellt) und 
auch die Ereignisse, Taster wurde gedrückt oder losgelassen, reagieren 
kann.

Es fehlt also noch eine Timer basierenede Tasterentprellung.

Dann würde ich ein Ausgang-Bit-Variable <bit_output> definieren, die die 
realen Ausgangszustände abbildet.
Dann kann man doch einfach die neue gedrückte Taste in der zugehörigen 
Bitposition der Variable <bit_output> setzen und der Ausgabefunktion 
übergeben.
Diese setzt oder löscht dann anhand einer "0" oder "1" an einer 
Bitposition das zugeordnete Bit am Ausgang.

von Michael H. (h_m)


Lesenswert?

Karl M. schrieb:
> Hallo,
>
> Wichtiger ist noch, dass man alle Taster sauber abfragt (entprellt) und
> auch die Ereignisse, Taster wurde gedrückt oder losgelassen, reagieren
> kann.
>
> Es fehlt also noch eine Timer basierenede Tasterentprellung.

also die Entprellung soll anders stattfinden und zwar indem ich einen 
invertierenden Schmitttriger zwischen Taster und I/O schalte.

Dann würde ich ein Ausgang-Bit-Variable <bit_output> definieren, die die
realen Ausgangszustände abbildet.
Dann kann man doch einfach die neue gedrückte Taste in der zugehörigen
Bitposition der Variable <bit_output> setzen und der Ausgabefunktion
übergeben.
Diese setzt oder löscht dann anhand einer "0" oder "1" an einer
Bitposition das zugeordnete Bit am Ausgang.

das kapier ich irgendwie nicht, gibt es da irgendwo ein Beispiel oder 
ähnliches wo ich mir das mal abschauen kann ?

von Karl M. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe die Aufgabenstellung mal in LunaAVR herunter programmiert, 
vielleicht findest Du Anregungen.

Die Syntax zu Verstehen, sollte nicht so schwer sein.

Bitte beachte die Modularisierung der verschiedenen Abschnitte des 
Programms.

https://avr.myluna.de/doku.php?id=de:download

Version Main Release 2018 R2

von georg (Gast)


Lesenswert?

Michael H. schrieb:
> das heisst es darf kein anderer eingeschaltet werden

Dann ist es auch überflüssig, 5 x int für die Taster zu speichern, es 
reicht einer, der die Nummer des Tasters enthält, das macht den Zustand 
von vornherein eindeutig. Ein Tastendruck setzt den Zustand auf die 
zugehörige Nummer, und es wird das zur Nummer gehörende Bitmuster 
ausgegeben. Oder ist das zu kompliziert?

Georg

von Cprog (Gast)


Lesenswert?

Lieber Michael H.,

zeig doch mal was Du bisher programmiert hast.

von wendelsberg (Gast)


Lesenswert?

Karl M. schrieb:
> Es fehlt also noch eine Timer basierenede Tasterentprellung.

Die Entprellung in diesem Spezialfall hier entbehrlich, weil es nur 
darum geht, zu erkennen, dass ein Taster min. 1x gedrueckt wurde. Ob das 
1x oder 100x erkannt wird, aendert nichts.

wendelsberg

von MaWin (Gast)


Lesenswert?

Karl M. schrieb:
> Wichtiger ist noch, dass man alle Taster sauber abfragt (entprellt)

Spielt bei dieser Anwendung keine Rolle.

Das Problem hier ist die Aufgabenstellung. Die entspricht nämlich NICHT 
einem Tastenaggregat.

Michael H. schrieb:
> ich möchte mit jedem Taster einen Kanal Einschalten, wenn der jeweilige
> Kanal gewählt wird soll der zuletzt gewählte Kanal ausgeschaltet werden,
> das heisst es darf kein anderer eingeschaltet werden

sondern einem dead lock, bricked: Wenn EIN Mal ein Kanal durch 
Tastendruck gewählt wurde (wer zuerst kommt mahlt zuerst) kannn NIE MEHR 
ein anderer gewählt werden, denn die sind ja nun verriegelt und kann 
nicht mehr eingeschaltet werden.

Da er aber von "der zuletzt gewählte ausgeschaltet" redet, meint er wohl 
nicht, was er hier als Blödsinn hingeschrieben hat. Er soll sich erst 
mal lklar werden, welche Logik er wirklich will, dann kann man die auch 
implementieren. Denn Unlogik macht ein Prozessor nicht mit.

Eventuell sind die anderen Kanäle nur so lange verriegelt, bis der 
zuerst gedrückte Taster wieder lisgelassen wird. Wenn dann aber mehrere 
andere Taster immer noch gedrückt gehalten wurden, wäre die Frage, 
welchen man seinen Ausgang einschalten lässt. Oder erst denjenigen, den 
man erneut niederdrückt. Viele Interpretationsmöglichkeiten der 
halbgaren Aufgabe.

von Stefan F. (Gast)


Lesenswert?

Michael H. schrieb:
>> indem du nur definiert 1 Bit in PORTC setzt...
> das ist das, was ich ausprobieren möchte, nur kann ich mir gerade
> überhaupt nicht vorstellen wie das aussehen soll, kann mir  bitte hier
> jemand einen Ansatz zeigen

Gerne
1
#define Kanal1 (1<<PC0)
2
#define Kanal2 (1<<PC1)
3
#define Kanal3 (1<<PC2)
4
#define Kanal4 (1<<PC3)
5
#define Kanal5 (1<<PC5)
6
#define AlleKanaele  (Kanal1+Kanal2+Kanal3+Kanal4+Kanal5)
7
8
PORTC = (PORTC & ~AlleKanaele) | Kanal1;

(PORTC & ~AlleKanaele) setzt alle Kanäle auf Low und lässt die übrigen 
Bits unverändert.

| Kanal1 setzt den gewünschten Kanal auf High.

Beides zusammen löscht also alle Kanäle und setzt den einen gewünschten 
Kanal. Dieser Lösungsansatz setzt voraus, dass alle Kanäle im selben 
Port sind.

von Einer K. (Gast)


Lesenswert?

wendelsberg schrieb:
> Die Entprellung in diesem Spezialfall hier entbehrlich, weil es nur
> darum geht, zu erkennen, dass ein Taster min. 1x gedrueckt wurde. Ob das
> 1x oder 100x erkannt wird, aendert nichts.


Wie auch immer...

Ich kann dir ein Arduino Beispiel liefern, wie sowas aussehen könnte.
Habe ich aus einem anderen Projekt raus geschnitten, und so eben auf 
dein Problem angepasst.

Die betreffenden Pins/Ports sind anders konfiguriert, um es testen zu 
können.
Da ist also Anpassungsarbeit nötig.
Findet sich aber alles schön übersichtlich in einem Array.

Leider kann ich gerade kein C testen, darum C++ Code.
Allerdings ist der Code sehr C artig.
Sollte also umformbar sein.

Für C müssten die Daten Typen und die Schleifen umgebaut werden.
1
//# define F_CPU 8000000
2
//#include <avr/io.h>
3
//#include <util/delay.h>
4
5
6
7
using Register = volatile byte *;
8
9
struct Port
10
{
11
  Register ddr;
12
  Register pin;
13
  Register port;
14
  byte    maske; 
15
};
16
17
struct TasterDingen
18
{
19
  Port taster;
20
  Port out;
21
};
22
23
using TasterArrayType = TasterDingen[5];
24
25
TasterArrayType td {
26
                       {{&DDRB,&PINB,&PORTB,(1<<PB0)},{&DDRC,&PINC,&PORTC,(1<<PC0)}},
27
                       {{&DDRB,&PINB,&PORTB,(1<<PB1)},{&DDRC,&PINC,&PORTC,(1<<PC1)}},
28
                       {{&DDRB,&PINB,&PORTB,(1<<PB2)},{&DDRC,&PINC,&PORTC,(1<<PC2)}},
29
                       {{&DDRB,&PINB,&PORTB,(1<<PB3)},{&DDRC,&PINC,&PORTC,(1<<PC3)}},
30
                       {{&DDRB,&PINB,&PORTB,(1<<PB4)},{&DDRC,&PINC,&PORTC,(1<<PC4)}},
31
                     };
32
33
34
35
void alleAus(TasterArrayType &td)
36
{
37
  for(TasterDingen &t:td) *(t.out.port) &= ~t.out.maske;
38
}
39
40
int scan(TasterArrayType &td) // liefert den index einer gedrueckten Taste
41
{
42
  int i = 0;
43
  for(TasterDingen &t:td)
44
  {
45
    if(!(*(t.taster.pin) & t.taster.maske)) return i; 
46
    i++; 
47
  }
48
  return -1; // kein taster gedrueckt
49
}
50
51
52
int main(void)
53
{   
54
  for(TasterDingen &t:td) 
55
  {
56
    // Inputs vorbereiten
57
    *(t.taster.ddr)  |= t.taster.maske;
58
    *(t.taster.port) |= t.taster.maske;
59
60
    // Outputs vorbereiten
61
    *(t.out.ddr) |= ~t.out.maske;
62
  }
63
64
  int last = -1; // -1 ist kein taster gedrueckt
65
    
66
  while(1) 
67
  {
68
    int s = scan(td);
69
    if((s >= 0) && (s != last))
70
    {
71
     last = s;
72
     alleAus(td);
73
     *(td[s].out.port) |= td[s].out.maske; // den einen Ausgang ein
74
    }
75
  }
76
}

von machet (Gast)


Lesenswert?

Er dat mal meschanisch...

von Peter D. (peda)


Lesenswert?

wendelsberg schrieb:
> Die Entprellung in diesem Spezialfall hier entbehrlich

Jain.
Eine Entprellung schützt auch gegen "zufälliges" Umschalten durch 
Störimpulse. Tasten werden erst dann als gedrückt gemeldet, wenn der 
Pegel einige ms stabil anliegt.
Die Verriegelung macht man am einfachsten mit je einem Encoder/Decoder.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Michael H. schrieb:
> while (1)
>     {
>     }

Ja, da mußt Du was reinschreiben:
1
  while (1) {
2
    decode(encode());
3
  }

Entprellen fehlt noch in meinem Beispiel.

von Rainer V. (a_zip)


Lesenswert?

Michael H. schrieb:
> ich möchte mit jedem Taster einen Kanal Einschalten, wenn der jeweilige
> Kanal gewählt wird soll der zuletzt gewählte Kanal ausgeschaltet werden,
> das heisst es darf kein anderer eingeschaltet werden, wie kann ich hier
> am besten vorgehen um die fünf Taster gegenseitig zu verriegeln ??

Hallo, ich kann zwar kein "C" oder so was...aber ich denke, wenn dein 
Programm mit Initialisieren fertig ist, dann ist jeder Kanal inaktiv und 
du wartest auf eine Eingabe. Das erste Eingabe-Low, das du pollst, setzt 
den Eingang und setzt alle anderen zurück. Wenn nun jemand schlau 
"Klavier spielt", dann gewinnt immer Einer...und alle anderen sind raus. 
Wie du nun die zeitlichen Zuordnungen zwischen den Signalen legst, ist 
allein dein Gustus. Viel kann man da nicht falsch machen! Es sei denn du 
hast Menschen, die Eingaben im Bereich des Prozessortakts tätigen 
können.
Gruß Rainer

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.