Forum: Mikrocontroller und Digitale Elektronik AVR Ausgänge mit "Dauerfeuer" belegen


von Lokus P. (derschatten)


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

von Karl H. (kbuchegg)


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.

von Lokus P. (derschatten)


Lesenswert?

Timer Interrupt ist eine gute Idee.

Diese Tabelle um eine Variable erweitern oder wie meinst du das genau?
Die Frage ist nur wie filtere ich diesen einen PIN heraus?

von Lokus P. (derschatten)


Lesenswert?

In meinem Programm verwende ich bereits einen zeitgeber der mit 10ms 
taktet. Den ich für die Tastenabfrage nutze (Kurz/lang gedrückt)

kann ich da einen zweiten parallel laufen lassen?

von Stefan (Gast)


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.

von Karl H. (kbuchegg)


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)

von Lokus P. (derschatten)


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]

von Karl H. (kbuchegg)


Lesenswert?

OUT_PORT = Summe & repeatMask;                  // Definierte 
Konfiguration mit Dauerfeuer an Ausgang PortC.0 ausgeben

Lies endlich den verdammten Beitrag über "Bitmanipulation"

von Lokus P. (derschatten)


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?

von Lokus P. (derschatten)


Lesenswert?

Wohl zu schnell geqntwortet? :)

Das war nicht geraten.

Da steht doch:

PORTB  = PORTB | variable; // lange Schreibweise

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

von Karl H. (kbuchegg)


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.

von Lokus P. (derschatten)


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

von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:

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

Nö.

> Das ist alles so verwirrend. Pffff....

Das ist nur deswegen verwirrend, weil dir massiv die Grundlagen fehlen.

Aber Hinweis:
Niemand sagt, dass du nur 1 binäre Operation anwenden darfst.

von Lokus P. (derschatten)


Lesenswert?

Karl heinz Buchegger schrieb:
> Niemand sagt, dass du nur 1 binäre Operation anwenden darfst.

Das muß ich ja vorraussetzen, da ich nur auf PortC.0 das Dauerfeuer 
möchte.

von Lokus P. (derschatten)


Lesenswert?

Mit dem IF funktioniert das sowieso nicht, da ja der Port auch im 
ruhezustand des Tasters permanent getoggelt wird.

Wie mach ich das?

von Lokus P. (derschatten)


Lesenswert?

Sonst jemand noch einen Tip für mich?

Die Aufgabestellung ist nur bei gedrückten Tasten und einer gesetzten 
Variable den Ausgang PortC.0 zu toggeln.

von gast0815 (Gast)


Lesenswert?

Lass es doch einfach Karl Heinz. Zuerst entwerfen wir ihm hier seine 
Schaltung und jetzt sollen wir auch noch die Software machen.
Er soll doch zuerst mal etwas Grundlagenforschung betreiben und dann 
etwas sein Hirn anstrengen.

von Claudio H. (bastelfinger)


Lesenswert?

Hast du schonmal daran gedacht, das Dauerfeuer über einen NE555 zu 
lösen? Einfach einen Umschalter zwischen Protpin und NE555 einbauen, und 
dann noch ein Poti zum Einstellen der Dauerfeuerfrequenz. Ist halt die 
Frage, ob du das mit Hardware oder mit Software lösen willst...

von Lokus P. (derschatten)


Lesenswert?

Ja, mit dem NE555 hatte ich das ganze zuerst schon aufgebaut.
Das funktioniert auch problemlos.

Allerdings möchte ich das ganze Regelbar machen. Dafür könnte man 
natürlich auch ein Poti einsetzen.
Ist aber nicht die feine Lösung. Außerdem ist der AVR ja schon da, warum 
also nicht gleich dafür nützen?

von Lokus P. (derschatten)


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.

von Volker S. (volkerschulz)


Lesenswert?

Mit einer PWM koennte man bestimmt auch prima dauerfeuern... Spaetestens 
im KHz-Bereich haben die Gegner keine Chance mehr! ;)

Achso, den PWM-Ausgang dann natuerlich noch mit Pin C0 OR-verknuepfen.

Volker

von Lokus P. (derschatten)


Lesenswert?

Mein AVR ist leider voll belegt. Da ist kein einziger Pin mehr frei.

von Volker S. (volkerschulz)


Lesenswert?

Manfred W. schrieb:
> Mein AVR ist leider voll belegt. Da ist kein einziger Pin mehr frei.

Dann tauschst Du halt C0 mit was immer am PWM-Output so anliegt.

Volker

von Lokus P. (derschatten)


Lesenswert?

Das problem wäre damit sicher nicht gelöst. Da ich das Programm genauso 
verändern müßte. Auch die vorhandene Tabelle. Die schickt ja weiterhin 
ein HI auf meinen Ausgang.

von Volker S. (volkerschulz)


Lesenswert?

Sobald die PWM aktiv ist, werden Outputs an dem Port ignoriert... Aber 
das Grundproblem scheint mir in der Tat woanders zu liegen... ;)

Volker

von Lokus P. (derschatten)


Lesenswert?

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.

von Volker S. (volkerschulz)


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

von Lokus P. (derschatten)


Lesenswert?

Erklär mir bitte wie man PWM "aktiviert"

von Volker S. (volkerschulz)


Lesenswert?

Manfred W. schrieb:
> Erklär mir bitte wie man PWM "aktiviert"

Auch das steht im Tutorial. Bevor ich jetzt alles zitiere, hier ist der 
Link:

http://www.mikrocontroller.net/articles/AVR-Tutorial:_PWM

Abschnitt "PWM und der Timer"

Wenn Du keinen Mega8 verwendest, muss natuerlich das ein oder andere 
Register angeglichen werden.

Volker

von Lokus P. (derschatten)


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 :)

von Volker S. (volkerschulz)


Lesenswert?

Manfred W. schrieb:
> Ich glaub ich habs jetzt gelöst:
> [...]
> Ihr dürft mich Gott nennen :)

Wieviel Hilfe-Beitraege im Forum hat Gott denn so gebraucht, bis alles 
stand? Der hatte uebrigens vermutlich auch kein Tutorial... ;)

Volker

von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:

> Ihr dürft mich Gott nennen :)

Scheusliche Lösung

von Lokus P. (derschatten)


Lesenswert?

Karl heinz Buchegger schrieb:
> Scheusliche Lösung

Ich hab nur deinen Rat befolgt :)

Was ist daran scheuslich?

von Karl H. (kbuchegg)


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.

von Lokus P. (derschatten)


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

von Karl H. (kbuchegg)


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?

von Karl H. (kbuchegg)


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?

von Lokus P. (derschatten)


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

von Karl H. (kbuchegg)


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.

von Lokus P. (derschatten)


Lesenswert?

wie müssen repeatPin und repeatOutputMask deklariert werden?

von Lokus P. (derschatten)


Lesenswert?

Hab gestern bei meiner Variante nur eine kleine unschönheit entdeckt.

Sollte es nämlich vorkommen das vor dem abschalten des Toggeln der 
Portausgang zuvor auf LOW gestanden haben. Funktioniert die Ausgabe auf 
diesem Port nicht mehr. Da dieser ja dann ständig mit LOW aktiviert 
wird.

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.