Help fixing loop issue (Magnet Sensor and OLED screen)

Hello,

I'm new to arduino and I have a issue with my code.

I'm trying to count each time the magnet sensor detect a magnet and display it on the OLED screen. I guess this is very basic.

Here is my code:

#define Led A0
#define Hall 2

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width,  in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);



unsigned long count = 0;
int val; //numeric variable

void setup() {
  // MAGNET SENSOR
  pinMode(Led, OUTPUT);
  pinMode(Hall, INPUT);
  Serial.begin(9600);


  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

}

void loop() {
  //MAGNET CODE

  val = digitalRead(Hall); //Read the sensor
  if(val == LOW) //when magnetic field is detected, turn led on
  {
    digitalWrite(Led, HIGH);
    ++count;
    
    display.clearDisplay();
    display.setTextSize(3);             // Normal 1:1 pixel scale
    display.setTextColor(SSD1306_WHITE);        // Draw white text
    display.setCursor(0,25);             // Start at top-left corner
    display.println(count);
    display.display();
  }
  else
  {
    digitalWrite(Led, LOW);
  }
}

The counter keep increasing and do not increase only when I put a magnet in front of the sensor.

Already tried to move the ++count and display code to the else condition. The result is the same, count increase automatically without end...

Any help would be appreciated :slight_smile:

(assuming you have a pull down)

this detects when the magnet is in front of the sensor, not when it arrives in front of the sensor.

As the loop runs fast, you can have many hits as long as the magnet stays in front of the sensor.

Study the examples about State Change Detection (for example https://www.arduino.cc/en/Tutorial/BuiltInExamples/StateChangeDetection)

I'm looking to your link

edit:

Now the magnet sensor isn't working, its not detecting when I put a magnet in front


  // read the pushbutton input pin:
  buttonState = digitalRead(Hall);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      ++count;
    
      display.clearDisplay();
      display.setTextSize(3);             // Normal 1:1 pixel scale
      display.setTextColor(SSD1306_WHITE);        // Draw white text
      display.setCursor(0,25);             // Start at top-left corner
      display.println(count);
      display.display();
    } else {
      // if the current state is LOW then the button went from on to off:
      //Serial.println("off");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;


  // turns on the LED every four button pushes by checking the modulo of the
  // button push counter. the modulo function gives you the remainder of the
  // division of two numbers:
  if (count % 4 == 0) {
    digitalWrite(Led, HIGH);
  } else {
    digitalWrite(Led, LOW);
  }

how did you wire things up?

I use this hall sensor

Wire connection :

D0 on D2
A0 on A0
GND on GND
VCC on 5V

#define Led A0
#define Hall 2

connect

  • Arduino PIN D2 to Sensor D0
  • Arduino GND to Sensor GND
  • Arduino 5V to Sensor VCC

upload this code and open the Serial monitor at 115200 bauds

const byte sensorPin = 2; // Arduino PIN D2 to Sensor D0

void setup() {
  Serial.begin(115200);
  pinMode(sensorPin, INPUT); // not ncessary, it's INPUT by default
}

void loop() {
  Serial.println((digitalRead(sensorPin) == LOW) ? F("LOW") : F("HIGH"));
  delay(100);
}

and wave a magnet in front of / away from the sensor.

try adjusting the potentiometer on the Sensor board if no detection occurs

if you want to see some raw data, connect

  • Arduino PIN A0 to Sensor A0
  • Arduino GND to Sensor GND
  • Arduino 5V to Sensor VCC
    try this code:
const byte sensorPin = A0; // Arduino PIN A0 to Sensor A0

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println(analogRead(sensorPin));
  delay(100);
}

The sensor is working! but I have no display on my OLED screen

edit: I added the OLED code and now its working :slight_smile: Thank you!

Final code

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width,  in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const byte sensorPin = 2; // Arduino PIN D2 to Sensor D0
unsigned long count = 0;

void setup() {
  Serial.begin(115200);
  pinMode(sensorPin, INPUT); // not ncessary, it's INPUT by default

    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
}

void loop() {
  Serial.println((digitalRead(sensorPin) == LOW) ? F("LOW") : F("HIGH"));

  if (digitalRead(sensorPin) == LOW) {
     ++count;
    
      display.clearDisplay();
      display.setTextSize(3);             // Normal 1:1 pixel scale
      display.setTextColor(SSD1306_WHITE);        // Draw white text
      display.setCursor(0,25);             // Start at top-left corner
      display.println(count);
      display.display();
  }
  
  delay(100);
}

EDIT 2 :

Could you tell me how I can adjust the sensibility of the sensor ? If it is possible :slight_smile:

progress ! :slight_smile:

side note: blocking the code for some time with

is not going to work for you if your magnet goes slowly (you'll count way more than needed) in front of the sensor or at more than 10 Hz (you'll miss some counts)

you should really implement a state change detection

state change detection implemented and working :

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width,  in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const byte sensorPin = 2; // Arduino PIN D2 to Sensor D0
unsigned long count = 0;
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
  Serial.begin(115200);
  pinMode(sensorPin, INPUT); // not ncessary, it's INPUT by default

    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
}

void loop() {
  Serial.println((digitalRead(sensorPin) == LOW) ? F("LOW") : F("HIGH"));

  // read the pushbutton input pin:
  buttonState = digitalRead(sensorPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      ++count;
    
      display.clearDisplay();
      display.setTextSize(3);             // Normal 1:1 pixel scale
      display.setTextColor(SSD1306_WHITE);        // Draw white text
      display.setCursor(0,25);             // Start at top-left corner
      display.println(count);
      display.display();
    } else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("off");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;
}

Wow. That has to be least time problem to state change detection I’ve ever seen. Well done.

a7

Sound like now I have to implement EEPROM storing read/write/update to keep the value of my counter after a reboot/poweroff

Will update final code here.

Careful on how often you write a new value to the EEPROM. There is a 100,000 Times limit after which things can go wrong.

It may seem a lot but if you write often, say every second, you’ll kill the memory cells you use in less than 28 hours

A smart way to deal with this is to add a big enough capacitor and a small circuit to detect the power failure and use the power from the capacitor to write to the EEPROM before the complete shutdown

Do you have any exemple of capacitor and a small circuit to detect the power failure ?

Because the counter will be increased by a lot ... easily millions of time..

I don't have one in English.

There is a good tutorial in French on @hbachetti blog

I'm pretty sure Google translate can do a good enough job on this page so that it makes sense to you.

Google translate link ➜ RitonDuino: Arduino: sauvegarde de données en EEPROM en cas de coupure d'alimentation

I'm French so it couldn't be better :smiley:
Thank you buddy

:slight_smile:

there is an active French forum if you want