mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Probleme auf ATmega88PA


Autor: Marc Brexner (drakenfly)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute!

Ich bin derzeit schwer am rätseln, da mir ein sehr mysteriöses Problem 
auftritt. Es handelt sich um eine Binäre Uhr, bei der die LEDs 
pulsierend betrieben werden.

Dazu habe ich mir folgendes gedacht:

#define LED_MASK 0b00000000111101111111011111110011

ich habe eine Maske, die aussagt, ob sich an der aktuellen Position 
überhaupt eine LED befindet. Der Aufbau ist ja so:

x o | x o | x o       <-- an PC2
x o | o o | o o       <-- an PC3
o o | o o | o o       <-- an PC4
o o | o o | o o       <-- an PC5

trotzdem zähle ich die Positionen so:

3 7 | 11 15 | 19 23
2 6 | 10 14 | 18 22
1 5 |  9 13 | 17 21
0 4 |  8 12 | 16 20

also, egal ob eine LED da ist, oder nicht, da ist eine Fix-Position. 
Dies mache ich, damit ich von einer einfachen Counter-Variable, die sich 
in einem Bereich von 0-24 bewegt, einfach auf die Matrix umrechnen kann.

Wie man oben sieht sind die Zeilen von oben nach unten an PC2 - PC5 
angeschlossen, die Spalten sind von links nach rechts an PB0 - PB5
PORTB ist für GND zuständig, PORTC für VCC.

Das heißt, wenn ich LED 14 einschalten will:
PORTC = 0x00; // Alles aus (in Sperrrichtung)
PORTB = 0xFF;
PORTC |= (1<<PC3);
PORTB &= ~(1<<PB3);

So, nun lasse ich das ganze über einen Timer pulsieren.
#define LED_MASK 0b00000000111101111111011111110011
#define LED_MAX 32 // 24 LEDS -> bei 25 wieder auf 0 setzen!

ISR (TIMER0_OVF_vect)
{
PORTB = 0xFF; // Alles aus, Dioden in Sperrichtung
PORTC = 0x00;
PORTB &= ~(1<<(currentLed / 4)); // Hier sieht man nochmal, was ich mit dem Umrechnen meinte
PORTC |= (1<<(5 - (currentLed % 4)));
do
{
  currentLed++;
}
while (~LED_MASK & (1<<currentLed));
if (currentLed >= LED_MAX) { // Es gibt nur "24" (aufgrund der Löcher) LEDS
  currentLed = 0; // -> Wieder von vorne beginnen
}
}

Komischerweise leuchtet bei diesem Code aber nicht LED 15 auf.

Und wenn ich es nicht mehr pulsieren lasse, sondern auf CPU/1024 stelle 
und die einzelnen aufleuchten sehe, fällt auch auf, dass der µc versucht 
NACH der 15. LED jede LED auf. Man merkt das durch die zeitlichen 
Abstände, z.B. ist zwischen 18 und 20 ein längerer Abstand und nach 24 
dauert es auch 8 Schritte bis er wieder bei 0 beginnt.

Ich dachte mir, dass es etwas damit zu tun hat, dass es sich hier um 32 
bit handelt, und der ATmega88PA das vllt. nicht verarbeiten kann.

Habt ihr eine Idee? Ich bin ja doch noch ein bisschen ein Frischling und 
habe nicht sooo viel Erfahrung. Aber ich bin seit 5 Stunden am 
experimentieren und bekomm es nicht hin =/

Vielen Dank im Vorhinein!
Lg Marc

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Marc Brexner schrieb:
> Ich dachte mir, dass es etwas damit zu tun hat, dass es sich hier um 32
> bit handelt, und der ATmega88PA das vllt. nicht verarbeiten kann.

Der ATmega88 kann keine 32-Bit Werte verarbeiten, aber darum künnert 
sich der Compiler -- vorausgesetzt, der C-Code veranlasst ihn dazu.

Da wir die Deklarationen nicht sehen dürfen, rate ich mal, daß die 
Variablen nur 16 Bits breit sind.

Ein Anfang wäre z.B. anstatt
> #define LED_MASK 0b00000000111101111111011111110011
ein
#define LED_MASK 0b00000000111101111111011111110011UL
damit das nicht nur eine 16-Bit Konstante ist, sondern 32 Bits hat.

Ausserdem empfehle ich dir Warnungen zu aktivieren (z.B. -W -Wall) und 
darauf zu achten.

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

Bewertung
0 lesenswert
nicht lesenswert
while (~LED_MASK & (1<<currentLed));

du musst die 1 zu einem long machen, damit du auch die Bits über dem Bit 
15 noch erreichst. Wenn currentLED den Wert 16 hat, würde sonst

   1<<currentLED

eine glatte 0 ergeben, weil du das 1-Bit aus dem Bereich für int (16 
Bit) hinausgeschoben hast.

while (~LED_MASK & (1UL<<currentLed));


> und nach 24
> dauert es auch 8 Schritte bis er wieder bei 0 beginnt.

Logo.
Zitat
#define LED_MAX 32 // 24 LEDS -> bei 25 wieder auf 0 setzen!

wieso 32? Du hast doch nur 24 Led.

Autor: Marc Brexner (drakenfly)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also an und für sich klappt das jetzt endlich, danke für den Hinweis! 
Auf das hätte ich eigentlich auch selbst kommen müssen.... :(

Trotz allem leuchtet jetzt komischerweise die letzte LED heller als alle 
anderen.
#define LED_MASK 0b00000000111101111111011111110011UL
#define LED_MAX 24 // 24 LEDS -> bei 25 wieder auf 0 setzen!
ISR (TIMER0_OVF_vect)
{
  // LEDS pulsieren lassen über Register Display
  PORTB = 0xFF; // Alles aus, Dioden in Sperrichtung
  PORTC = 0x00;
  PORTB &= ~(1UL<<(currentLed / 4));
  PORTC |= (1UL<<(5 - (currentLed % 4)));
  do
  {
    currentLed++;
  }
  while ((~LED_MASK) & (1UL<<currentLed));
  if (currentLed >= LED_MAX) { // Es gibt nur "24" (aufgrund der Löcher) LEDS
    currentLed = 0; // -> Wieder von vorne beginnen
  }
}

Setze ich LED_MAX auf 23 leuchtet die letzte gar nicht mehr...

Lg Marc

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Möglicherweise wird für die letzte LED so lange geschoben (immerhin sind 
da einige 0en in LED_MASK), daß die nächste IRQ verpennt wird und erst 
verzögert nachgeholt wird.

1. In PORTB |= ... genügt 1 <<  anstatt 1UL << weil es nur einen
   8-Bit Wert berechnet wird und es dietch /4 bzw. %4 nicht zum
   Überlauf kommt.

2. Anstatt 1UL << in der Schleife ist es besser, eine Variable x mit
   LED_MASK zu füllen und die per ISR einmal nach rechts zu schieben.
   Wenn x == 0 ist, beginnt ein neuer Zyklus. Abgetestet, ob
   eine LED vorhanden ist, geht dann einfach per (x & 1).

Vielleicht löst das die Effizienzprobleme. Rumgeschiebe um variable 
offsets ist leider ineffizient auf AVR, zumal es in der Schleife 
mehrfach geschieht, vor allem gegen Ende, also nach LED 23.

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.