Metinleri Değişken Adlara Ekleme: Lütfen Bu Kodu Kısaltın Bana Yardım Edin

Aşağıdaki "kurulum" altındaki kodu kısaltmaya çalışıyorum, ki burada harici bir EEPROM'dan okunan 120'den fazla değişken var. EEPROM adresinin konumunu saklayan değişkenin, doldurulmakta olan değişkenin adı ve "Pos" kelimesi olduğu bir desen vardır.

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);
}

İdeal olarak bunun gibi çalışmasını isterim (nasıl yapılacağını bilmediğim için sözde kod kullanıyorum):

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');
  }

Bu C ++/Arduino kullanarak mümkün mü?

1
EEPROM değişkenini RAM'e (ör. Bir karakter dizisine) kopyalayın. Ardından, kelimenizi sonuna eklemek için strcat 'ı kullanın. Bitmiş sözcükler için yeterli alana ve sonlandırıcı 0x00 baytına izin verin.
katma yazar Nick Gammon, kaynak

2 cevap

Bu basit bir ön işlemci makrosu ile elde edilebilir:

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

Daha sonra kullanabilirsiniz:

readEE(foo);

ve genişletilecek:

foo = readEEPROM(AT24C32_ADDRESS, 1, fooPos);

Makrolardaki ## operatörü, her iki tarafı da genişletir (VAR ve Pos) ve ardından sonuçları birlikte birleştirir. VAR'ın kendisi bir makro olduğu için (makroyu çağırdığınızda geçtiğiniz her ne olursa olsun) o değerle değiştirilir, ancak Pos, makro olmadığından sadece Pos olarak kalır. Yani, Pos ismiyle birleştirilmiş değişken isminiz ile sonuçlanırsınız.

Bir dizide değişken isimleri olan bir döngüde kullanamayacağınızı unutmayın - sadece değişken isimleri kaynak kodunda değil, derlenmiş kodda yer aldığından, koddan sonra bu değişken adlarıyla hiçbir şey yapamazsınız. derlenmiş. Bu nedenle işi yapmak için önişlemci kullanmanız gerekir.

Evet, bu, tüm 120 değişken için 120 satırlık kod yazmanız gerektiği anlamına gelir, ancak readEE (varname); ile kısaltılmıştır.

Ancak daha iyi bir çözüm, ya Mikael'in struct yöntemini kullanmak, ya da sadece bir dizi kullanmak ve isimler kavramı hakkında farklı düşünmek:

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

Yani şimdi tüm değişken değerleriniz data [] dizgesindedir ve programınızda hangi değerin hangisinin olduğunu bilmek zorundasınız - ve bunu ön işlemci olarak her pozisyon için isimleri tanımlayarak yapabilirsiniz. makrolar:

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

Sonra bu makroları sayıların yerine kullanın:

Serial.println(data[FAN_SPEED]);

Alternatif olarak, değişken isimleri "maskelemek" için makroları kullanabilirsiniz:

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

Yine de fark edebileceğiniz bir şey var: Burada hiçbir şey kodunuzu kısaltmaz, sadece bir şeyleri biraz hareket ettirir. Yüzleşelim - 120 yerde saklanan 120 değişken var. Ne yaparsanız yapın, yine de, bu değişkenlere ve konumlarına 120 formluk bir form vermeniz gerekecektir. Gerçekten yapabileceğiniz tek şey, en okunabilirliği sağlayan yöntemi seçmektir, böylece kodunuza bakacak başka biri, neler olup bittiğini anlayabilir. Ne yaparsanız yapın, tanımlamak veya kurmak için uzun bir değişkenler listesi veya değişken isimleriniz vardır, bu da çok fazla yazım anlamına gelir.

3
katma
Özlü "büyük resim" genel bakış için çok teşekkürler. Tüm yöntemleri öğrenmeyi çok severdim. İlk denemem önişlemci makrosu ile olacak sanırım, çünkü bu, değişkenlerin yazıldığı ya da adlandırıldığı şekli değiştirmeden, kodu (temel amacım olan) kısaltır/basitleştirir. Değişkenlerin saklanma şeklini değiştirirsem yüzlerce satır kod değiştirmem gerekirdi, eğer gelecekte zamanım/hırsım varsa deneyebilirim.
katma yazar Alex Rigos, kaynak
Önişlemci çözümümü koduma ekledim ve bir aksama olmadan güzelce çalıştı. Problem için gerçekten çok ideal bir çözümdü. Teşekkürler.
katma yazar Alex Rigos, kaynak
Önişlemci çözümü gerçekten güzel - bunu düşünmedim :).
katma yazar Mikael Patel, kaynak
variableNames[i] = readEE(variableNames[i] + 'Pos');

Bu, C ++/Arduino kullanarak mümkün mü?

Yok hayır! Çok az programlama dili, çok fazla çalışma zamanı bilgisi gerektirdiğinden izin verir.

Bunun yerine sorununuzu tekrar gözden geçirelim; EEPROM 'dan büyük bir değişken kümesi yükleyin. Bu konuda yardımcı olabilecek C/C ++ ve AVR kütüphanesinde hangi mekanizmalara sahibiz?

İşte bir "tek liner" ile sonuçlanan gerçekten basit bir çözümdür; eeprom_read_block ().

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

Açıkçası var_t ve var çok iyi isimler değildir (ve daha iyi bir şey bulmanız gerekecektir) ve bu iç EEPROM için geçerlidir ancak aynı teknik aşağıdakiler için kullanılabilir. I2C EEPROM.

Şerefe!

BW: Hangi AT24CXXX kütüphanesini kullanıyorsunuz? Çünkü bu garip görünüyor.

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

İade beyanı, vb.

3
katma
Cevap için teşekkürler! Bu şey benim için biraz fazla karmaşık, bu yüzden biraz daha net hale gelmeden önce yapmaya çalışıyorum (@Nick Gammon'un yorumu için de aynı, daha fazla çalışmam gereken). AT24CXXX bir DS3231 RTC panosunda ve sanırım daha az yaygın olan DS3231 kütüphanelerini Due ile çalışacak birisini bulmak zorunda kaldım (ATmegas ile çalışanları bulmak kolaydı). Kullandığım kod şu adrestedir: github.com/kriswiner/DS3231RTC . Sanırım Due'da çalışmak için bazı değişiklikler yapmak zorunda kaldım, ama tam olarak hatırlamıyorum.
katma yazar Alex Rigos, kaynak