Tekst aan variabele namen toevoegen: help me alstublieft deze code in te korten

Ik probeer de code in te korten onder "setup" hieronder, waar ik meer dan 120 variabelen heb die van een externe EEPROM worden gelezen. Er is een patroon waarbij de variabele die de positie van het EEPROM-adres opslaat de naam is van de variabele die wordt ingevuld, plus het woord "Pos".

byte fanSpeed, nl1Toggle, ledsToggle;
byte fanSpeedPos = 12, nl1TogglePos = 95, ledsTogglePos = 7;

void setup() {
  fanSpeed = readEE(fanSpeedPos);
  nl1Toggle = readEE(nl1TogglePos);
  ledsToggle = readEE(ledsTogglePos);
  //there are over 120 of the above readEE statements in the actual code.
}

uint8_t readEE(uint8_t entry) {
  readEEPROM(AT24C32_ADDRESS, 1, entry);
}

Idealiter zou ik willen dat het zo werkt (ik gebruik pseudo-code omdat ik niet weet hoe dit moet):

char* variableNames [] = { "fanSpeed", "nl1Toggle", "ledsToggle" };
byte fanSpeedPos = 12, nl1TogglePos = 95, ledsTogglePos = 7;

void setup() {
  for (int i = 1; i < 120; i++;) {
    variableNames[i] = readEE(variableNames[i] + 'Pos');
  }

Is dit mogelijk met C ++/Arduino?

1
Kopieer de EEPROM-variabele naar RAM (dat wil zeggen naar een tekenarray). Gebruik vervolgens strcat om uw woord aan het einde toe te voegen. Geef voldoende ruimte voor de voltooide woorden en de afsluitende 0x00 byte.
toegevoegd de auteur Nick Gammon, de bron

2 antwoord

Dit kan worden bereikt met een eenvoudige preprocessor-macro:

#define readEE(VAR) VAR = readEEPROM(AT24C32_ADDRESS, 1, VAR ## Pos)

U kunt dan gebruiken:

readEE(foo);

en het zal worden uitgebreid naar:

foo = readEEPROM(AT24C32_ADDRESS, 1, fooPos);

De operator ## in macro's breidt zich uit aan beide zijden (VAR en Pos) en voegt vervolgens de resultaten samen. Omdat VAR zelf een macro is (wat je ook doorgeeft als je de macro aanroept), wordt het vervangen door die waarde, maar Pos, omdat het geen macro is, blijft het gewoon Pos. U krijgt dus uw variabelenaam samengevoegd met het woord Pos.

Merk op dat je dat niet in een lus met variabelenamen in een array kunt gebruiken - simpelweg omdat variabelenamen alleen voorkomen in de broncode, niet in de gecompileerde code, dus je kunt niets doen met die variabelenamen als de code eenmaal is gecompileerd. Daarom moet u de preprocessor gebruiken om het werk te doen.

Ja, het betekent dat je nog steeds 120 regels code moet schrijven voor alle 120 variabelen, maar ze worden gewoon ingekort tot readEE (varname); .

Een betere oplossing is echter om de struct-methode van Mikael te gebruiken of om gewoon een array te gebruiken en anders over het concept van namen na te denken:

uint8_t data[120];
for (int i = 0; i < 120; i++) {
    data[i] = readEEPROM(AT24C32_ADDRESS, 1, i);
);

Dus nu staan ​​al uw variabelewaarden in de array data [] , en u moet in uw programma weten welke waarde dat is - en u kunt dat doen door namen voor elke positie als preprocessor te definiëren macro's:

#define FAN_SPEED 12
#define N1_TOGGLE 95
#define LEDS_TOGGLE 7

Gebruik vervolgens die macro's in plaats van de cijfers:

Serial.println(data[FAN_SPEED]);

Als alternatief kunt u de macro's gebruiken om namen van variabelen te "maskeren":

#define fanSpeed data[12]
#define n1Toggle data[95]
#define ledsToggle data[7]

Er is echter één ding dat je misschien hebt opgemerkt: niets hier verkort je code, het verplaatst gewoon de zaken een beetje. Laten we eerlijk zijn - je hebt 120 variabelen opgeslagen op 120 locaties. Wat je ook doet, je zult nog steeds 120 wijzers van een bepaalde vorm moeten hebben voor die variabelen en hun locaties. Het enige dat u echt kunt doen, is de methode kiezen die de meeste leesbaarheid biedt, zodat iemand anders die naar uw code kijkt begrijpt wat er aan de hand is. Wat je ook doet, je hebt een lange lijst met variabelen of variabelenamen om te definiëren of in te stellen, wat veel typen betekent.

3
toegevoegd
Heel erg bedankt voor het beknopte overzicht van "grote foto's". Ik hield ervan om over alle methoden te leren. Ik denk dat mijn eerste poging zal zijn met de preprocessor-macro, want dat verkort/vereenvoudigt de code (wat mijn belangrijkste doel was), zonder de manier te veranderen waarop de variabelen worden geschreven of genoemd. Ik zou honderden regels code moeten wijzigen als ik de manier waarop de variabelen zijn opgeslagen veranderde, waarmee ik zou kunnen experimenteren als ik in de toekomst tijd/ambitie heb.
toegevoegd de auteur Alex Rigos, de bron
Ik heb zojuist de preprocessor-oplossing aan mijn code toegevoegd en het werkte probleemloos zonder problemen. Het was echt een heel ideale oplossing voor het probleem. Bedankt.
toegevoegd de auteur Alex Rigos, de bron
De preprocessor-oplossing is echt leuk - dacht daar niet aan :).
toegevoegd de auteur Mikael Patel, de bron
variableNames[i] = readEE(variableNames[i] + 'Pos');

Is dit mogelijk met C ++/Arduino?

Nee! Er zijn maar weinig programmeertalen toegestaan, omdat er veel runtime-informatie voor nodig is.

Laten we in plaats daarvan terugkomen op uw probleem; Laad een groot aantal variabelen van EEPROM . Welke mechanismen hebben we in de C/C ++ - en AVR-bibliotheek die hierbij kunnen helpen?

Hier is een heel eenvoudige oplossing die resulteert in een "one-liner"; eeprom_read_block ().

struct var_t {
  byte fanSpeed, nl1Toggle, ledsToggle;
};
var_t var;
const void* pos = ...;
eeprom_read_block(&var, pos, sizeof(var));

Het is duidelijk dat var_t en var geen erg goede namen zijn (en je zult met iets beters moeten komen) en dit is voor de interne EEPROM maar dezelfde techniek kan worden gebruikt voor de I2C EEPROM.

Proost!

BW: Welke AT24CXXX-bibliotheek gebruikt u? Omdat dit er vreemd uitziet.

 uint8_t readEE(uint8_t entry) {
   readEEPROM(AT24C32_ADDRESS, 1, entry);
 }

Geen retourverklaring, etc.

3
toegevoegd
Dankje voor het antwoord! Dit spul is een beetje te complex voor mij, dus ik moet nog wat studeren voordat het duidelijker wordt (zelfde voor de opmerking van @Nick Gammon, waar ik meer over moet leren). De AT24CXXX staat op een DS3231 RTC-kaart en ik denk dat ik door een aantal van de minder voorkomende DS3231-bibliotheken moest zoeken om er een te vinden die zou werken met de Due (het was gemakkelijk om degenen te vinden die met de ATmegas werkten). De code die ik heb gebruikt, bevindt zich hier: github.com/kriswiner/DS3231RTC . Ik denk dat ik nog wat aanpassingen moest aanbrengen om het op de Due te laten werken, maar ik weet het niet precies meer.
toegevoegd de auteur Alex Rigos, de bron