Home > Mobile >  How to write to a specific register on RP2040 to debounce
How to write to a specific register on RP2040 to debounce

Time:10-24

I'm using the Arduino IDE and langauge (C) to program a Raspberry Pi Pico. I have a project that uses a 16x2 LCD and a button to control it's backlight. The button and everything other works correctly, my problem is that every time i press the switch, the backlight flickers, and need to press it random times to stay on or off i suggest due to bouncing. I want to clear the 22 bit in the ICSR register of the RP2040 to clear any pending stuff in the interrupt buffer before return from the interrupt. https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_m0plus (page 87, or 86 on the bottom of the page)

My code so far:

#include <Adafruit_BMP280.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
#include "hardware/regs/m0plus.h"
//#include <pico/stdlib.h>
//#include <hardware/pwm.h>

Adafruit_BMP280 bmp; //I2C

hd44780_I2Cexp lcd(0x27, 16, 2);

const uint16_t AirValue = 1023;
const uint16_t WaterValue = 660; //measured fully submerged in water
const uint16_t DarkValue = 0;
const uint16_t LightValue = 1023;
uint16_t soilMoisture;
uint16_t soilMoisturePercent;
uint16_t lightIntensity;
uint16_t lightIntensityPercent;
volatile bool lcdBacklightStatus = false;

byte pressureChar[] = { 0b01000, 0b11110, 0b11100, 0b01000, 0b00011, 0b01111, 0b00000, 0b11110
};

byte moistureChar[] = { 0b00000, 0b00100, 0b01110, 0b11111, 0b11111, 0b11111, 0b01110, 0b00000
};

byte lightIntensityChar[] = { 0b00000, 0b01110, 0b10001, 0b11011, 0b10101, 0b01110, 0b01110, 0b00100
};

byte temperatureChar[] = { 0b01000, 0b10111, 0b10100, 0b11111, 0b11100, 0b11100, 0b11100, 0b01000
};

byte separatorWall[] = { 0b10101, 0b01010, 0b10101, 0b01010, 0b10101, 0b01010, 0b10101, 0b01010
};

byte degreeChar[] = { 0b00111, 0b00101, 0b00111, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000
};

void backlight();

void setup() {
  lcd.begin(0x27, 16, 2);

  lcd.createChar(0, pressureChar);
  lcd.createChar(1, moistureChar);
  lcd.createChar(2, lightIntensityChar);
  lcd.createChar(3, temperatureChar);
  lcd.createChar(4, separatorWall);
  lcd.createChar(5, degreeChar);

  lcd.home();

  pinMode(26, INPUT); //soilMoisture
  pinMode(27, INPUT); //lightIntensity
  pinMode(17, INPUT); //button

  attachInterrupt(digitalPinToInterrupt(17), backlight, RISING);
  
  //Serial.begin(9600);

  bmp.begin(0x76);
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                  Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
                  Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
                  Adafruit_BMP280::FILTER_X16,      /* Filtering. */
                  Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */

  lcd.clear();
  lcd.backlight(); //lcd.noBacklight();

  lcd.setCursor(1,0);
  lcd.print("Plant Station");
  lcd.setCursor(6,1);
  lcd.print("V0.8");

  delay(2000);

  lcd.noBacklight();
  lcd.clear();

  lcd.setCursor(0,0);
  lcd.write(byte(3));
  lcd.setCursor(10,0);
  lcd.write(byte(2));
  lcd.setCursor(0,1);
  lcd.write(byte(0));
  lcd.setCursor(10,1);
  lcd.write(byte(1));
  lcd.setCursor(7,0);
  lcd.write(byte(5));
  lcd.setCursor(8,0);
  lcd.print("C");
  lcd.setCursor(15,0);
  lcd.print("%");
  lcd.setCursor(6,1);
  lcd.print("hPa");
  lcd.setCursor(15,1);
  lcd.print("%");
}

void loop() {
  soilMoisture = analogRead(26);
  soilMoisturePercent = map(soilMoisture, AirValue, WaterValue, 0, 100);

  lightIntensity = analogRead(27);
  lightIntensityPercent = map(lightIntensity, DarkValue, LightValue, 0, 100);

  if(soilMoisturePercent >= 100) soilMoisturePercent = 100;
    else if(soilMoisturePercent <= 0) soilMoisturePercent = 0; 

  if(lightIntensityPercent >= 100) lightIntensityPercent = 100;
    else if(lightIntensityPercent <= 0) lightIntensityPercent = 0;

  //Serial.print("Moisture: ");
  //Serial.println(soilMoisture);
  //Serial.print("Percentage: ");
  //Serial.println(soilMoisturePercent);
  //Serial.print("LightIntensity: ");
  //Serial.println(lightIntensity);
  //Serial.print(soilMoisture);
  //Serial.println(soilMoisturePercent);

  //BANNED CURSOR POSITIONS: 0,0  9,0  0,1  9,1  6,0  14,0  7,0  15,0  5,1  15,1

  lcd.setCursor(3,0);
  lcd.print(bmp.readTemperature(),1);
  lcd.setCursor(2,1);
  lcd.print(((bmp.readPressure()/100)),0);
  if(soilMoisturePercent < 10) {
    lcd.setCursor(13,1);
    lcd.print(" ");
    lcd.print(soilMoisturePercent);
  } else if(soilMoisturePercent < 100) {
    lcd.setCursor(13,1);
    lcd.print(soilMoisturePercent);
  } else {
    lcd.setCursor(12,1);
    lcd.print(soilMoisturePercent);
  }
  if(lightIntensityPercent < 10) {
    lcd.setCursor(13,0);
    lcd.print(" ");
    lcd.print(lightIntensityPercent);
  } else if(lightIntensityPercent < 100) {
    lcd.setCursor(13,0);
    lcd.print(lightIntensityPercent);
  } else {
    lcd.setCursor(12,0);
    lcd.print(lightIntensityPercent);
  }

  delay(60000);
}

void backlight() {
  //noInterrupts();
  detachInterrupt(digitalPinToInterrupt(17));
  if(lcdBacklightStatus == true) {
    lcd.noBacklight();
  } else if(lcdBacklightStatus == false) {
    lcd.backlight();
  }
  delayMicroseconds(500000);
  //interrupts();
  attachInterrupt(digitalPinToInterrupt(17), backlight, RISING);
  lcdBacklightStatus = !lcdBacklightStatus;
  //want to clear ICSR register here i guess
}

I may be not clear enough, sorry if that's the case, English isn't my main langauge.

CodePudding user response:

@stark became my hero, i removed the entire Interrupt section and the 60seconds long delay at the end of the main loop. Then added the following code, and now when the button is pressed for 1second, the lcd backlight toggles, and the sensors are still only checked every 60seconds. Still don't know how to handle registers to debounce, so the post remains open.

  for(int i = 0; i < 600; i  ) {
    if(digitalRead(17) == 1) trueCount  ;
    if(trueCount == 10) {
      lcdBacklightStatus = !lcdBacklightStatus;
      trueCount = 0;
    }
    if(lcdBacklightStatus == false) {
    lcd.noBacklight();
    } else if(lcdBacklightStatus == true) {
    lcd.backlight();
    }
    delay(100);
  }

CodePudding user response:

The RP2040 does not have a turn-key debouncing feature that you can just turn on by writing to a bit in a register somewhere.

You will have to perform multiple digital readings and use a timing function like millis() to detect when the button has been held down or released for a long-enough time. You can use the Pushbutton library from Pololu to do that, or just read its code as a reference so you can understand how to implement your own debouncing.

You could also consider reading the button using a PIO state machine and just sending press/release events to the main CPU.

  • Related