Release 2017.5.20 / Update 2017.6.19

TIPS for finding bugs

You may unforcely fail to right code sometimes when you modify it. If the sketch isn’t long, it doesn’t matter. But the more big project makes it more difficult to find the bug.

On this article, I show you how I find it. These are TIPS for finding bugs when compile is OK.

Finding problems

If your miss is obvious, compiler finds it. But if it isn’t, the program works tentatively and hard to find.

I think reason that the program does not work well can be summarized into two points.

  • The program flow does not work as expected
  • Failing to calculate variable properly

As a conclusion, you have to find the wrong code yourself. But if you use Serial.print, it will be more easier to find the bug.

Wiring and Sample Sketch

If you use Arduino UNO, you can exchange SDA as A4 pin, SCL as A5 pin.

I expect to use OLED of 128×64 size and I2C.

Following sample works tact switch as “ON” display, variable resistor as value and gauge bar display.

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI
#define VR A0
#define SW 7
short   vr_val;
boolean sw_status;

void setup() {
  u8g.setFont(u8g_font_6x10);   // set font on OLED
  u8g.setColorIndex(1);         // set color on OLED to white
  pinMode(VR, INPUT);           // set VR pin
  pinMode(SW, INPUT_PULLUP);    // set tact switch pin
}

void loop() {
  vr_val = VR_READ(vr_val);   // VR read
  BUTTON();                   // tact switch read
  DRAW();                     // draw to OLED
}

void BUTTON() {
  unsigned int gauge = 0;                      // make gauge variable
  while (digitalRead(SW) == true) gauge++;     // "gauging"
  if (gauge > 700) sw_status = !sw_status;     // change'sw_status' by the result
}

short VR_READ(short tmp) {
  short read_val = tmp * 0.9 + analogRead(VR) * 0.1;     // get VR value
  return tmp;                                            // return the value
}

void DRAW() {
  byte gauge_x = map(vr_val, 0, 1013, 0, 127);  // remap VR value to OLED X size

  u8g.firstPage();
  do {
    u8g.setPrintPos(0, 10);                     // set position of VR value
    u8g.print(vr_val);                          // display VR value as number

    u8g.drawBox(0, 30, gauge_x, 10);            // display VR value as gauge bar
    if (sw_status) u8g.drawStr(100, 10, "ON");  // display tact switch status

    vr_val = VR_READ(vr_val);                   // get VR value (for faster response)
    BUTTON();                                   // tact switch read (for faster response)
  } while ( u8g.nextPage() );
}

Originally the numerical value and the bar will be displayed on the OLED if the switch is pressed “ON”, or by turning the variable resistor.

But it doesn’t, intentionally.

VR is disabled although display. So finding where to fix, use Serial.println.

Find freezing line

Basically, Arduino flow start from setup() function, then it loops loop() function. So at first, I make numbering print for doubtful code.

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI
#define VR A0
#define SW 7
short   vr_val;
boolean sw_status;

void setup() {
  Serial.begin(38400);
  u8g.setFont(u8g_font_6x10);
  u8g.setColorIndex(1);
  pinMode(VR, INPUT);
  pinMode(SW, INPUT_PULLUP);
  Serial.println("A");
}

void loop() {
  Serial.println("B");
  vr_val = VR_READ(vr_val);
  Serial.println("C");
  BUTTON();
  Serial.println("D");
  DRAW();
  Serial.println("E");
}

You can see it stopped before ‘D’ on Serial Monitor.

It tells you ‘BUTTON()’ function is suspicious. Then, find accurate code from BUTTON() function as same way.

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI
#define VR A0
#define SW 7
short   vr_val;
boolean sw_status;

void setup() {
  Serial.begin(38400);
  u8g.setFont(u8g_font_6x10);
  u8g.setColorIndex(1);
  pinMode(VR, INPUT);
  pinMode(SW, INPUT_PULLUP);
}

void loop() {
  vr_val = VR_READ(vr_val);
  BUTTON();
  DRAW();
}

void BUTTON() {
  Serial.println("A");
  unsigned int gauge = 0;
  Serial.println("B");
  while (digitalRead(SW) == true) gauge++;
  Serial.println("C");
  if (gauge > 700) sw_status = !sw_status;
  Serial.println("D");
}

You will see it stops before ‘C’.

while (digitalRead(SW) == true) gauge++;

I can assume this code goes wrong.

You have to find what is wrong at yourself in the end. But this way is much easier to find to where. By the way, this problem is caused of internal pullup.

while (digitalRead(SW) ==false) gauge++;

Now you can see tact switch works.

Well, here is another problem still. VR does not works yet.

As Serial Monitor returns B to E value, program seems to flow correct.

Check variable change

If the sketch doesn’t have unexpected stop, there could be wrong calculation for variables. So then, I make return of the variable to Serial Monitor. There is a variable ‘vr_val’ on this sample sketch, set Serial print return to end of line.

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI
#define VR A0
#define SW 7
short   vr_val;
boolean sw_status;

void setup() {
  Serial.begin(38400);
  u8g.setFont(u8g_font_6x10);
  u8g.setColorIndex(1);
  pinMode(VR, INPUT);
  pinMode(SW, INPUT_PULLUP);
}

void loop() {
  vr_val = VR_READ(vr_val);
  BUTTON();
  DRAW();
  Serial.println(vr_val);
}

‘vr_val’ doesn’t change at all.

Just in case, set same returns on other lines.

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI
#define VR A0
#define SW 7
short   vr_val;
boolean sw_status;

void setup() {
  Serial.begin(38400);
  u8g.setFont(u8g_font_6x10);
  u8g.setColorIndex(1);
  pinMode(VR, INPUT);
  pinMode(SW, INPUT_PULLUP);
}

void loop() {
  Serial.println(vr_val);
  vr_val = VR_READ(vr_val);
  Serial.println(vr_val);
  BUTTON();
  Serial.println(vr_val);
  DRAW();
  Serial.println(vr_val);
}

You can assume VR_READ() function doesn’t work well.

short VR_READ(short tmp) {
  short read_val = tmp * 0.9 + analogRead(VR) * 0.1;
  return tmp;
}

And in the end, find it yourself.

As saying the answer, the return of VR_READ() is wrong. Modify the code to “return read_val;” or,

short VR_READ(short tmp) {
  return tmp * 0.9 + analogRead(VR) * 0.1;
}

Now program works as I expected.

Make function and use preprocessor

As you know, this method is meaningless on this short sketch. But like my follow focus project, it is very convenient on the long code.

If you plan to have big project, you might get those debug code lines as comment out in advance.

void loop() {
  //Serial.println(vr_val);
  vr_val = VR_READ(vr_val);
  //Serial.println(vr_val);
  BUTTON();
  DRAW();
  //Serial.println(vr_val);
}

But this is bothersome way. I recommend you to make a ‘debug function’ for the important arguments.

void DEBUG(char num) {
  Serial.print(num);
  Serial.print(  "VR:");
  Serial.print(vr_val);
  Serial.print("  SW:");
  Serial.print(sw_status);
  Serial.println();
}

Then, by using ‘#define’ preprocessor, you can change entire displaying with ‘true’ or ‘false’.

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI
#define VR A0
#define SW 7
#define debug_on true

short   vr_val;
boolean sw_status;

void setup() {
  if (debug_on) Serial.begin(38400);
  u8g.setFont(u8g_font_6x10);
  u8g.setColorIndex(1);
  pinMode(VR, INPUT);
  pinMode(SW, INPUT_PULLUP);
}

void loop() {
  if (debug_on) DEBUG('A');
  vr_val = VR_READ(vr_val);
  if (debug_on) DEBUG('B');
  BUTTON();
  if (debug_on) DEBUG('C');
  DRAW();
}

void BUTTON() {
  unsigned int gauge = 0;
  while (digitalRead(SW) == false) gauge++;
  if (gauge > 700) sw_status = !sw_status;
}

short VR_READ(short tmp) {
  return tmp * 0.9 + analogRead(VR) * 0.1;
}

void DRAW() {
  byte gauge_x = map(vr_val, 0, 1013, 0, 127);

  u8g.firstPage();
  do {
    u8g.setPrintPos(0, 10);
    u8g.print(vr_val);
    u8g.drawBox(0, 30, gauge_x, 10);
    if (sw_status) u8g.drawStr(100, 10, "ON");
    vr_val = VR_READ(vr_val);
    BUTTON();
  } while ( u8g.nextPage() );
}

void DEBUG(char num) {
  Serial.print(num);
  Serial.print("  VR:");
  Serial.print(vr_val);
  Serial.print("  SW:");
  Serial.print(sw_status);
  Serial.println();
}

And more, if you use ‘#if’ and ‘#endif’ preprocessor, it makes the sketch compact and be faster.

#if(Judgment formula)
  code~
#endif

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI
#define VR A0
#define SW 7
#define debug_on true

short   vr_val;
boolean sw_status;

void setup() {
#if (debug_on)
  Serial.begin(38400);
#endif
  u8g.setFont(u8g_font_6x10);
  u8g.setColorIndex(1);
  pinMode(VR, INPUT);
  pinMode(SW, INPUT_PULLUP);
}

void loop() {
#if (debug_on)
DEBUG('A');
#endif
  vr_val = VR_READ(vr_val);
#if (debug_on)
DEBUG('B');
#endif
  BUTTON();
#if (debug_on)
DEBUG('C');
#endif
  DRAW();
}

I used this method on my Follow Focus Sketch. Check it if you are going to use.

DIY Follow Focus Sketch