AVR Ausgänge mit "Dauerfeuer" belegen

#1568988
Lesenswert?

Ich bräuchte wieder einen Tip:

ich nutze meinen AVR als Steuerung eines Joypads (Wii, PC, ...)
Der Sinn dahinter ist es 6 Eingänge je nach Konfiguration auf 6 gewählte 
Ausgänge zu schalten. Also einfach durchzuschleifen.

Die Hardware und die Software steht soweit und funktioniert auch 
perfekt.
Jetzt möchte ich mein Programm gerne um eine "Dauerfeuer-Funktion" 
erweitern. D.h. Bei gedrückthalten einer Taste soll der entsprechende 
Ausgang mit einer bestimmten Zeitschleife einen Impuls wiederholen.

Alles soweit eigentlich klar. Konnte ich mit einer IF-Anweisung lösen.

Das Problem jetzt allerdings dabei ist das ich meine Portzuweisungen aus 
einer Tabelle beziehe und diese beim Drücken einer der 6 Tasten 
durchschalte.

Das sieht so aus:
1
.......
2

3
// Tasteneingänge definieren
4
// =========================
5
#define KEY_DDR         DDRB
6
#define KEY_PORT        PORTB
7
#define KEY_PIN         PINB
8
#define KEY0            7
9
#define KEY1            6
10
#define KEY2            0
11
#define KEY3            1
12
#define KEY4            2
13
#define KEY5            3
14
#define KEY6            4
15
#define KEY7            5
16
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2 | 1<<KEY3 | 1<<KEY4 | 1<<KEY5 | 1<<KEY6 | 1<<KEY7)
17

18
// Segment und Tasten-Ausgänge definieren
19
// ======================================
20
#define SEGMENT_DDR    DDRD
21
#define SEGMENT_PORT  PORTD
22
#define OUT_DDR         DDRC
23
#define OUT_PORT        PORTC
24
#define OUT1            0
25
#define OUT2            1
26
#define OUT3            2
27
#define OUT4            3
28
#define OUT5            4
29
#define OUT6            5
30
#define ALL_OUT        (1<<OUT1 | 1<<OUT2 | 1<<OUT3 | 1<<OUT4 | 1<<OUT5 | 1<<OUT6)
31

32
#define LED0      (1<<PC0)
33
#define LED1      (1<<PC1)
34
#define LED2      (1<<PC2)
35
#define LED3      (1<<PC3)
36
#define LED4      (1<<PC4)
37
#define LED5      (1<<PC5)
38
#define NR_KONFIGS    9
39
#define NR_KEYS      6
40

41
uint8_t Pattern[NR_KONFIGS][NR_KEYS] PROGMEM =
42
  {
43
    {LED0,LED1,LED2,LED3,LED4,LED5},          // Konfiguration 0
44
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 1
45
    {LED2,LED0,LED4,LED1,LED3,LED5},          // Konfiguration 2
46
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 3
47
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 4
48
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 5
49
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 6
50
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 7
51
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 8
52
   };
53

54
  while(1)
55
  {
56
    Summe = 0;
57

58
    if(!(KEY_PIN & 0x01))                // Wenn Taste PortB.0 auf HIGH
59
      Summe |= pgm_read_byte(&Pattern[nKeyPress][0]);
60
    if(!(KEY_PIN & 0x02))                // Wenn Taste PortB.1 auf HIGH
61
      Summe |= pgm_read_byte(&Pattern[nKeyPress][1]);
62
    if(!(KEY_PIN & 0x04))                // Wenn Taste PortB.2 auf HIGH
63
      Summe |= pgm_read_byte(&Pattern[nKeyPress][2]);
64
    if(!(KEY_PIN & 0x08))                // Wenn Taste PortB.3 auf HIGH
65
      Summe |= pgm_read_byte(&Pattern[nKeyPress][3]);
66
    if(!(KEY_PIN & 0x10))                // Wenn Taste PortB.4 auf HIGH
67
      Summe |= pgm_read_byte(&Pattern[nKeyPress][4]);
68
    if(!(KEY_PIN & 0x20))                // Wenn Taste PortB.5 auf HIGH
69
      Summe |= pgm_read_byte(&Pattern[nKeyPress][5]);
70

71
    OUT_PORT = Summe;                  // Definierte Konfiguration ausgeben
72

73
........

Jetzt möchte ich gerne wenn eine bestimmte Variable zb. 0 ist der 
Ausgang PortC.0 mit der Dauerfeuerfunktion belegt ist.

zb:
1
if(!(KEY_PIN & 0x01))                // Wenn Taste PortB.0 auf HIGH
2
      {
3
        PORTC |= (1 << PC0);        // LED an PC0 umschalten
4
        _delay_ms (30);
5
        PORTC &= ~(1 << PC0);        // LED an PC0 umschalten
6
        _delay_ms (30);
7
      }

Wie würdet ihr das lösen?
Soll ich die IF-Abfrage einfach drunter am Code anhängen und parallel zu 
der Tastenzuordnung laufen lassen oder die Tastenzuweisung umstricken?
Also der Ausgang ist immer fix
#1568993
Lesenswert?

Manfred W. schrieb:

> Jetzt möchte ich gerne wenn eine bestimmte Variable zb. 0 ist der
> Ausgang PortC.0 mit der Dauerfeuerfunktion belegt ist.
>
> zb:
>
>
1
> if(!(KEY_PIN & 0x01))                // Wenn Taste PortB.0 auf HIGH
2
>       {
3
>         PORTC |= (1 << PC0);        // LED an PC0 umschalten
4
>         _delay_ms (30);
5
>         PORTC &= ~(1 << PC0);        // LED an PC0 umschalten
6
>         _delay_ms (30);
7
>       }
8
>
>
> Wie würdet ihr das lösen?

Auf jeden Fall ohne _delay_ms
Das verzögert dir sonst alle anderen Tasten sobald sich Dauerfeuer 
aktiviert.
Timer als Zeitgeber benutzen. In der ISR eine Variable von 0 auf 0xFF 
(und umgekehrt) toggeln. Zur normalen Ummaptabelle gibt es eine 
Erweiterung, die mir sagt, ob auf diesem Pin Dauerfeuer liegen soll oder 
nicht und wenn ja, wird die Ausgabe an diesem Pin in der Schleife 
zusätzlich noch mit besagter Togglevariable verundet.
Gast #1569279
Lesenswert?

Hallo,

ich bin selbst Neuling. Aber ich würde sagen, du kannst dem Timer ja 
mehrere Aufgaben zukommen lassen.
Zähle doch im TimerOVF Interrupt einfach eine Variable hoch z.B. zeit++
Zeit wird also jede 10ms erhöht, hat Zeit den Wert 2, so sind 20ms 
vergangen, hat Zeit den Wert 100, so ist eine Sekunde vergangen.
Sobald deine Taste dann gedrückt wird, setzt du Zeit auf den Wert "0" 
und führst eine Aktion aus.
Ab dann kannst du nun mit der Abfrage der Variable Zeit dein 
"Dauerfeuer" einstellen.
Wenn die Variable Zeit einen Wert überschreitet, setzt du dein 
Dauerfeuer zurück.
Gefährlich wird es wohl nur, wenn die Variable Zeit zu groß wird, weil 
kein Dauerfeuer angewendet wird und sie somit nicht auf 0 gesetzt wird.
Vielleicht sollte man daher in die ISR noch einbauen wenn zeit>max_wert 
zeit=0;
Wie gesagt, ich bin selbst neu auf dem Gebiet, es gibt ganz sicher eine 
deutlich elegantere Lösung.
#1569294
Lesenswert?

Stefan schrieb:
> Hallo,
>
> ich bin selbst Neuling. Aber ich würde sagen, du kannst dem Timer ja
> mehrere Aufgaben zukommen lassen.
> Zähle doch im TimerOVF Interrupt einfach eine Variable hoch z.B. zeit++
> Zeit wird also jede 10ms erhöht, hat Zeit den Wert 2, so sind 20ms
> vergangen, hat Zeit den Wert 100, so ist eine Sekunde vergangen.
> Sobald deine Taste dann gedrückt wird, setzt du Zeit auf den Wert "0"
> und führst eine Aktion aus.

Bis hier her war das ok.
Das mit der 'Aktion ausführen' machst du aber nicht in der ISR

> Gefährlich wird es wohl nur, wenn die Variable Zeit zu groß wird, weil
> kein Dauerfeuer angewendet wird und sie somit nicht auf 0 gesetzt wird.
> Vielleicht sollte man daher in die ISR noch einbauen wenn zeit>max_wert
> zeit=0;

Wenn du das richtig machst, brauchst du dir auch um diesen Fall keine 
Gedanken zu machen. Der Schlüssel liegt in der Trennung von "Generierung 
eines periodischen Signals" und dessen "Verwendung"

> Wie gesagt, ich bin selbst neu auf dem Gebiet, es gibt ganz sicher eine
> deutlich elegantere Lösung.

Du bist schon auf einem sehr guten Weg.
1
...
2
uint8_t cntTicks;
3
volatile uint8_t repeatMask;
4

5
ISR( .... )   //periodischer Interrupt
6
{
7
  cntTicks++;
8
  if( cntTicks == 50 ) {  // zb nach 50 mal 10ms
9
    repeatMask ^= 0xFF;   // von 0x00 nach 0xFF
10
                          // und umgekehrt: von 0xFF nach 0x00
11
    cntTicks = 0;
12
  }
13
  ...
14
}
15

16
...
17

18
int main()
19
{
20
  ...
21

22
  while( 1 ) {
23

24
    if( !( PINB & 0x01 ) ) {
25

26
      PORTC = 0x03 & repeatMask;
27
    }
28

29
    ....
30
  }
31
}

Schlüssel zum ganzen ist, dass repeatMask mit der vorgegebenen 
zeitlichen Einstellung in der ISR ständig seinen Wert zwischen 0xFF und 
0x00 ändert. Damit liefert die UND Verknüpfung in der Hauptschleife im 
selben zeitlichen Rhytmus 0x03 (wie beabsichtigt) und 0x00.

Eventuell muss man da noch was drehen, je nachdem was Ruhezustand an den 
Pins ist (0 oder 1)
#1569436
Lesenswert?

Danke!

Hab das mal eingepflanzt:
1
volatile uint8_t key_state;                  // Entprellt und invertierte Tastenstatus:
2
                              // Bit=1 -> Taste wurde gedrückt
3
volatile uint8_t key_press;                  // Tastendruck registriert
4
volatile uint8_t key_rpt;                  // Tastendruckdauer
5
volatile uint8_t nKeyPress;                  // Tastendruckanzahl
6
volatile uint8_t Fire; // Feuergeschwindigkeit
7
uint8_t cntTicks; // Zähler im Bezug zum Timer
8

9
// Timer Interrupt von 10ms definieren
10
// ===================================
11
ISR(TIMER0_OVF_vect)
12
{
13
  static uint8_t ct0, ct1, rpt;
14
  uint8_t i;
15

16
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);
17

18
  i = key_state ^ ~KEY_PIN;                // Taste geändert?
19
  ct0 = ~(ct0 & i);                    // resete oder zähle CT0
20
  ct1 = ct0 ^ (ct1 & i);                  // resete oder zähle CT1
21
  i &= ct0 & ct1;                      // Überlauf gezählt?
22
  key_state ^= i;                      // dann Entprellstatus ändern
23
  key_press |= key_state & i;                // 0->1: Tastendruck erkannt
24

25
  if((key_state & REPEAT_MASK) == 0)            // Überprüfe Tastenwiederholfunktion
26
    rpt = REPEAT_START;                  // Starte Verzögerung
27
  if(--rpt == 0)
28
  {
29
    rpt = REPEAT_NEXT;                  // Wiederhole Verzögerung
30
    key_rpt |= key_state & REPEAT_MASK;
31
  }
32

33
  cntTicks++;
34
  if( cntTicks == Fire )      // zb nach <Fire> mal 10ms
35
  {
36
    repeatMask ^= 0x01;   // von 0x00 nach 0x01
37
                    // und umgekehrt: von 0x01 nach 0x00
38
    cntTicks = 0;
39
  }
40
}

Die Geschwindigkeit selbst wird dann durch die Variabel "Fire" 
definiert.

Jetzt rein von der Überlegung her, könnt ich das nicht gleich so auf 
mein Tabellenergebnis anwenden:
1
if(Dauerfeuer= 1) // Wenn Dauerfeuer aktiv
2
{
3
OUT_PORT = Summe & repeatMask;                  // Definierte Konfiguration mit Dauerfeuer an Ausgang PortC.0 ausgeben
4
}
5
else
6
{
7
OUT_PORT = Summe // sonst nur definierte Konfiguration ausgeben
8
}

[c]
#1569464
Lesenswert?

Karl heinz Buchegger schrieb:
> OUT_PORT = Summe & repeatMask;                  // Definierte
> Konfiguration mit Dauerfeuer an Ausgang PortC.0 ausgeben
>
> Lies endlich den verdammten Beitrag über "Bitmanipulation"

Grr, jaaa :)
So müßte es passen:
1
OUT_PORT = Summe | repeatMask;

Mir gings aber mehr ums Prinzip ob das so funktionieren würde. Ohne das 
ich jetzt viel an meiner Tabelle herumschrauben muß.

Das war es ja was du mit "Erweiterung in der Ummaptabelle" gemeint hast, 
oder?
#1569495
Lesenswert?

Manfred W. schrieb:
> Wohl zu schnell geqntwortet? :)

Ja.
Weil es darauf ankommt, was jetzt eigentlich Grundzustand der Leitung 
ist.

> Ist PORTB vorher z.B. 0b01111010, dann ist der Inhalt nach der Operation
> 0b01111010 or 0b00000101 = 0b01111111, die gewünschten Bits sind somit
> gesetzt!

Es sei denn, dein Mapping hat vorher die betreffenden Bits auf 1 
gesetzt. Dann kannst du odern soviel du willst. Sie werden immer 1 
bleiben.
#1569508
Lesenswert?

Karl heinz Buchegger schrieb:
> Es sei denn, dein Mapping hat vorher die betreffenden Bits auf 1
>
> gesetzt. Dann kannst du odern soviel du willst. Sie werden immer 1
>
> bleiben.

Stimmt, und das geht so auch nicht. Mit oder kann ich ja nur auf 1 
setzen.
Wenn der Timer dann 0x01 hat würde der ja nie 0x00 setzen.

Und noch einen Fehler von mir:
1
    repeatMask ^= 0x01;   // von 0x00 nach 0x01
2
                    // und umgekehrt: von 0x01 nach 0x00

Ich will ja zwischen 0x00 und 0x01 wechseln
In dem Fall würde er ja zwischen 0xFE und 0x01 wechseln.

Das ist alles so verwirrend. Pffff....
#1577751
Lesenswert?

Karl heinz Buchegger schrieb:
> Zur normalen Ummaptabelle gibt es eine
>
> Erweiterung, die mir sagt, ob auf diesem Pin Dauerfeuer liegen soll oder
>
> nicht und wenn ja, wird die Ausgabe an diesem Pin in der Schleife
>
> zusätzlich noch mit besagter Togglevariable verundet.

Trotz der Vermutung hin hier noch weiteren Spot zu erben, wollte ich 
Herrn Karl heinz mal fragen wie das genau gemeint war.
Ich hänge immer noch an dem Problem das ich nicht weiß wie ich meine 
Tabelle so ummoddeln kann das sie nicht immer den definierten Fixwert 
ausgibt.
Denn mit Grundissen scheint es ja hier nicht getan zu sein.
Ich verlange hier kein fertiges Programm, weitere Ansätze wären schon 
hilfreich.
#1578072
Lesenswert?

Manfred W. schrieb:
> Ok, aber nur alleine dadurch das an einem Ausgang ein analoger Wert
> anliegt, bring ich die LED nicht zum blinken.
> Da ist wieder zusätzliche Hardware notwendig und die möcht ich mir
> ersparen.

Eine PWM ist KEIN analoger Wert, sondern genau das, was zum 
Blinkenlassen einer LED benoetigt wird. Ein An-Aus-Signal mit variablem 
Tastverhaeltnis. Vielleicht fehlen doch noch ein paar Grundlagen, die in 
den Tutorials prima erklaert werden?

Volker
#1578211
Lesenswert?

Ich glaub ich habs jetzt gelöst:

Die Tabelle um einen Wert erweitert:
1
uint8_t KonfigPattern[NR_KONFIGS][NR_KEYS] =
2
  {
3
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 1
4
    {LED1,LED0,LED3,LED2,LED5,LED4,1},            // Konfiguration 2
5
    {LED5,LED4,LED3,LED2,LED1,LED0,5},            // Konfiguration 3
6
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 4
7
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 5
8
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 6
9
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 7
10
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 8
11
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 9
12
   };
der sagt welcher Ausgang getoggelt werden soll.

Und dann in der Timerschleife abgefragt:
1
  cntTicks++;
2
  if((cntTicks >= nFireTime) && (nFire != 0))          // Ist Variable <nFireTime> mal 10ms
3
  {
4
    KonfigPattern[nKonfig-1][KonfigPattern[nKonfig-1][6]] ^= 0x01;  // Wechselt PortC.0 nach Zeit von 0 auf 1
5
    cntTicks = 0;
6
  }

Ihr dürft mich Gott nennen :)
#1579017
Lesenswert?

Manfred W. schrieb:
> Karl heinz Buchegger schrieb:
>> Scheusliche Lösung
>
> Ich hab nur deinen Rat befolgt :)

Das glaub ich nicht :-)

> Was ist daran scheuslich?

Man verändert sich mutwillig keine Konfigurationsdaten.

Ausserdem: Was, wenn ich das ganze so konfigurieren will, dass 
Dauerfeuer nicht auf PC0 sondern auf PC5 ausgegeben wird?
1
uint8_t KonfigPattern[NR_KONFIGS][NR_KEYS] =
2
  {
3
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 1
4
    {LED1,LED0,LED3,LED2,LED5,LED4,1},            // Konfiguration 2
5
    {LED5,LED4,LED3,LED2,LED1,LED0,5},            // Konfiguration 3
6
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 4
7
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 5
8
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 6
9
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 7
10
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 8
11
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 9
12
   };

Die letzte Spalte (die mit den Zahlen), sagt im Grunde nur aus, an 
welcher Position in dieser Zeile der Eintrag LED0 steckt. Was wird wohl 
passieren, wenn ich mich vertue und dort eine falsche Angabe mache.

Warum steht da der 6-er direkt im Code?

etc, etc.
#1579028
Lesenswert?

Karl heinz Buchegger schrieb:
> Man verändert sich mutwillig keine Konfigurationsdaten.
>

Ich bin froh das ich es wenigstens so hinbekommen habe.
ich wäre ja für andere lösungen jederzeit offen.

> Ausserdem: Was, wenn ich das ganze so konfigurieren will, dass
>
> Dauerfeuer nicht auf PC0 sondern auf PC5 ausgegeben wird?

Dann ändere ich einfach den letzten Wert in der Tabelle.
Abgesehen davon werden die Ausgäne ja nie verdreht. Nur die Eingänge.

> Warum steht da der 6-er direkt im Code?

Da wird aus der Tabelle die Stelle ausgelesen die getoggelt wird.

> etc, etc.

Sicher kann man das ganze bestimmt professioneller lösen, aber wie 
gesagt. Aller Anfang ist schwer...
#1579042
Lesenswert?

Manfred W. schrieb:

>> Ausserdem: Was, wenn ich das ganze so konfigurieren will, dass
>>
>> Dauerfeuer nicht auf PC0 sondern auf PC5 ausgegeben wird?
>
> Dann ändere ich einfach die Variable in der Tabelle.

Ach ja?
Und wie hängt das dann mit
1
    KonfigPattern[nKonfig-1][KonfigPattern[nKonfig-1][6]] ^= 0x01;  // Wechselt PortC.0 nach Zeit von 0 auf 1
zusammen? Muss da nicht auch zufällig etwas verändert werden?
#1579046
Lesenswert?

Manfred W. schrieb:

> Dann ändere ich einfach den letzten Wert in der Tabelle.
> Abgesehen davon werden die Ausgäne ja nie verdreht. Nur die Eingänge.
>
>> Warum steht da der 6-er direkt im Code?
>
> Da wird aus der Tabelle die Stelle ausgelesen die getoggelt wird.

Darum geht es nicht.
Angenommen du hast nicht 6 Eingänge sondern 8.
Von welcher Stelle in der Tabelle musst du dann lesen und wie hängt das 
alles mit

#define NR_KEYS      7    // du hast das hoffentlich erhöht

zusammen?
#1579054
Lesenswert?

Karl heinz Buchegger schrieb:
> h ja?
>
> Und wie hängt das dann mit
>
>     KonfigPattern[nKonfig-1][KonfigPattern[nKonfig-1][6]] ^= 0x01;  // Wechselt 
PortC.0 nach Zeit von 0 auf 1
>
>
>
>
>
> zusammen? Muss da nicht auch zufällig etwas verändert werden?

Richtig, der entsprechende Port der getoggelt werden soll.
Aber wie gesagt, so Variabel muß das ganze gar nicht sein.

> #define NR_KEYS      7    // du hast das hoffentlich erhöht
Klar, sonst gehts ja nicht

dann kannst du mir ja vielleicht doch noch erklären wie du das mit:

"Zur normalen Ummaptabelle gibt es eine
Erweiterung, die mir sagt, ob auf diesem Pin Dauerfeuer liegen soll oder
nicht und wenn ja, wird die Ausgabe an diesem Pin in der Schleife
zusätzlich noch mit besagter Togglevariable verundet."
#1579139
Lesenswert?

Na zb so
1
// die letzte Spalte gibt jeweils an, welcher Eingang
2
// Dauerfeuer erzeugen soll.
3
// Ist der Eingang auf 0, so wird der zugordnete Ausgang
4
// regelmässig getoggelt
5
//
6
uint8_t KonfigPattern[NR_KONFIGS][NR_KEYS] =
7
  {
8
    {LED0,LED1,LED2,LED3,LED4,LED5, PC2},            // Konfiguration 1
9
    {LED1,LED0,LED3,LED2,LED5,LED4, PC3},            // Konfiguration 2
10
    {LED5,LED4,LED3,LED2,LED1,LED0, PC0},            // Konfiguration 3
11
    {LED0,LED1,LED2,LED3,LED4,LED5, PC1},            // Konfiguration 4
12
    {LED0,LED1,LED2,LED3,LED4,LED5, PC0},            // Konfiguration 5
13
    {LED0,LED1,LED2,LED3,LED4,LED5, PC0},            // Konfiguration 6
14
    {LED0,LED1,LED2,LED3,LED4,LED5, PC0},            // Konfiguration 7
15
    {LED0,LED1,LED2,LED3,LED4,LED5, PC0},            // Konfiguration 8
16
    {LED0,LED1,LED2,LED3,LED4,LED5, PC5},            // Konfiguration 9
17
   };
18

19

20
....
21

22
ISR( .... )   //periodischer Interrupt
23
{
24
  cntTicks++;
25
  if( cntTicks == 50 ) {  // zb nach 50 mal 10ms
26
    repeatMask ^= 0xFF;   // von 0x00 nach 0xFF
27
                          // und umgekehrt: von 0xFF nach 0x00
28
    cntTicks = 0;
29
  }
30
  ...
31
}
32

33
....
34

35
  // bei welchem Eingang soll in dieser Konfiguration
36
  // Dauerfeuer ausgelöst werden. Gleich als Maske zurechtlegen
37
  repeatPin = 1 << Pattern[nKonfig][NR_KEYS-1];
38

39
  // das ist welcher Ausgang? Auch hier: gleich wieder als Maske zurechtlegen
40
  repeatOutputMask = Pattern[nKonfig][ Pattern[nKonfig][NR_KEYS-1] ];
41

42
  while(1)
43
  {
44
    Summe = 0;
45

46
    if(!(KEY_PIN & 0x01))                // Wenn Taste PortB.0 auf HIGH
47
      Summe |= Pattern[nKonfig][0]);
48
    if(!(KEY_PIN & 0x02))                // Wenn Taste PortB.1 auf HIGH
49
      Summe |= Pattern[nKonfig][1]);
50
    if(!(KEY_PIN & 0x04))                // Wenn Taste PortB.2 auf HIGH
51
      Summe |= Pattern[nKonfig][2]);
52
    if(!(KEY_PIN & 0x08))                // Wenn Taste PortB.3 auf HIGH
53
      Summe |= Pattern[nKonfig][3]);
54
    if(!(KEY_PIN & 0x10))                // Wenn Taste PortB.4 auf HIGH
55
      Summe |= Pattern[nKonfig][4]);
56
    if(!(KEY_PIN & 0x20))                // Wenn Taste PortB.5 auf HIGH
57
      Summe |= Pattern[nKonfig][5]);
58

59
    // Dauerfeuer behandeln
60
    if( !(KEY_PIN & repeatPin ) ) {
61
      fire = repeatOutputMask & repeatMask;
62
      Summe &= ~repeatOutputMask;
63
      Summe |=  fire;
64
    }
65

66
    OUT_PORT = Summe;                  // Definierte Konfiguration ausgeben

wird zwischendurch nKonfig verändert, müssen natürlich die beiden Masken 
repeatPin und repeatOutputMask neu bestimmt werden :-)
Aber ansonsten ist das einfach nur eine Anwendung der Bitmanipulationen 
und dazu noch eine Variable die in der ISR laufend von 0x00 auf 0xFF 
umschaltet. Die Bitmanipulationen holen sich daraus das ineterssierende 
Bit für den Output

      fire = repeatOutputMask & repeatMask;

setzen in Summe zunächst für diesen Output die zugehörigen Bits auf 0
      Summe &= ~repeatOutputMask;

und bauen dann, je nach Zustand der OutputMask und der repeatMask wieder 
die richtigen 1 Bits ein.

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