17 LEDs sollen blinken, nur 16 tun es

Hallo,
ich wollte ein paar LEDs blinken lassen. Bei den LEDs 0 bis 15 ist mir das auch gelungen. Nur Port 16 und 17 machen mir Sorgen. Port 16 funktioniert, aber nicht mit der auskommentierten Zeile. Geht die sprachinterne Bitverschiebung nur bis zum BIT 15? Und die LED 17 geht gar nicht an. Hardware ist in Ordnung, wenn ich digitalWrite (17,HIGH) eingebe, leuchtet die LED. Was ist falsch?

void setup() {
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  pinMode(14, OUTPUT);
  pinMode(15, OUTPUT);
  pinMode(16, OUTPUT);
  pinMode(17, OUTPUT); }

void loop() 
{
  long i;
  for (i=0; i<=131071 ; i++)
  {
  digitalWrite(0, (i&1!=0)); 
  digitalWrite(1, (i&1<<1)); 
  digitalWrite(2, (i&1<<2));  
  digitalWrite(3, (i&1<<3));  
  digitalWrite(4, (i&1<<4));  
  digitalWrite(5, (i&1<<5));   
  digitalWrite(6, (i&1<<6));  
  digitalWrite(7, (i&1<<7)!=0);   
  digitalWrite(8, (i&1<<8)!=0);   
  digitalWrite(9, (i&1<<9)!=0);   
  digitalWrite(10, (i&1<<10)!=0);  
  digitalWrite(11, (i&1<<11)!=0);   
  digitalWrite(12, (i&1<<12)!=0);  
  digitalWrite(13, (i&1<<13)!=0);  
  digitalWrite(14, (i&1<<14)!=0);  
  digitalWrite(15, (i&1<<15)!=0);   
 // digitalWrite(16, (i&1<<16)!=0);  
  digitalWrite(16, (i&65536)!=0);  
  digitalWrite(17, (i&1<<17)!=0);   
  digitalWrite(17, (i&131072)!=0);  
  delay (10);
}}
for (i=0; i<=131071 ; i++)

Vieleicht weil 131071 kleiner als 131072 ist?
Wenn dann i auch gleich 131072 wird, weil Du die FOR Schleife bis 131072 korrigierst, dann blitzt die LED für 10mS alle 21,8 Minuten auf.
Grüße Uwe

Auf einem 'standard' Arduino mit 8-Bit Prozessor werden alle Berechnungen standardmaßig 16 Bit lang berechnet. Dein (1<<16) ist also eine 16-Bit Berechnuing, und das Bit fällt vorn wieder raus.
Wenn Du das als long berechnen willst, musst Du das dem Prozessor sagen:

digitalWrite(16, (i&1L<<16)!=0);

Und für das Verschieben um 17 Bits ist deine Schleife zu kurz - so groß wird i garnicht.
Damit die auch wieder doppelt so lang an ist wie die Led davor musst Du bis 262144 zählen.

Danke! Funktioniert nun wie erwartet. Das mit dem 1L war der Punkt.

Hallo Uwe,
stimmt, es war ein wenig langsam mit 20 Minuten. Nachdem es nun richtig lief, habe ich es noch etwas kompakter und schneller gemacht. 2 Sekunden pro Durchlauf. So gut, oder geht das noch besser?

void setup() {
  DDRD=255;
  DDRB=63;
  DDRC=63;
  }
void loop() {
  long i;
  for (i=0; i<=262144 ; i++)
  {
  PORTD=i&255;
  PORTB=63L&i>>8;
  PORTC=15L&i>>14;
 // delay(500);
}}

Hi

So ein klein Wenig richt Das ja schon nach einem der bekannten Arduino ... nur stört mich Da, daß D0 und D1 benutzt werden, was eigentlich nicht sonderlich intelligent ist - Die werden bereits vom USB-Gebämmsel gebraucht.
Dann kommt hinzu, was oben schon zu den 16 Bit gesagt wurde - ein int auf einem normalem Arduino hat halt nur 16 (0...15) - da kann man schieben, wie man will, Das wird Null :slight_smile:

MfG

postmaster-ino:
Hi

So ein klein Wenig riecht Das ja schon nach einem der bekannten Arduino ... nur stört mich da, daß D0 und D1 benutzt werden, was eigentlich nicht sonderlich intelligent ist - Die werden bereits vom USB-Gebämmsel gebraucht.
Dann kommt hinzu, was oben schon zu den 16 Bit gesagt wurde - ein int auf einem normalem Arduino hat halt nur 16 (0...15) - da kann man schieben, wie man will, Das wird Null :slight_smile:

MfG

Ja, das ist ein Arduino. Allerdings hat der Pro mini kein USB. Er erzeugt Rechtecksignale von 66kHz bis 1/8 Hz, von Port zu Port jeweils mit der doppelten Frequenz. Leider ist ein wenig Jitter dabei, aber das stört mich nicht.

Hallo,

den for Schleifenzähler bitte niemals ohne Grund außerhalb definieren.

Anbei noch ein einfaches Bsp. wie man das eleganter lösen kann, statt Spaghetticode.

// Arduino Mega2560

const byte pinLed [] = {28, 29, 30, 31, 32, 33, 34, 35};
const byte ANZAHL_LED = sizeof(pinLed) / sizeof(pinLed[0]);

void setup(void)
{  
  for (byte i = 0; i < ANZAHL_LED; ++i)
  {
    pinMode(pinLed[i], OUTPUT);
  }
}

void loop(void)
{
  for (byte i = 0; i < ANZAHL_LED; ++i)
  {
    digitalWrite(pinLed[i], HIGH);
    delay(100);
  }

  for (byte i = 0; i < ANZAHL_LED; ++i)
  {
    digitalWrite(pinLed[i], LOW);
    delay(100);
  }
}

zur Vollständigkeit noch die for range-based Variante

// Arduino Mega2560
// for Range-Based Variante
// https://forum.arduino.cc/index.php?topic=661149.0

const byte pinLed[] = {28, 29, 30, 31, 32, 33, 34, 35};

void setup(void)
{  
  for (auto &i: pinLed)
  {
    pinMode(i, OUTPUT);
  }
}

void loop(void)
{
  for (auto &i: pinLed)
  {
    digitalWrite(i, HIGH);
    delay(100);
  }

  for (auto &i: pinLed)
  {
    digitalWrite(i, LOW);
    delay(100);
  }
}

Nur ist dein Beispiel um Welten langsamer als das, was du als Spaghetticode bezeichnest.

Hi

Dann entferne doch Mal die delay(100); und prüfe erneut.

Das Verstehen des Sketch hilft Da natürlich auch ungemein, manches Mal hilft sogar ein einfaches Anschauen.

MfG

Eierschale:
Nur ist dein Beispiel um Welten langsamer als das, was du als Spaghetticode bezeichnest.

Das ist doch nur künstlich, damit man auch was sieht. Auch die kleinen Controller sind so schnell dass du echte Performance-Unterschiede nicht mit bloßem Auge siehst

Das ist mir auch klar, dass delay da ist, um das Programm zu verzögern. Ganz ganz früher hatte ich einen Z80 oder eine 6502 genommen, 00 oder EA fest verdrahtet, also für nicht-Assemblerkenner den Befehl NOP, No Operation. Da der Befehl per Lötbrücke fest verdrahtet war, wurde er jedesmal aufgerufen, egal, was der Adresscounter gerade vorgab. So wurde bei jedem (je nach CPU) Takt der Adressbus binär um 1 hochgezählt. Man hatte dann an 16 Adress-Leitungen 16 Rechtecksignale, mit jeweils halber Frequenz der Adressleitung darunter. Nun fragte ich mich, ob - 35 Jahre später - eine ATMEGA in der Lage ist, das Verhalten in Software zu imitieren. Das hat er nun nicht ganz geschafft, immerhin kam ich dabei auf 66kHz max. Rechteckfrequenz. Natürlich sieht man da mit dem bloßen Augen keinen Unterschied zu einem sauber strukturiertem, aber simplen LED-Blinkprogramm.

Ein Controller ist keine CPU. Beim Controller ATMEGA328 ist der Daten und Adressbus nicht nach außen geführt.
Grüße Uwe

Hallo,

sag erstmal was dein primäres Ziel ist. Dann bekommste vielleicht eine passendere Lösung.

Eierschale:
Nun fragte ich mich, ob - 35 Jahre später - eine ATMEGA in der Lage ist, das Verhalten in Software zu imitieren. Das hat er nun nicht ganz geschafft, immerhin kam ich dabei auf 66kHz max. Rechteckfrequenz.

Wenn man das richtig programmiert, schafft er das schon:

void setup() {
  DDRD = 255;
  DDRB = 63;
  DDRC = 63;
  noInterrupts();
  while (1) {
    if ( ++PORTD == 0 ) {
      if ( ++PORTB & 0x3f == 0 ) {
        ++PORTC;
      }
    }
  }
}
void loop() {
}

Da liegt die Frequenz am D0 bei ca. 1,3Mhz - also schneller als das ein normaler 6502 ( 1MHz Takt ) geschafft hat. Einen kleinen Jitter hast Du natürlich jeweils wenn er auf den nächsten Port schaltet. Wenn Du die Interrupts nicht abschaltest kommt ca. jede ms noch die ISR für die millis dazwischen.

Wie sinnvoll das Ganze ist, steht auf einem anderen Blatt... (Aber der 6502 konnte da ja auch schon nichts Vernünftiges machen :wink: ).
Wesentlich schneller geht das jedenfalls mit einer einfach Zählerkette aus HC-Bausteinen 8)

Hallo MicroBahner,

dein Code läuft tatsächlich schnell, Respekt. Leider kommt bei mir nichts an Port C an und ich weiss nicht, wo der Fehler ist. Hast du eine Idee?

Wofür ich das brauche: Beim Vermessen einiger Bauteile benutzte ich einen Rechteckgenerator und einen nachgeschalteten Mosfet um das Verhalten bei unterschiedlichen Frequenzen zu verstehen. Das Ändern der Ausgangsfrequenz war mir zu umständlich. Mit der Arduino mini pro Schaltung mit der 2-reihigen 2,54mm Steckkontaktleiste stecke ich einen Jumper um.

Wolfgang

Hallo,

könnte mir vorstellen das müßte so sein, nur beim letzten Bit bzw. beim Nullen von Port D/B gibts eine kurze Lücke.

void setup()
{
  DDRD = 255;
  DDRB = 63;
  DDRC = 63;
  noInterrupts();
  while (1)
  {
    if ( ++PORTD == 0 ) {
      if ( ++PORTB == 64 ) {
        PORTB = 0;
        ++PORTC;
      }
    }
  }
}

void loop()
{}

Wegen der Aufgabe. Könnte mir für dich vorstellen das ein Frequenzgenerator zu programmieren auch eine nette Aufgabe wäre. Könnte man mit Poti bzw. Encoder live die Einstellungen ändern - ohne erst Jumper umzustecken.

Hallo Wolfgang,

Eierschale:
Leider kommt bei mir nichts an Port C an und ich weiss nicht, wo der Fehler ist. Hast du eine Idee?

ich bin mir eigentlich sicher dass das bei mir funktioniert hat. Das war zwar auf einem Nano und nicht Mini. Das sollte aber keinen Unterschied machen - ist ja letztendlich das gleiche, nur ohne seriell-USB Wandler. Kann es aber derzeit nicht testen, da ich unterwegs bin.

Hallo,

wenn ich anmerken darf. Du hast scheinbar nur Port D und B angeschaut.
PortC wird nicht getaktet, weil der Vergleich nie wahr wird. :wink:

if ( ++PORTB & 0x3f == 0 ) {
        ++PORTC;
      }

Im Grunde möchte man "nur" erkennen wann Port.B den Wert 63 bzw. 64 erreicht hat?
Der künstliche Überlauf fehlte auch noch, sonst hat die weitere Takthalbierung "Lücken". :wink:

Eigentlich alles in allem eine schöne und einfache Lösung. Keine Frage. Wunderbare Idee von dir. Mir persönlich würden nur die Lücken in der Takterzeugung der ersten beiden Ports stören. Was bedingt durch den if Vergleich hervorgerufen wird.

Hi

Vorschlag:
Varialbe 16 32bit stur hochzählen
Die untersten 8 Bit nach PORTD (D0...D7) - D0 und D1 sind die Serielle Schnittstelle auf UNO/NANO
Die Bits 9...14 nach PORTB (D8...D13)
Die Bits 15...20 nach PORTC (A0...A5)
(Wenn man den Reset-Pin zum normalen I/O macht, wäre Der an PC6 zu finden)
(NUR machen, wenn man weiß, was man tut, ohne Reset ist ruck zuck Alles doof)

So habe ich keine IFs, Die den zeitlichen Ablauf ungleichmäßig stören.
Die Bit-Schieberei habe ich IMMER, die Port-Zuweisung habe ich IMMER - egal, ob sich was geändert hat, oder nicht.

MfG

Edit
wenn wir 20 Bit ausgeben wollen, wird eine 16bit Variable wohl 'zu kurz' sein - auf 32 geändert