{"id":77536,"date":"2018-11-14T17:40:32","date_gmt":"2018-11-14T17:40:32","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=77536"},"modified":"2020-04-13T21:34:12","modified_gmt":"2020-04-13T21:34:12","slug":"software-debugger-arduino-ide-serialdebug-library","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/software-debugger-arduino-ide-serialdebug-library\/","title":{"rendered":"Better Debugging for Arduino IDE using Software Debugger (Part 2)"},"content":{"rendered":"<div style=\"padding: 10px; line-height: 1.2; text-align: center; background-color: #f5f5f5; margin-bottom: 10px;\">This tutorial was written by Jo\u00e3o Lopes and edited by Sara Santos.<\/div>\n<p>The SerialDebug library created by Jo\u00e3o Lopes allows you to improve debugging for the Arduino IDE. In this article he\u2019ll show you how to use the simple software debugger of the <a href=\"https:\/\/github.com\/JoaoLopesF\/SerialDebug\" target=\"_blank\" rel=\"noopener noreferrer\">SerialDebug library<\/a> that has most functionalities of an hardware debugger.<\/p>\n<p><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" class=\"aligncenter size-full wp-image-77571\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/Serial-debug-software-arduino-ide.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"1200\" height=\"675\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/Serial-debug-software-arduino-ide.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/Serial-debug-software-arduino-ide.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/Serial-debug-software-arduino-ide.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/Serial-debug-software-arduino-ide.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/p>\n<p>This is part 2 of a series of articles about the SerialDebug library. You can check all the articles on the links below.<\/p>\n<ul>\n<li><a href=\"https:\/\/randomnerdtutorials.com\/serialdebug-library-arduino-ide\/\">Part 1 &#8211; Using debug with levels<\/a><\/li>\n<li>Part 2 &#8211; Simple Software Debugger (currently reading)<\/li>\n<li><a href=\"https:\/\/randomnerdtutorials.com\/serialdebugapp-arduino-ide-serialdebug-library\/\">Part 3 &#8211; SerialDebugApp<\/a><\/li>\n<\/ul>\n<h2>Simple Software Debugger<\/h2>\n<p>When I (Jo\u00e3o) was developing in ESP-IDF (ESP32 native SDK), I used an hardware debugger, using external hardware compatible with JTAG, GDB server and Eclipse CDT. This is a great solution for debugging because I can see the value of variables, set breakpoints (up to 2 for ESP32), run code step by step, and more.<\/p>\n<p>However, until now Arduino IDE doesn\u2019t support hardware debugger. If you\u2019d like to use hardware debugger, you need:<\/p>\n<ul>\n<li>An external hardware (JTAG, Atmel-Ice, etc)<\/li>\n<li>Another IDE (Eclipse, Atmel studio, etc)<\/li>\n<li>Skills to configure and use it<\/li>\n<\/ul>\n<p>There are simpler solutions, but these are not free, like the MicroStudio. That\u2019s why there are such few people using debugger in Arduino IDE. Most of all debugging in Arduino IDE is done with <em>Serial.prin<\/em>t commands.<\/p>\n<p>When I was developing SerialDebug library, I thought how to bring some hardware debugger features to Arduino without the need for extra hardware and skills. The SerialDebug library has a simple software debugger. Let\u2019s take a closer look at its features:<\/p>\n<ul>\n<li><strong>Simple:<\/strong> It&#8217;s a simple, but functional debugger. It doesn\u2019t have all features of a real hardware debugger (like the ability to run code step by step).<\/li>\n<li><strong>Software:<\/strong> It&#8217;s implemented in software, not in hardware as a real hardware debugger. But it is optimized to reduce memory and overhead of processing. For this reason, this feature in SerialDebug library starts disabled until receiving the command &#8220;dbg&#8221;.<\/li>\n<li><strong>Debugger:<\/strong> It is a debugger, you can send commands in the Serial Monitor such as:\n<ul>\n<li>Call a function (works if debugger is enabled or disabled)<\/li>\n<li>Show and change values of global variables (works only if debugger is enabled)<\/li>\n<li>Add or change watches for global variables (works only if debugger is enabled)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong>Note:<\/strong> due to&nbsp;program memory limitations, the simple software debugger doesn\u2019t run in low memory boards such as Arduino Uno. But you can try the debugger with this board by disabling DEBUG_MINIMUM mode, just comment line 64 of <em>SerialDebug.h<\/em>.<\/p>\n<h2>How to use Simple Software Debugger<\/h2>\n<p>First, follow the steps in <a href=\"https:\/\/randomnerdtutorials.com\/serialdebug-library-arduino-ide\/\">Part 1 of this series<\/a> to install SerialDebug library. Then, open the advanced example. In the <strong>File<\/strong> menu, select <strong>Examples<\/strong> &gt; <strong>SerialDebug<\/strong> &gt; <strong>SerialDebug_Advanced<\/strong>.<\/p>\n<p>Then select <strong>Avr<\/strong> for Arduino with AVR arch, like Uno, Leonardo and Mega. Or <strong>Others<\/strong> for Arduino as Due, MKR, Teensy, Esp8266 and Esp32.&nbsp;For this post, we use ESP32 board and the example in the &#8220;Others&#8221; directory.<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter size-full wp-image-77537\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-advanced-example.png?resize=941%2C680&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"941\" height=\"680\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-advanced-example.png?w=941&amp;quality=100&amp;strip=all&amp;ssl=1 941w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-advanced-example.png?resize=300%2C217&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-advanced-example.png?resize=768%2C555&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 941px) 100vw, 941px\" \/><\/p>\n<p>The following code should open:<\/p>\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/\/\/\/\/\/\/\/\n\/\/ Libraries Arduino\n\/\/\n\/\/ Library: SerialDebug - Improved serial debugging to Arduino, with simple software debugger\n\/\/ Author: Joao Lopes\n\/\/\n\/\/ Example to show how to use it.\n\/\/\n\/\/ Example of use:\n\/\/\n\/\/   print macros:\n\/\/\n\/\/\t\tprintA(F(&quot;This is a always - var &quot;));\n\/\/\t\tprintlnA(var);\n\/\/\t\tprintV(F(&quot;This is a verbose - var &quot;));\n\/\/\t\tprintlnV(var);\n\/\/\t\tprintD(F(&quot;This is a debug - var &quot;));\n\/\/\t\tprintlnD(var);\n\/\/\t\tprintI(F(&quot;This is a information - var &quot;));\n\/\/\t\tprintlnI(var);\n\/\/\t\tprintW(F(&quot;This is a warning - var &quot;));\n\/\/\t\tprintlnW(var);\n\/\/\t\tprintE(F(&quot;This is a error - var &quot;));\n\/\/\t\tprintlnE(var);\n\/\/\n\/\/\t\tprintlnV(&quot;This not have args&quot;);\n\/\/\n\/\/ \tdebug macros (printf formatting):\n\/\/\n\/\/\t\tdebugA(&quot;This is a always - var %d&quot;, var);\n\/\/\n\/\/\t\tdebugV(&quot;This is a verbose - var %d&quot;, var);\n\/\/\t\tdebugD(&quot;This is a debug - var %d&quot;, var);\n\/\/\t\tdebugI(&quot;This is a information - var %d&quot;, var);\n\/\/\t\tdebugW(&quot;This is a warning - var %d&quot;, var);\n\/\/\t\tdebugE(&quot;This is a error - var %d&quot;, var);\n\/\/\n\/\/\t\tdebugV(&quot;This not have args&quot;);\n\/\/\n\/\/\/\/\/\/\/\n\n\/\/\/\/\/\/\/\n\/\/ Note: this version is for Espressif or ARM boards,\n\/\/       Not using F() to reduce memory,\n\/\/       due these boards have memory a lot,\n\/\/\t     and RAM memory is much faster than Flash memory\n\/\/       If want or need, please open the example in Directory Avr.\n\/\/\/\/\/\/\/\n\n\/\/\/\/\/\/ Includes\n\n#include &quot;Arduino.h&quot;\n\n\/\/ SerialDebug Library\n\n\/\/ Disable all debug ? Good to release builds (production)\n\/\/ as nothing of SerialDebug is compiled, zero overhead :-)\n\/\/ For it just uncomment the DEBUG_DISABLED\n\/\/#define DEBUG_DISABLED true\n\n\/\/ Disable SerialDebug debugger ? No more commands and features as functions and globals\n\/\/ Uncomment this to disable it \n\/\/#define DEBUG_DISABLE_DEBUGGER true\n\n\/\/ Debug TAG ?\n\/\/ Usefull with debug any modules\n\/\/ For it, each module must have a TAG variable:\n\/\/ \t\tconst char* TAG = &quot;...&quot;;\n\/\/ Uncomment this to enable it\n\/\/#define DEBUG_USE_TAG true\n\n\/\/ Define the initial debug level here (uncomment to do it)\n\/\/ #define DEBUG_INITIAL_LEVEL DEBUG_LEVEL_VERBOSE\n\n\/\/ Force debug messages to can use flash ) ?\n\/\/ Disable native Serial.printf (if have)\n\/\/ Good for low memory, due use flash, but more slow and not use macros\n\/\/#define DEBUG_USE_FLASH_F true\n\n\/\/ Include SerialDebug\n\n#include &quot;SerialDebug.h&quot; \/\/https:\/\/github.com\/JoaoLopesF\/SerialDebug\n\n#ifdef BOARD_LOW_MEMORY\n\t#error &quot;This is not for low memoy boards, please use the basic example&quot;\n\t\/\/ If this error occurs, your board is a low memory board,\n\t\/\/ and for this, the default is mininum mode,\n\t\/\/ to especially to reduce program memory (flash)\n\t\/\/ You can do it:\n\t\/\/ - Open the basic example, or\n    \/\/ - Open Advanced\/Avr example (this uses F() to reduce RAM usage),\n    \/\/   and before, comment the DEBUG_MININUM in SerialDebug.h - line 64\n#endif\n\n\/\/\/\/\/\/ Variables\n\n\/\/ Time\n\nuint8_t mRunSeconds = 0;\nuint8_t mRunMinutes = 0;\nuint8_t mRunHours = 0;\n\n\/\/ Buildin Led ON ?\n\n#ifndef LED_BUILTIN \/\/ For compatibility\n\t#ifdef BUILTIN_LED\n\t\t#define LED_BUILTIN BUILTIN_LED\n\t#else\n\t\t#define LED_BUILTIN 2\n\t#endif\n#endif\n\nboolean mLedON = false;\n\n\/\/ Globals for this example\n\nboolean mBoolean = false;\nchar mChar = 'X';\nbyte mByte = 'Y';\nint mInt = 1;\nunsigned int mUInt = 2;\nlong mLong = 3;\nunsigned long mULong = 4;\nfloat mFloat = 5.0f;\ndouble mDouble = 6.0;\n\nString mString = &quot;This is a string&quot;;\nString mStringLarge = &quot;This is a large stringggggggggggggggggggggggggggggggggggggggggggggg&quot;;\n\nchar mCharArray[] = &quot;This is a char array&quot;;\nchar mCharArrayLarge[] = &quot;This is a large char arrayyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy&quot;;\n\nint mIntArray[5] = {1 ,2 ,3, 4, 5};\n\n\/\/const char mCharArrayConst[] = &quot;This is const&quot;;\n\n\/\/\/\/\/\/ Setup\n\nvoid setup() {\n\n    \/\/ Initialize the Serial\n\n    Serial.begin(250000); \/\/ Can change it to 115200, if you want use debugIsr* macros\n\n    delay(500); \/\/ Wait a time\n\n  \t\/\/ Debug\n\n\t\/\/ Attention:\n    \/\/ SerialDebug starts disabled and it only is enabled if have data avaliable in Serial\n    \/\/ Good to reduce overheads.\n\t\/\/ if You want debug, just press any key and enter in monitor serial\n\n    \/\/ Note: all debug in setup must be debugA (always), due it is disabled now.\n\n    Serial.println(); \/\/ To not stay in end of dirty chars in boot\n\n    debugA(&quot;**** Setup: initializing ...&quot;);\n\n    \/\/ Buildin led\n\n    pinMode(LED_BUILTIN, OUTPUT);\n    digitalWrite(LED_BUILTIN, LOW);\n\n    \/\/ WiFi connection, etc ....\n\n    \/\/ ...\n\n#ifndef DEBUG_DISABLE_DEBUGGER\n\n    \/\/ Add Functions and global variables to SerialDebug\n\n    \/\/ Notes: descriptions is optionals\n\n    \/\/ Add functions that can called from SerialDebug\n\n    if (debugAddFunctionVoid(&quot;benchInt&quot;, &amp;benchInt) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To run a benchmark of integers&quot;);\n    }\n    if (debugAddFunctionVoid(&quot;benchFloat&quot;, &amp;benchFloat) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To run a benchmark of float&quot;);\n    }\n    if (debugAddFunctionVoid(&quot;benchGpio&quot;, &amp;benchGpio) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To run a benchmark of Gpio operations&quot;);\n    }\n    if (debugAddFunctionVoid(&quot;benchAll&quot;, &amp;benchAll) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To run all benchmarks&quot;);\n    }\n\n    if (debugAddFunctionVoid(&quot;benchSerialPrints&quot;, &amp;benchSerialPrint) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To benchmarks standard Serial debug&quot;);\n    }\n    if (debugAddFunctionVoid(&quot;benchSerialDebug&quot;, &amp;benchSerialDebug) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To benchmarks SerialDebug&quot;);\n    }\n    if (debugAddFunctionVoid(&quot;benchSerialDbgPr&quot;, &amp;benchSerialDbgPr) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To benchmarks SerialDebug print macros&quot;);\n    }\n    if (debugAddFunctionVoid(&quot;benchSerialAll&quot;, &amp;benchSerialAll) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To benchmarks all Serial&quot;);\n    }\n\n    if (debugAddFunctionStr(&quot;funcArgStr&quot;, &amp;funcArgStr) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To run with String arg&quot;);\n    }\n    if (debugAddFunctionChar(&quot;funcArgChar&quot;, &amp;funcArgChar) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To run with Character arg&quot;);\n    }\n    if (debugAddFunctionInt(&quot;funcArgInt&quot;, &amp;funcArgInt) &gt;= 0) {\n    \tdebugSetLastFunctionDescription(&quot;To run with Integer arg&quot;);\n    }\n\n    \/\/ Add global variables that can showed\/changed from SerialDebug\n    \/\/ Note: Only global, if pass local for SerialDebug, can be dangerous\n\n    if (debugAddGlobalUInt8_t(&quot;mRunSeconds&quot;, &amp;mRunSeconds) &gt;= 0) {\n    \tdebugSetLastGlobalDescription(&quot;Seconds of run time&quot;);\n    }\n    if (debugAddGlobalUInt8_t(&quot;mRunMinutes&quot;, &amp;mRunMinutes) &gt;= 0) {\n    \tdebugSetLastGlobalDescription(&quot;Minutes of run time&quot;);\n    }\n    if (debugAddGlobalUInt8_t(&quot;mRunHours&quot;, &amp;mRunHours) &gt;= 0) {\n    \tdebugSetLastGlobalDescription(&quot;Hours of run time&quot;);\n    }\n\n    \/\/ Note: easy way, no descriptions ....\n\n    debugAddGlobalBoolean(&quot;mBoolean&quot;, \t&amp;mBoolean);\n    debugAddGlobalChar(&quot;mChar&quot;, \t\t&amp;mChar);\n    debugAddGlobalByte(&quot;mByte&quot;, \t\t&amp;mByte);\n    debugAddGlobalInt(&quot;mInt&quot;, \t\t\t&amp;mInt);\n    debugAddGlobalUInt(&quot;mUInt&quot;, \t\t&amp;mUInt);\n    debugAddGlobalLong(&quot;mLong&quot;, \t\t&amp;mLong);\n    debugAddGlobalULong(&quot;mULong&quot;, \t\t&amp;mULong);\n    debugAddGlobalFloat(&quot;mFloat&quot;, \t\t&amp;mFloat);\n    debugAddGlobalDouble(&quot;mDouble&quot;, \t&amp;mDouble);\n\n    debugAddGlobalString(&quot;mString&quot;, \t&amp;mString);\n\n    \/\/ Note: For char arrays, not use the '&amp;'\n\n    debugAddGlobalCharArray(&quot;mCharArray&quot;, mCharArray);\n\n    \/\/ Note, here inform to show only 20 characteres of this string or char array\n\n    debugAddGlobalString(&quot;mStringLarge&quot;, &amp;mStringLarge, 20);\n\n    debugAddGlobalCharArray(&quot;mCharArrayLarge&quot;,\n    \t\t\t\t\t\t\t\t\tmCharArrayLarge, 20);\n\n    \/\/ For arrays, need add for each item (not use loop for it, due the name can not by a variable)\n    \/\/ Notes: Is good added arrays in last order, to help see another variables\n    \/\/        In next versions, we can have a helper to do it in one command\n\n\tdebugAddGlobalInt(&quot;mIntArray[0]&quot;, \t&amp;mIntArray[0]);\n\tdebugAddGlobalInt(&quot;mIntArray[1]&quot;, \t&amp;mIntArray[1]);\n\tdebugAddGlobalInt(&quot;mIntArray[2]&quot;, \t&amp;mIntArray[2]);\n\tdebugAddGlobalInt(&quot;mIntArray[3]&quot;,\t&amp;mIntArray[3]);\n\tdebugAddGlobalInt(&quot;mIntArray[4]&quot;,\t&amp;mIntArray[4]);\n\n    \/\/ Add watches for some global variables\n    \/\/ Note: watches can be added\/changed in serial monitor too\n\n\t\/\/ Watch -&gt; mBoolean when changed (put 0 on value)\n\n\tdebugAddWatchBoolean(&quot;mBoolean&quot;, DEBUG_WATCH_CHANGED, 0);\n\n\t\/\/ Watch -&gt; mRunSeconds == 10\n\n\tdebugAddWatchUInt8_t(&quot;mRunSeconds&quot;, DEBUG_WATCH_EQUAL, 10);\n\n\t\/\/ Watch -&gt; mRunMinutes &gt; 3\n\n\tdebugAddWatchUInt8_t(&quot;mRunMinutes&quot;, DEBUG_WATCH_GREAT, 3);\n\n\t\/\/ Watch -&gt; mRunMinutes == mRunSeconds (just for test)\n\n\tdebugAddWatchCross(&quot;mRunMinutes&quot;, DEBUG_WATCH_EQUAL, &quot;mRunSeconds&quot;);\n\n#endif \/\/ DEBUG_DISABLE_DEBUGGER\n\n    \/\/ End\n\n    debugA(&quot;**** Setup: initialized.&quot;);\n\n}\n\n\/\/\/\/\/\/ Loop\n\nvoid loop()\n{\n\t\/\/ SerialDebug handle\n\t\/\/ NOTE: if in inactive mode (until receive anything from serial),\n\t\/\/ it show only messages of always or errors level type\n\t\/\/ And the overhead during inactive mode is very much low\n\n\tdebugHandle();\n\n\t\/\/ Blink the led\n\n\tmLedON = !mLedON;\n\tdigitalWrite(LED_BUILTIN, (mLedON)?LOW:HIGH);\n\n\t\/\/ Debug the time (verbose level)\n\n\tdebugV(&quot;* Run time: %02u:%02u:%02u (VERBOSE)&quot;, mRunHours, mRunMinutes, mRunSeconds);\n\n\tif (mRunSeconds % 5 == 0) { \/\/ Each 5 seconds\n\n\t\t\/\/ Debug levels\n\n\t\tdebugV(&quot;* This is a message of debug level VERBOSE&quot;);\n\t\tdebugD(&quot;* This is a message of debug level DEBUG&quot;);\n\t\tdebugI(&quot;* This is a message of debug level INFO&quot;);\n\t\tdebugW(&quot;* This is a message of debug level WARNING&quot;);\n\n\t\tif (mRunSeconds == 55) { \/\/ Just for not show initially\n\t\t\tdebugE(&quot;* This is a message of debug level ERROR&quot;);\n\t\t}\n\n\t\tmBoolean = (mRunSeconds == 30); \/\/ Just to trigger the watch\n\n\t\t\/\/ Functions example to show auto function name feature\n\n\t\tfoo();\n\n\t\tbar();\n\n\t\t\/\/ Example of float formatting:\n\n\t\tmFloat += 0.01f;\n\n#ifndef ARDUINO_ARCH_AVR \/\/ Native float printf support\n\t\tdebugV(&quot;mFloat = %.3f&quot;, mFloat);\n#else \/\/ For AVR, it is not supported, using String instead\n\t\tdebugV(&quot;mFloat = %s&quot;, String(mFloat).c_str());\n#endif\n\n\t}\n\n\t\/\/ Count run time (just a test - for real suggest the TimeLib and NTP, if board have WiFi)\n\n\tmRunSeconds++;\n\n\tif (mRunSeconds == 60) {\n\t\tmRunMinutes++;\n\t\tmRunSeconds = 0;\n\t}\n\tif (mRunMinutes == 60) {\n\t\tmRunHours++;\n\t\tmRunMinutes = 0;\n\t}\n\tif (mRunHours == 24) {\n\t\tmRunHours = 0;\n\t}\n\n\t\/\/ Delay of 1 second\n\n\tdelay(1000);\n}\n\n\n\/\/ Functions example to show auto function name feature\n\nvoid foo() {\n\n  uint8_t var = 1;\n\n  debugV(&quot;This is a debug - var %u&quot;, var);\n}\n\nvoid bar() {\n\n  uint8_t var = 2;\n\n  debugD(&quot;This is a debug - var %u&quot;, var);\n}\n\n\/\/\/\/\/\/ Benchmarks - simple\n\n\/\/ Note: how it as called by SerialDebug, must be return type void and no args\n\/\/ Note: Flash F variables is not used during the tests, due it is slow to use in loops\n\n#define BENCHMARK_EXECS 10000\n\n\/\/ Simple benckmark of integers\n\nvoid benchInt() {\n\n\tint test = 0;\n\n\tfor (int i = 0; i &lt; BENCHMARK_EXECS; i++) {\n\n\t\t\/\/ Some integer operations\n\n\t\ttest++;\n\t\ttest += 2;\n\t\ttest -= 2;\n\t\ttest *= 2;\n\t\ttest \/= 2;\n\t}\n\n\t\/\/ Note: Debug always is used here\n\n\tdebugA(&quot;*** Benchmark of integers. %u exec.&quot;, BENCHMARK_EXECS);\n\n}\n\n\/\/ Simple benckmark of floats\n\nvoid benchFloat() {\n\n\tfloat test = 0;\n\n\tfor (int i = 0; i &lt; BENCHMARK_EXECS; i++) {\n\n\t\t\/\/ Some float operations\n\n\t\ttest++;\n\t\ttest += 2;\n\t\ttest -= 2;\n\t\ttest *= 2;\n\t\ttest \/= 2;\n\t}\n\n\t\/\/ Note: Debug always is used here\n\n\tdebugA(&quot;*** Benchmark of floats, %u exec.&quot;, BENCHMARK_EXECS);\n\n}\n\n\/\/ Simple benckmark of GPIO\n\nvoid benchGpio() {\n\n\/\/\tconst int execs = (BENCHMARK_EXECS \/ 10); \/\/ Reduce it\n\tconst int execs = BENCHMARK_EXECS;\n\n\tfor (int i = 0; i &lt; execs; i++) {\n\n\t\t\/\/ Some GPIO operations\n\n\t\tdigitalWrite(LED_BUILTIN, HIGH);\n\t\tdigitalRead(LED_BUILTIN);\n\t\tdigitalWrite(LED_BUILTIN, LOW);\n\n\t\tanalogRead(A0);\n\t\tanalogRead(A0);\n\t\tanalogRead(A0);\n\n\t}\n\n\t\/\/ Note: Debug always is used here\n\n\tdebugA(&quot;*** Benchmark of GPIO. %u exec.&quot;, execs);\n\n}\n\n\/\/ Run all benchmarks\n\nvoid benchAll() {\n\n\tbenchInt();\n\tbenchFloat();\n\tbenchGpio();\n\n\t\/\/ Note: Debug always is used here\n\n\tdebugA(&quot;*** All Benchmark done.&quot;);\n\n}\n\n\/\/ Serial benchmarks, to compare Serial.prints with SerialDebug\n\n#define BENCHMARK_SERIAL 25\n\nvoid benchSerialPrint() {\n\n\t\/\/ Note: Serial.printf is not used, due most Arduino not have this\n\t\/\/ Show same info to compare real speed\n\t\/\/ Same data size of SerialDebug to compare speeds of processing and not the time elapsed to send it\n\n\tunsigned long timeBegin = micros();\n\n\tfor (uint16_t i = 0; i &lt; BENCHMARK_SERIAL; i++) {\n\n\t\tSerial.print(&quot;(A &quot;);\n\t\tSerial.print(millis());\n\t\tSerial.print(&quot; benchSerialPrint&quot;);\n#ifdef ESP32\n\t\tSerial.print(&quot; C&quot;);\n\t\tSerial.print(xPortGetCoreID());\n#endif\n\t\tSerial.print(&quot;) Exec.: &quot;);\n\t\tSerial.print(i+1);\n\t\tSerial.print(&quot; of &quot;);\n\t\tSerial.println(BENCHMARK_SERIAL);\n\n\t}\n\n\tunsigned long elapsed = (micros() - timeBegin);\n\n\tSerial.print(&quot;*** Benchmark of Serial prints. Execs.: &quot;);\n\tSerial.print(BENCHMARK_SERIAL);\n\tSerial.print(&quot; time elapsed -&gt; &quot;);\n\tSerial.print(elapsed);\n\tSerial.println(&quot; us&quot;);\n\n}\n\nvoid benchSerialDebug() {\n\n\t\/\/ Notes: printf formats can be used,\n\t\/\/ even if Arduino not have this, this is done in internal debugPrintf\n\t\/\/ Debug always level is used here\n\n\tdebugShowProfiler(false, 0, false); \/\/ Disable the profiler during the test (the Serial.print not have it)\n\n\tunsigned long timeBegin = micros();\n\n\tfor (uint16_t i = 0; i &lt; BENCHMARK_SERIAL; i++) {\n\n\t\tdebugA(&quot;Exec.: %u of %u&quot;, (i+1), BENCHMARK_SERIAL);\n\n\t}\n\n\tunsigned long elapsed = (micros() - timeBegin);\n\n\t\/\/ Note not using SerialDebug macros below, to show equals that SerialPrints\n\n\tSerial.print(&quot;*** Benchmark of Serial debugA. Execs.: &quot;);\n\tSerial.print(BENCHMARK_SERIAL);\n\tSerial.print(&quot; time elapsed -&gt; &quot;);\n\tSerial.print(elapsed);\n\tSerial.println(&quot; us&quot;);\n\n\tdebugShowProfiler(true, 0, false); \/\/ Reenable\n\n}\n\nvoid benchSerialDbgPr() {\n\n\t\/\/ Using print macros to avoid printf\n\t\/\/ Same data size of SerialDebug to compare speeds of processing and not the time elapsed to send it\n\n\tdebugSetProfiler(false); \/\/ Disable it, due standard prints not have it\n\n\tunsigned long timeBegin = micros();\n\n\tfor (uint16_t i = 0; i &lt; BENCHMARK_SERIAL; i++) {\n\n\t\tprintA(&quot;Exec.: &quot;);\n\t\tprintA(i+1);\n\t\tprintA(&quot; of &quot;);\n\t\tprintlnA(BENCHMARK_SERIAL);\n\n\t}\n\n\tunsigned long elapsed = (micros() - timeBegin);\n\n\tdebugSetProfiler(true); \/\/ Restore\n\n\t\/\/ Note not using SerialDebug macros below, to show equals that SerialPrints\n\n\tSerial.print(&quot;*** Benchmark of Serial printA. Execs.: &quot;);\n\tSerial.print(BENCHMARK_SERIAL);\n\tSerial.print(&quot; time elapsed -&gt; &quot;);\n\tSerial.print(elapsed);\n\tSerial.println(&quot; us&quot;);\n\n}\n\nvoid benchSerialAll() {\n\n\tbenchSerialPrint();\n\n\tdelay(1000); \/\/ To give time to send any buffered\n\n\tbenchSerialDebug();\n\n\tdelay(1000); \/\/ To give time to send any buffered\n\n\tbenchSerialDbgPr();\n}\n\n\/\/ Example functions with argument (only 1) to call from serial monitor\n\/\/ Note others types is not yet available in this version of SerialDebug\n\nvoid funcArgStr (String str) {\n\n\tdebugA(&quot;*** called with arg.: %s&quot;, str.c_str());\n}\nvoid funcArgChar (char character) {\n\n\tdebugA(&quot;*** called with arg.: %c&quot;, character);\n}\nvoid funcArgInt (int number) {\n\n\tdebugA(&quot;*** called with arg.: %d&quot;, number);\n}\n\n\/\/\/\/\/\/\/\/\/\/\/ End\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/JoaoLopesF\/SerialDebug\/raw\/master\/Examples\/SerialDebug_advanced\/Others\/SerialDebug_advanced\/SerialDebug_advanced.ino\" target=\"_blank\">View raw code<\/a><\/p>\n<h3>Setup Codes for the Debugger<\/h3>\n<p>To call functions via Serial Monitor, or SerialDebugApp (<a href=\"https:\/\/randomnerdtutorials.com\/serialdebugapp-arduino-ide-serialdebug-library\/\">see it in Part 3<\/a>), you have to set the debugger in the <em>setup()<\/em> function of your sketch. For example:<\/p>\n<pre>\/\/ Add functions that can be called from SerialDebug\n\nif (debugAddFunctionVoid(\"benchInt\", &amp;benchInt) &gt;= 0) {\n  debugSetLastFunctionDescription(\"To run a benchmark of integers\");\n}\n\nif (debugAddFunctionVoid(\"benchFloat\", &amp;benchFloat) &gt;= 0) {\n  debugSetLastFunctionDescription(\"To run a benchmark of float\");\n}\n\nif (debugAddFunctionVoid(\"benchGpio\", &amp;benchGpio) &gt;= 0) {\n  debugSetLastFunctionDescription(\"To run a benchmark of Gpio operations\");\n}\n\nif (debugAddFunctionVoid(\"benchAll\", &amp;benchAll) &gt;= 0) {\n  debugSetLastFunctionDescription(\"To run all benchmarks\");\n}\n\nif (debugAddFunctionVoid(\"benchSerialPrints\", &amp;benchSerialPrint) &gt;= 0) {\n  debugSetLastFunctionDescription(\"To benchmarks standard Serial debug\");\n}\n\nif (debugAddFunctionVoid(\"benchSerialDebug\", &amp;benchSerialDebug) &gt;= 0) {\n  debugSetLastFunctionDescription(\"To benchmarks SerialDebug\");\n}\nif (debugAddFunctionVoid(\"benchSerialDbgPr\", &amp;benchSerialDbgPr) &gt;= 0) {\ndebugSetLastFunctionDescription(\"To benchmarks SerialDebug print macros\");\n}\n\nif (debugAddFunctionVoid(\"benchSerialAll\", &amp;benchSerialAll) &gt;= 0) {\n  debugSetLastFunctionDescription(\"To benchmarks all Serial\");\n}\n\nif (debugAddFunctionStr(\"funcArgStr\", &amp;funcArgStr) &gt;= 0) {\n  debugSetLastFunctionDescription(\"To run with String arg\");\n}\n\nif (debugAddFunctionChar(\"funcArgChar\", &amp;funcArgChar) &gt;= 0) {\n  debugSetLastFunctionDescription(\"To run with Character arg\");\n}\n\nif (debugAddFunctionInt(\"funcArgInt\", &amp;funcArgInt) &gt;= 0) {\n  debugSetLastFunctionDescription(\"To run with Integer arg\");\n}<\/pre>\n<p>You can set it in a shorter way with no descriptions:<\/p>\n<pre>debugAddFunctionVoid(\"benchInt\", &amp;benchInt);<\/pre>\n<p><strong>Note:<\/strong> in the current version, it only supports functions with the following requirements:<\/p>\n<ul>\n<li>Without any argument (void)<\/li>\n<li>Or one argument of type int, char or String<\/li>\n<\/ul>\n<p><strong>Tip:<\/strong>&nbsp;you can create a generic function with one argument for debugging purpose. Then, you can call that function and pass different arguments to test it.<\/p>\n<p>The previous code sets functions that can be called with an &#8220;<strong>f<\/strong>&#8221; command:<\/p>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" class=\"aligncenter size-full wp-image-77538\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-functions.png?resize=708%2C393&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"708\" height=\"393\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-functions.png?w=708&amp;quality=100&amp;strip=all&amp;ssl=1 708w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-functions.png?resize=300%2C167&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/><\/p>\n<p><strong>Note 1:<\/strong> command &#8220;<strong>f<\/strong>&#8221; without arguments lists all available functions.<\/p>\n<p><strong>Note 2:<\/strong> for this post, we use the ESP32 with the full features of SerialDebug, because it has enough memory.<\/p>\n<p>To call the first function, just type the command: <strong>f 1<\/strong><\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-77540\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/debugger-function-f1.png?resize=708%2C462&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"708\" height=\"462\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/debugger-function-f1.png?w=708&amp;quality=100&amp;strip=all&amp;ssl=1 708w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/debugger-function-f1.png?resize=300%2C196&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/><\/p>\n<p>To call a function that requires an argument, you can write a command as follows &#8220;<strong>f 11 123<\/strong>&#8220;. In this case, the function 11 has received the value 123 as argument.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-77541\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-function-arguments.png?resize=708%2C209&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"708\" height=\"209\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-function-arguments.png?w=708&amp;quality=100&amp;strip=all&amp;ssl=1 708w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-function-arguments.png?resize=300%2C89&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/><\/p>\n<h3>Show\/Change Global Variables Values<\/h3>\n<p>To use global variables in the debugger, you need to set them in the <em>setup()<\/em> function:<\/p>\n<pre>\/\/ Add global variables that can showed\/changed from SerialDebug\n\/\/ Note: Only global, if pass local for SerialDebug, can be dangerous\n\nif (debugAddGlobalUInt8_t(\"mRunSeconds\", &amp;mRunSeconds) &gt;= 0) {\n  debugSetLastGlobalDescription(\"Seconds of run time\");\n}\nif (debugAddGlobalUInt8_t(\"mRunMinutes\", &amp;mRunMinutes) &gt;= 0) {\n  debugSetLastGlobalDescription(\"Minutes of run time\");\n}\nif (debugAddGlobalUInt8_t(\"mRunHours\", &amp;mRunHours) &gt;= 0) {\n  debugSetLastGlobalDescription(\"Hours of run time\");\n}\n\n\/\/ Note: easy way, no descriptions ....\n\ndebugAddGlobalBoolean(\"mBoolean\", &amp;mBoolean);\ndebugAddGlobalChar(\"mChar\", &amp;mChar);\ndebugAddGlobalByte(\"mByte\", &amp;mByte);\ndebugAddGlobalInt(\"mInt\", &amp;mInt);\ndebugAddGlobalUInt(\"mUInt\", &amp;mUInt);\ndebugAddGlobalLong(\"mLong\", &amp;mLong);\ndebugAddGlobalULong(\"mULong\", &amp;mULong);\ndebugAddGlobalFloat(\"mFloat\", &amp;mFloat);\ndebugAddGlobalDouble(\"mDouble\", &amp;mDouble);\n\ndebugAddGlobalString(\"mString\", &amp;mString);\n\n\/\/ Note: For char arrays, not use the '&amp;'\n\ndebugAddGlobalCharArray(\"mCharArray\", mCharArray);\n\n\/\/ Note, here inform to show only 20 characteres of this string or char array\n\ndebugAddGlobalString(\"mStringLarge\", &amp;mStringLarge, 20);\n\ndebugAddGlobalCharArray(\"mCharArrayLarge\", mCharArrayLarge, 20);<\/pre>\n<p>Here\u2019s some things you need to keep in mind when using the debugger show\/change global variables values functionality:<\/p>\n<ul>\n<li>It only works with global variables, defined out of any function, generally before all function definitions.<\/li>\n<li>Don&#8217;t use this for local variables, because this will always be accessed, and if it is a local variable, it may not exist anymore, which would lead to invalid memory access.<\/li>\n<li>You should have a function for each type of value, for example: <em>debugAddGlobalString()<\/em><\/li>\n<li>To help you migrating your code to use SerialDebug, there is a converter that reads your code and generates the setup() code for global variables automatically: <a href=\"https:\/\/github.com\/JoaoLopesF\/SerialDebugConverter\" target=\"_blank\" rel=\"noopener noreferrer\">SerialDebugConverter<\/a><\/li>\n<\/ul>\n<h3>List Global Variables<\/h3>\n<p>To list all global variables: just use command &#8220;<strong>g<\/strong>&#8220;. First, type &#8220;<strong>dbg<\/strong>&#8221; to activate the debugger and then use the &#8220;g&#8221; command&nbsp; .<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-77544\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/globals1.png?resize=708%2C204&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"708\" height=\"204\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/globals1.png?w=708&amp;quality=100&amp;strip=all&amp;ssl=1 708w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/globals1.png?resize=300%2C86&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/><\/p>\n<p><strong>Note:<\/strong> to avoid overheads of processing of debugger, it starts always disabled. If enabled, the debugger processes watches, as you can see in the following figure:<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-77545\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/debugger_on.png?resize=708%2C306&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"708\" height=\"306\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/debugger_on.png?w=708&amp;quality=100&amp;strip=all&amp;ssl=1 708w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/debugger_on.png?resize=300%2C130&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">By default, the debugger will stop for watches. If you don\u2019t want this to happen, use the command &#8220;<strong>wa ns<\/strong>&#8220;:<\/span><\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-77546\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/watches_nonstop.png?resize=708%2C211&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"708\" height=\"211\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/watches_nonstop.png?w=708&amp;quality=100&amp;strip=all&amp;ssl=1 708w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/watches_nonstop.png?resize=300%2C89&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Now, use the command &#8220;<strong>g<\/strong>&#8221; to list all global variables:<\/span><\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-77547\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-list-global-variables-1.png?resize=708%2C496&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"708\" height=\"496\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-list-global-variables-1.png?w=708&amp;quality=100&amp;strip=all&amp;ssl=1 708w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/serial-debugger-list-global-variables-1.png?resize=300%2C210&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">To change any global variable, e.g. the global number <em>07 &#8211; mInt(int)<\/em>, just type the command &#8220;<strong>g 7 = 10<\/strong>&#8220;:<\/span><\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-77548\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/change-value-global-variable-debugger.png?resize=708%2C188&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"708\" height=\"188\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/change-value-global-variable-debugger.png?w=708&amp;quality=100&amp;strip=all&amp;ssl=1 708w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/change-value-global-variable-debugger.png?resize=300%2C80&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/><\/p>\n<p><strong>Note:<\/strong> the debugger will ask a confirmation to change the value of the variable. You just need to append &#8220;<strong>y<\/strong>&#8221; in command: &#8220;<strong>g 7 = 10 y<\/strong>&#8221;<\/p>\n<p>You can use command &#8220;<strong>g ?<\/strong>&#8220;, to show help of commands for global variables.<\/p>\n<h3>Add\/Change Watches for Global Variables<\/h3>\n<p>A watch is a good feature of any debugger. It observes a certain variable and shows a message if the variable has changed, or reached a pre-established condition. For example, imagine the following scenario:<\/p>\n<ul>\n<li>We have a global variable mControl, that can\u2019t be set to zero.<\/li>\n<li>However, during the tests, it has received the value of zero.<\/li>\n<li>To help detect this bug, we just add a watch with condition &#8220;<strong>mControl == 0<\/strong>&#8220;.<\/li>\n<li>When it occurs, a watch is triggered, and we can see it in the Serial Monitor.<\/li>\n<li>Analyzing the debug outputs before the watch allows us to determine the possible source of this bug.<\/li>\n<\/ul>\n<p>Watches can be set in 2 ways:<\/p>\n<ul>\n<li>In the <em>setup()<\/em> function (this watch isn\u2019t lost if the device turns off or resets)<\/li>\n<li>In the Serial Monitor or SerialDebugApp<\/li>\n<\/ul>\n<h4>Setting watches in setup() function<\/h4>\n<p>For the example SerialDebug_Advanced, we have the following:<\/p>\n<pre>\/\/ Watch -&gt; mBoolean when changed (put 0 on value)\ndebugAddWatchBoolean(\"mBoolean\", DEBUG_WATCH_CHANGED, 0);\n\n\/\/ Watch -&gt; mRunSeconds == 10\ndebugAddWatchInt(\"mRunSeconds\", DEBUG_WATCH_EQUAL, 10);\n\n\/\/ Watch -&gt; mRunMinutes &gt; 3\/\/ Watch -&gt; mRunMinutes &gt; 3\ndebugAddWatchUInt8_t(\"mRunMinutes\", DEBUG_WATCH_GREAT, 3);\n\n\/\/ Watch -&gt; mRunMinutes == mRunSeconds (just for test)\ndebugAddWatchCross(\"mRunMinutes\", DEBUG_WATCH_EQUAL, F(\"mRunSeconds\"));<\/pre>\n<p>Note that the watch can be set for a specific condition or for when&nbsp;&nbsp;(global) variable is changed.<\/p>\n<p>Here\u2019s the types of watches that can be used:<\/p>\n<ul>\n<li><strong>DEBUG_WATCH_CHANGED<\/strong> -&gt; Changed value ?<\/li>\n<li><strong>DEBUG_WATCH_EQUA<\/strong>L -&gt; Equal (==)<\/li>\n<li><strong>DEBUG_WATCH_DIFF<\/strong> -&gt; Different (!=)<\/li>\n<li><strong>DEBUG_WATCH_LESS<\/strong> -&gt; Less (&lt;=)<\/li>\n<li><strong>DEBUG_WATCH_GREAT<\/strong> -&gt; Greater (&gt;)<\/li>\n<li><strong>DEBUG_WATCH_LESS_EQ<\/strong> -&gt; Less or equal (&lt;=)<\/li>\n<li><strong>DEBUG_WATCH_GREAT_EQ<\/strong> -&gt; Greater or equal (&gt;=)<\/li>\n<\/ul>\n<p>To list running watches, use &#8220;<strong>wa<\/strong>&#8220;:<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-77549\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/watches1.png?resize=708%2C328&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"708\" height=\"328\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/watches1.png?w=708&amp;quality=100&amp;strip=all&amp;ssl=1 708w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/watches1.png?resize=300%2C139&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">To show help for watch commands, use &#8220;<strong>wa ?<\/strong>&#8221; command:<\/span><\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-77551\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/watches2.png?resize=708%2C225&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" width=\"708\" height=\"225\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/watches2.png?w=708&amp;quality=100&amp;strip=all&amp;ssl=1 708w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/watches2.png?resize=300%2C95&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 708px) 100vw, 708px\" \/><\/p>\n<h2>Debug Macros<\/h2>\n<p>In <a href=\"https:\/\/randomnerdtutorials.com\/serialdebug-library-arduino-ide\/\">Part 1<\/a>, we\u2019ve seen the print macros for SerialDebug library. It is like a standard Serial.print(). We can also use the debug macros with the powerful <em>printf<\/em> formatting, regardless of whether the board has Serial.printf native or not. As far as I know, only Espressif boards have Serial.printf native.<\/p>\n<p>For example, this snippet:<\/p>\n<pre>Serial.print(\"*** Example - varA = \");\nSerial.print(varA);\nSerial.print(\" varB = \");\nSerial.print(varB);\nSerial.print(\" varC = \");\nSerial.print(varC);\nSerial.println();<\/pre>\n<p>Can be converted to a single command:<\/p>\n<pre>debugD(\"*** Example - varA = %d varB = %d varC = %d\", varA, varB, varC);<\/pre>\n<p>And you can add more format parameters:<\/p>\n<pre>debugD(\"*** Example - varA = %02d varB = %02d varC = %02d\", varA, varB, varC);<\/pre>\n<p>The&#8221;%02&#8243; means: minimum of 2 digits, lead of zero, if needed (e.g 2 is shown as 02).<\/p>\n<p>Comparing the different types of debug outputs:<\/p>\n<ul>\n<li>print macros is easier to migrate, and there isn\u2019t overhead (it is a simple macro for Serial.print command)<\/li>\n<li>debug macros is more powerful, but it isn\u2019t so easy to migrate, and it has an extra overhead (about 1% more)<\/li>\n<\/ul>\n<p>It&#8217;s up to you, you can either use the simple print macro or the powerful printf of debug macro.<\/p>\n<h2>Wrapping Up<\/h2>\n<p>In this second article you&#8217;ve learned how to use the Simple software debugger commands of the <a href=\"https:\/\/github.com\/JoaoLopesF\/SerialDebug\" target=\"_blank\" rel=\"noopener noreferrer\">SerialDebug library<\/a> in the Arduino IDE to list and run functions, list and change global variables and set watches.<\/p>\n<p>In <a href=\"https:\/\/randomnerdtutorials.com\/serialdebugapp-arduino-ide-serialdebug-library\/\">Part 3<\/a>, you can discover how to take the most out of these features using the SerialDebugApp.<\/p>\n<p><strong>Continue Reading<\/strong>:&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/serialdebugapp-arduino-ide-serialdebug-library\/\">Better Debugging for Arduino IDE: SerialDebugApp (Part 3)<\/a><\/p>\n<p>Help me bring a better debug to the Arduino IDE using this library. Visit the GitHub page <a href=\"https:\/\/github.com\/JoaoLopesF\/SerialDebug\">https:\/\/github.com\/JoaoLopesF\/SerialDebug<\/a>, for more information, post issues and suggestions. Also, you can use the <a href=\"https:\/\/gitter.im\/SerialDebug\/Public\" target=\"_blank\" rel=\"noopener noreferrer\">gitter chat room<\/a> to share your feedback.<\/p>\n<p>Thanks to Random Nerd Tutorials for the possibility of doing a post about SerialDebug library.<\/p>\n<p>Jo\u00e3o Lopes<\/p>\n<p><em>Random Nerd Tutorials has more than 200 free electronics projects and tutorials. Check them all in the next link:&nbsp;<\/em><a href=\"https:\/\/randomnerdtutorials.com\/projects\/\" target=\"_blank\" rel=\"noopener noreferrer\">200+ Electronics Projects and Tutorials<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The SerialDebug library created by Jo\u00e3o Lopes allows you to improve debugging for the Arduino IDE. In this article he\u2019ll show you how to use the simple software debugger of the SerialDebug library that has most functionalities of an hardware debugger. <\/p>\n<p class=\"read-more-container\"><a href=\"https:\/\/randomnerdtutorials.com\/software-debugger-arduino-ide-serialdebug-library\/\" class=\"read-more button\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":77571,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[2,245,299,269,264],"tags":[],"class_list":["post-77536","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-arduino","category-arduino-ide","category-0-esp32","category-guide-project","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/11\/Serial-debug-software-arduino-ide.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/77536","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=77536"}],"version-history":[{"count":0,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/77536\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/77571"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=77536"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=77536"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=77536"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}