Dump obsahu premennej na sériový port

Zápisník experimentátora

Hierarchy: Ladenie programu v C++

Pretože Arduino IDE nepodporuje debuggovanie mikrokontroléra, máme trochu sťaženú úlohu. Obvykle si môžeme posielať iba ladiace výpisy cez sériový port. Každý si na to navrhuje nejakú formu výpisu, ale priznajme si otvorene, je to pracné. V tomto článku si predstavíme riešenie, ktoré značnú časť problémov vyrieši za nás.

Program

Zakladom je jedna šablónová funkcia a dve makrá. Funkcia sa volá dumpHex a slúži na to, aby nám na sériový port poslala obsah pamäte, ktorú zaberá konkrétna premenná. Šablónový parameter T je použitý preto, aby sme si mohli funkciou sizeof vypočítať veľkosť pamäte, ktorú zaberá premenná. Funkcia sa vyhodnotí počas prekladu a jej výsledok bude v premennej mySize.

Funkcia dumpHex sa ale nevolá priamo, ale ju používame pomocou makier. Prečo? Pretože makropríkazy jazyka C++ nám umožňujú urobiť malý trik, ktorý sa nám pri ladení hodí. Pozrite si kód makier DUMPVAL a DUMP. Nájdete tam riadok Serial.print(#var);. Ak v makre použijeme parameter makra spolu so znakom #, kompilátor vytvorí textový reťazec s názvom parametra. A vypísanie tohoto reťazca na sériový port nám dodá názov funkcie. Všimnite si, že je to použiteľné aj napríklad na premennú v štruktúre.

Makro DUMPVAL je použiteľné iba na typy premenných, ktoré pozná funkcia print. Pre všetky ostatné sa musí použiť iba makro DUMP.

template< typename T > void dumpHex(T &t) {
  int       theValue;
  char      textString[16];
  char      asciiDump[16];
  const uint8_t *myAddressPointer = (uint8_t*) &t;
  int mySize = sizeof(t);
  int maxrow;

  while (mySize > 0) {
    maxrow = min(16, mySize);
    sprintf(textString, "%04X - ", myAddressPointer);
    Serial.print(textString);
    for (int ii = 0; ii < maxrow; ii++) {
      theValue  = *myAddressPointer;
      sprintf(textString, "%02X ", theValue);
      Serial.print(textString);
      if ((theValue >= 0x20) && (theValue < 0x7f))
        asciiDump[ii]  = theValue;
      else
        asciiDump[ii]  = '.';
      myAddressPointer++;
    }
    asciiDump[maxrow] = 0;
    Serial.println(asciiDump);
    mySize -= maxrow;
  }
}

uint8_t sensorAdress[2][8] = {{ 0x28, 0xFF, 0x4E, 0xB8, 0x92, 0x15, 0x1, 0xA4 },
  { 0x28, 0xFF, 0x42, 0xB8, 0x92, 0x15, 0x1, 0x85 },
};

int abc=123;
double xyz=1.;
long qwe=4456789L;
const char mytext[]="ja som text 01234567890123456789";
uint8_t ttt='t';

struct demo {
  int x;
  int y;
  double z;
};

demo strdemo = {1,2,3.2};

#define DUMPVAL(var)     \
 {                       \ 
 Serial.print("Dump: "); \
 Serial.print(#var);     \
 Serial.print("=");      \
 Serial.println(var);    \
 dumpHex(var);           \
 }

#define DUMP(var)        \
 {                       \ 
 Serial.print("Dump: "); \
 Serial.println(#var);   \
 dumpHex(var);           \
 }

void setup() {
  Serial.begin(9600);
  DUMPVAL(abc);
  DUMPVAL(xyz);
  DUMPVAL(qwe);
  DUMP(sensorAdress);
  DUMPVAL(mytext);
  DUMPVAL(ttt);
  DUMP(strdemo);
  DUMPVAL(strdemo.x);
  DUMPVAL(strdemo.y);
  DUMPVAL(strdemo.z);

  for(int i=0;i<3;i++)
    DUMPVAL(i); 
}

void loop() {
}

Výstup z programu

Predchádzajúci program vygeneruje nasledovný výstup. V prehľadnej podobe dostanete obsah danej premennej a jej hexadecimálny výpis v pamäti.

Všimnite si, že mikrokontrolér ATmega328P dáva globálne premenné od adresy 0x0100, zatiaľ čo lokálne premenné vo funkcii, ktoré sa vytvárajú v zásobniku, sú zase na opačnom konci RAM.

Dump: abc=123
0121 - 7B 00 {.
Dump: xyz=1.00
011D - 00 00 80 3F ...?
Dump: qwe=4456789
0119 - 55 01 44 00 U.D.
Dump: sensorAdress
0109 - 28 FF 4E B8 92 15 01 A4 28 FF 42 B8 92 15 01 85 (.N.....(.B.....
Dump: mytext=ja som text 01234567890123456789
0133 - 6A 61 20 73 6F 6D 20 74 65 78 74 20 30 31 32 33 ja som text 0123
0143 - 34 35 36 37 38 39 30 31 32 33 34 35 36 37 38 39 4567890123456789
0153 - 00 .
Dump: ttt=116
0108 - 74 t
Dump: strdemo
0100 - 01 00 02 00 CD CC 4C 40 ......L@
Dump: strdemo.x=1
0100 - 01 00 ..
Dump: strdemo.y=2
0102 - 02 00 ..
Dump: strdemo.z=3.20
0104 - CD CC 4C 40 ..L@
Dump: i=0
08D9 - 00 00 ..
Dump: i=1
08D9 - 01 00 ..
Dump: i=2
08D9 - 02 00 ..

Zdrojový kód

Zdrojový kód si môžete stiahnuť na GitHub.


24.10.2016


Menu