Pins zu einer Adress-Variablen?

Hallo,

ich habe 16 IO's per #define zu Adressleitungen die ich lesen möchte zugewiesen.

Beispiel:

#define A0  16
#define A1  17
#define A2  18

usw.

Nun möchte ich diese 16 IO's als eine Adresse von $0000-$FFFF aus einer variablen lesen/auswerten können.

Wie kann man die 16 einzelnen IO's zu einer Variablen zusammenfasssen,
so daß ich später z.B.
if adr = 0xF000 ...
abfragen kann?

Ein paar mehr Infos solltest du schon liefern.
Was für Daten in welcher Form liefern denn dies Leitungen ?
Stehen diese Daten kurz oder ständig an ?

Bisher kann ich mir aus deiner Beschreibung nichts vorstellen.

die 16 IO's sind an einer Hardware mit 16 Adressleitungen angeschlossen und sind rein digital.
Die Adressen können sich ständig ändern.
Ganz einfach gesagt:
Ich möchte von einem 8Bit Computer den Adressbus auswerten.

Im Prinzip müssen diese IO's ständig gelesen werden und sollen in einer Variablen "adr" als 16Bit Adresse abfragbar sein

Warum Pins lesen, wenn man ganze Ports lesen kann?

geht hier leider nicht.
Darum geht es aber auch nicht, sondern wie man 16pins zu einer Variablen hinzufügen kann.

iss klar...

versuchs doch mal mit | oder |= und <<

Nimm einen Atmega 2560, dann kannst Du Deine 16 Leitungen an die Ports F und K (A0 bis A15) legen und diese mit 2 Lesebefehlen einlesen und mit <<8 kombinieren.

Ich vermute aber mal, dass sie die Adressleitungen schneller ändern, als Du sie mit einem MC auslesen kannst.

Gruß Tommy

ungeprüft:

/* 
  https://forum.arduino.cc/t/pins-zu-einer-adress-variablen/1385137
*/

const uint8_t pin[16] {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};

void readMyPort() {
  uint16_t my16bitPort = 0;
  for (size_t i = 0; i < sizeof(pin) / sizeof(pin[0]); i++) {
    if (digitalRead(pin[i]) == HIGH) my16bitPort |= (1 << i);
  }
  Serial.print(my16bitPort, HEX);
  Serial.print("\t");
  Serial.println(my16bitPort, BIN);
}

void setup() {
  Serial.begin(115200);
  for (auto & i : pin) pinMode (i, INPUT_PULLUP);
}

void loop() {
  readMyPort();
  delay(1000); // dirty delay
}

wenns einfacher ist, kannst du auch bitSet nehmen.
https://docs.arduino.cc/language-reference/de/funktionen/bits-and-bytes/bitSet/

Wie stellst Du sicher, dass Du die Adressleitungen nur ausliest, wenn die Adresse stabil anliegt? Und wie häufig ist 'ständig'? Wenn Du die INPUT-Pins nacheinander einliest, wird sich die Adresse mit hoher Wahrscheilichkeit während des Einlesens ändern und du liest Zufallswerte. Du wirst vermutlich ein 'capture-Register' für die Adressleitungen brauchen.

Hallo,

deine 16 Leitungen ändern sich nicht. Sonst hättest du keine defines für die Pins.
Der Wert, die Zustände, die Pegel, der 16 Leitungen ändern sich. Logisch.
Diese 0 und 1 möchtest du in einer 16 Bit Variablen speichern. Soweit klar.
Diese 16 Bits in einer Variablen sind völlig unabhängig an welchen Port Pins du die 16 Leitungen, die du überwachen möchtest, angeschlossen hast.
Wenn du anfängst alle 16 Leitungen einzeln nacheinander einzulesen, passiert das was MicroBahner beschreibt. Problem dabei ist, alle 16 Signale stammen nicht vom gleichen Zeitpunkt des Einlesens, du hast keine Zuordnung. Damit kann man sich das gesamte Vorhaben sparen. Man liest irgendwelchen Müll ein der nichts mit den Bitzuständen auf dem Bus zu tun hat. Wenn das ein Datenbus ist den ich mir im Moment vorstelle.

Man kann sich externe I/O Expander holen zum Zeitgleichen einlesen. Dann hat man aber noch einen Bus dazwischen. I2C oder SPI. Die Abfrage kostet Zeit. Kommt darauf an wie hoch die Abtastrate sein soll. Oder man wählt einen ausreichend großen Controller, Arduino Mega2560, woran man zwei 8-Bit Ports frei hat. Hier liest man 8-Bit auf einmal ein und das 2x hintereinander. Wenn diese 16 Bit zusammengehören, hat man auch einen Zeitversatz, selbst wenn es nur paar wenige Takte sind. Dann bräuchte man einen 16Bit oder 32Bit Controller der größere Portbreiten hat. Oder entsprechendes I/O Expander.

Jetzt musst du dir überlegen wir kritisch die Signale sind.
Was ist das für ein Bus?
Welchen Takt hat der Bus?
Muss jede Änderung erfasst werden oder darf es Lücken geben?
Müssen alle Bits zeitlich syncron erfasst werden?
usw. …

Atmega2560 wäre viel zu langsam.
Ich habe einen PiPico2 mit 150Mhz.

Zum synchronisieren soll PHI2, also der Systemtakt des abzufragenden Systems benutzt werden.

IF PHI2 == High
adr lesen...

PHI2 hat eine Taktgeschwindigkeit von 1.77 MHz.

bis der Adressbus wieder "ungültig" ist, sollte der PiPico2 das doch längst ausgelesen haben.

Habe spasseshalber mal ChatGPT gefragt... :slight_smile:


uint16_t readAddress() {
  uint16_t adr = 0;
  for (int i = 0; i < 16; i++) {
    int pinValue = digitalRead(A0 + i);  // A0 ist z. B. 14 auf Uno
    adr |= (pinValue << i);              // Bitweise einfügen
  }
  return adr;
}

void loop() {
  uint16_t adr = readAddress();

  if (adr == 0xE000) {
    // Deine Aktion hier
  }
}

wobei digitalRead(A0 + i) nicht funktionieren wird, da die Pins/GPIOs nicht fortlaufend sind

Ach, man könnte auch einen 32Bit µC verwenden, welcher den Kram per DMA einliest.
Schnellstmöglich, in einem Rutsch.

Aber der Grund lautet

PiPico ist schon da.
ganze Ports benutzen geht layouttechnisch nicht!

hättest das vor dem ersten Post gemacht und mit geppostet hätte ich mir 5 Min gespart.

ja sorry, bin auch eben erst darauf gekommen, ChatGPT mal zu fragen...

Mit nem Array sollte es eigentlich funktionieren, da die GPIOs nicht fortlaufend sind.

#include <digitalWriteFast.h>

// --- Adressleitungen ---
#define A0   36
#define A1   37
#define A2   38
#define A3   39
#define A4   23
#define A5   22
#define A6   21
#define A7   20
#define A8   33
#define A9   19
#define A10  35
#define A11  17
#define A12  34
#define A13  32
#define A14  18
#define A15  16

// --- Datenleitungen ---
#define D0   40
#define D1   41
#define D2   42
#define D3   43
#define D4   47
#define D5   46
#define D6   45
#define D7   44

// --- Steuerleitung ---
#define PHI2 2

// --- Arrays für Adress- und Datenpins ---
const uint8_t adrPins[16] = 
{
  A0, A1, A2, A3, A4, A5, A6, A7,
  A8, A9, A10, A11, A12, A13, A14, A15
};

const uint8_t dataPins[8] = 
{
  D0, D1, D2, D3, D4, D5, D6, D7
};

void setup() 
{
  for (int i = 0; i < 16; i++) 
  {
    pinMode(adrPins[i], INPUT);
  }
  for (int i = 0; i < 8; i++) 
  {
    pinMode(dataPins[i], INPUT);
  }
  pinMode(PHI2, INPUT);
}

uint16_t readAddress() 
{
  if (PHI2 == HIGH)
  {
    uint16_t adr = 0;
    for (int i = 0; i < 16; i++) 
    {
      int bit = digitalReadFast(adrPins[i]);
      adr |= (bit << i);
    }
    return adr;
  }
}

uint8_t readData() 
{
  if (PHI2 == HIGH)
  {
    uint8_t data = 0;
    for (int i = 0; i < 8; i++) 
    {
      int bit = digitalReadFast(dataPins[i]);
      data |= (bit << i);
    }
    return data;
  }
}

void loop() 
{
    // Beispiel: Adresse exakt 0xE000
    if (adr == 0xE000) {
      // Aktion bei Adresse 0xE000
    }
  }
}

sieht doch soweit richtig aus, oder?

weg mit den magic numbers 8 und 16.
defines brauchst da auch nicht. Nimm constexpr uint8_t

Hallo,

wenn du meinst das es nicht so Zeitkritisch ist, dann probiere es aus. Du wirst testen müssen ob der Pico schnell genug ist. Bevor du ChatGPT fragst, solltest du den Code von noiasca verstehen. Kann man noch zeitlich optimieren, die Basis ist da.

Nochmal kurz überschlagen. 150MHz / 1,77MHz = 84,7 Takte Luft
Das wird dennoch sportlich.
digitalRead befürchte ich, wird zu langsam ein.
Du wirst wohl direkt die Register auslesen müssen.
Ich würde ausgerollten Code schreiben. Keine Schleife. Ich würde versuchen die 16 Leitungen dennoch sortiert an die freien Pins zu klemmen. Dann sollte der Code zeitlich zu optimieren sein. Weniger einzelne Bitschubserei. Bit zusammenfassen usw.
Probiere es aus.

warum weg?
mit #defines wird m.E. nach übersichtlicher, da kommen noch mehr Dinge dazu

deshalb digitalReadFast..

Na mal sehen, noch ist der Pico in der Post...