mikrocontroller.net

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


Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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:
.......

// Tasteneingänge definieren
// =========================
#define KEY_DDR         DDRB
#define KEY_PORT        PORTB
#define KEY_PIN         PINB
#define KEY0            7
#define KEY1            6
#define KEY2            0
#define KEY3            1
#define KEY4            2
#define KEY5            3
#define KEY6            4
#define KEY7            5
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2 | 1<<KEY3 | 1<<KEY4 | 1<<KEY5 | 1<<KEY6 | 1<<KEY7)

// Segment und Tasten-Ausgänge definieren
// ======================================
#define SEGMENT_DDR    DDRD
#define SEGMENT_PORT  PORTD
#define OUT_DDR         DDRC
#define OUT_PORT        PORTC
#define OUT1            0
#define OUT2            1
#define OUT3            2
#define OUT4            3
#define OUT5            4
#define OUT6            5
#define ALL_OUT        (1<<OUT1 | 1<<OUT2 | 1<<OUT3 | 1<<OUT4 | 1<<OUT5 | 1<<OUT6)

#define LED0      (1<<PC0)
#define LED1      (1<<PC1)
#define LED2      (1<<PC2)
#define LED3      (1<<PC3)
#define LED4      (1<<PC4)
#define LED5      (1<<PC5)
#define NR_KONFIGS    9
#define NR_KEYS      6

uint8_t Pattern[NR_KONFIGS][NR_KEYS] PROGMEM =
  {
    {LED0,LED1,LED2,LED3,LED4,LED5},          // Konfiguration 0
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 1
    {LED2,LED0,LED4,LED1,LED3,LED5},          // Konfiguration 2
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 3
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 4
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 5
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 6
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 7
    {LED0,LED2,LED4,LED1,LED3,LED5},          // Konfiguration 8
   };

  while(1)
  {
    Summe = 0;

    if(!(KEY_PIN & 0x01))                // Wenn Taste PortB.0 auf HIGH
      Summe |= pgm_read_byte(&Pattern[nKeyPress][0]);
    if(!(KEY_PIN & 0x02))                // Wenn Taste PortB.1 auf HIGH
      Summe |= pgm_read_byte(&Pattern[nKeyPress][1]);
    if(!(KEY_PIN & 0x04))                // Wenn Taste PortB.2 auf HIGH
      Summe |= pgm_read_byte(&Pattern[nKeyPress][2]);
    if(!(KEY_PIN & 0x08))                // Wenn Taste PortB.3 auf HIGH
      Summe |= pgm_read_byte(&Pattern[nKeyPress][3]);
    if(!(KEY_PIN & 0x10))                // Wenn Taste PortB.4 auf HIGH
      Summe |= pgm_read_byte(&Pattern[nKeyPress][4]);
    if(!(KEY_PIN & 0x20))                // Wenn Taste PortB.5 auf HIGH
      Summe |= pgm_read_byte(&Pattern[nKeyPress][5]);

    OUT_PORT = Summe;                  // Definierte Konfiguration ausgeben

........

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

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

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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:
>
>
> if(!(KEY_PIN & 0x01))                // Wenn Taste PortB.0 auf HIGH
>       {
>         PORTC |= (1 << PC0);        // LED an PC0 umschalten
>         _delay_ms (30);
>         PORTC &= ~(1 << PC0);        // LED an PC0 umschalten
>         _delay_ms (30);
>       }
> 
>
> 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.

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
...
uint8_t cntTicks;
volatile uint8_t repeatMask;

ISR( .... )   //periodischer Interrupt
{
  cntTicks++;
  if( cntTicks == 50 ) {  // zb nach 50 mal 10ms
    repeatMask ^= 0xFF;   // von 0x00 nach 0xFF
                          // und umgekehrt: von 0xFF nach 0x00
    cntTicks = 0;
  }
  ...
}

...

int main()
{
  ...

  while( 1 ) {

    if( !( PINB & 0x01 ) ) {

      PORTC = 0x03 & repeatMask;
    }

    ....
  }
}

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)

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke!

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

// Timer Interrupt von 10ms definieren
// ===================================
ISR(TIMER0_OVF_vect)
{
  static uint8_t ct0, ct1, rpt;
  uint8_t i;

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

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

  if((key_state & REPEAT_MASK) == 0)            // Überprüfe Tastenwiederholfunktion
    rpt = REPEAT_START;                  // Starte Verzögerung
  if(--rpt == 0)
  {
    rpt = REPEAT_NEXT;                  // Wiederhole Verzögerung
    key_rpt |= key_state & REPEAT_MASK;
  }

  cntTicks++;
  if( cntTicks == Fire )      // zb nach <Fire> mal 10ms
  {
    repeatMask ^= 0x01;   // von 0x00 nach 0x01
                    // und umgekehrt: von 0x01 nach 0x00
    cntTicks = 0;
  }
}

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:
if(Dauerfeuer= 1) // Wenn Dauerfeuer aktiv
{
OUT_PORT = Summe & repeatMask;                  // Definierte Konfiguration mit Dauerfeuer an Ausgang PortC.0 ausgeben
}
else
{
OUT_PORT = Summe // sonst nur definierte Konfiguration ausgeben
}

[c]

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Lies endlich den verdammten Beitrag über "Bitmanipulation"

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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:
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?

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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:
    repeatMask ^= 0x01;   // von 0x00 nach 0x01
                    // 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....

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lokus Pokus (derschatten)
Datum:

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

Wie mach ich das?

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: gast0815 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Claudio H. (bastelfinger)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Volker Schulz (volkerschulz)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein AVR ist leider voll belegt. Da ist kein einziger Pin mehr frei.

Autor: Volker Schulz (volkerschulz)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Volker Schulz (volkerschulz)
Datum:

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

Volker

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Volker Schulz (volkerschulz)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erklär mir bitte wie man PWM "aktiviert"

Autor: Volker Schulz (volkerschulz)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaub ich habs jetzt gelöst:

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

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

Ihr dürft mich Gott nennen :)

Autor: Volker Schulz (volkerschulz)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manfred W. schrieb:

> Ihr dürft mich Gott nennen :)

Scheusliche Lösung

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Scheusliche Lösung

Ich hab nur deinen Rat befolgt :)

Was ist daran scheuslich?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?
uint8_t KonfigPattern[NR_KONFIGS][NR_KEYS] =
  {
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 1
    {LED1,LED0,LED3,LED2,LED5,LED4,1},            // Konfiguration 2
    {LED5,LED4,LED3,LED2,LED1,LED0,5},            // Konfiguration 3
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 4
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 5
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 6
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 7
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 8
    {LED0,LED1,LED2,LED3,LED4,LED5,0},            // Konfiguration 9
   };

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.

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
    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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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."

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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


....

ISR( .... )   //periodischer Interrupt
{
  cntTicks++;
  if( cntTicks == 50 ) {  // zb nach 50 mal 10ms
    repeatMask ^= 0xFF;   // von 0x00 nach 0xFF
                          // und umgekehrt: von 0xFF nach 0x00
    cntTicks = 0;
  }
  ...
}

....

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

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

  while(1)
  {
    Summe = 0;

    if(!(KEY_PIN & 0x01))                // Wenn Taste PortB.0 auf HIGH
      Summe |= Pattern[nKonfig][0]);
    if(!(KEY_PIN & 0x02))                // Wenn Taste PortB.1 auf HIGH
      Summe |= Pattern[nKonfig][1]);
    if(!(KEY_PIN & 0x04))                // Wenn Taste PortB.2 auf HIGH
      Summe |= Pattern[nKonfig][2]);
    if(!(KEY_PIN & 0x08))                // Wenn Taste PortB.3 auf HIGH
      Summe |= Pattern[nKonfig][3]);
    if(!(KEY_PIN & 0x10))                // Wenn Taste PortB.4 auf HIGH
      Summe |= Pattern[nKonfig][4]);
    if(!(KEY_PIN & 0x20))                // Wenn Taste PortB.5 auf HIGH
      Summe |= Pattern[nKonfig][5]);

    // Dauerfeuer behandeln
    if( !(KEY_PIN & repeatPin ) ) {
      fire = repeatOutputMask & repeatMask;
      Summe &= ~repeatOutputMask;
      Summe |=  fire;
    }

    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.

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wie müssen repeatPin und repeatOutputMask deklariert werden?

Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.