Go Down

Topic: ESP8266 NodeMCU 1.0 and PCF8574 - Call PCF Object by Reference (Read 74 times) previous topic - next topic

edsaib

Hello everyone,

so I've been working on this project for a while now and stumbled upon a problem which I haven't been able to solve so far. For this project I'm using an ESP8266 NodeMCU 1.0 with industrial buttons (see link below) connected to the PCF8574 port expander (I also integrated ws2812 smd's into the buttons). For the buttons I use a modified header file (input_pcf.h) which was initially written by a friend of mine and for the ws2812 I am also using a header file (neo.h) written by the same friend (both of them are working fine). As for the port expander, I use the PCF8574 library written by xreef on github https://github.com/xreef/PCF8574_library . To sum everything up, I connected the buttons to (GND and) the PCF8574, which is connected to the Microcontroller via I2C. The data bus of the smd's are also connected to the ESP.

industrial buttons: https://de.aliexpress.com/item/KEINE-NC-START-STOP-DPST-LED-Momentary-Drucktastenschalter-AC-220-V-F-r-Starter-Sch-tz/32841013279.html?spm=a2g0s.11045068.rcmd404.3.7af356a4BSADBP&pvid=39e487c7-cbee-4b92-91dc-703921392acb&gps-id=detail404&scm=1007.16891.96945.0&scm-url=1007.16891.96945.0&scm_id=1007.16891.96945.0

(Almost) everything has been working fine so far, until I modified the input.h file and connected the buttons to the port expander. You initialize the input object with a pin, which is connected to a button. You can connect the industrial button two ways: on the closing side and on the opening side, I am using the opening side against GND. As I cannot just initialize the input object with a pin from the port expander, I just modified the input.h to input_pcf.h where I also have to pass a reference of the PCF8574 object to it, so I can directly read the pin state in my input_pcf.h. Unfortunately, this is not working at all. The button presses are not detected at all and nothing is reacting to it. Now I am trying to resolve the problem...

...did I do something wrong when passing the object by reference? 
...is there a fallacy in my logic to it?

I have checked all connections many times, so I am pretty sure the connections are fine. When examining the button press with the esp, everything is working fine, and the smd's light up as intended. I tested the port expander as well with a simple code where I light up an LED and there were no problems with it. I hope some of you could help me to solve this problem! The code of all relevant files used are below and also attached to this post. Thank you in advance!

simplePCFinputTest.ino
Code: [Select]

#include "PCF8574.h"
#include "input_pcf.h"
#include "neo.h"

// neopixel
const int neo_data = D3;
const int btn = 0;
neo neo(2, neo_data);

//input button(btn);
PCF8574 pcf(0x20, D2, D1);
input_pcf button(btn, pcf);

bool pressed = false;
bool debug_once = true;
unsigned long timer = 0;

void setup() {
  // put your setup code here, to run once:
  delay(500);
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("\nSerial Init OK");

  //pcf
  pcf.pinMode(btn, INPUT);
  pcf.digitalWrite(btn, HIGH);
  pcf.begin();
  Serial.println("PCF Init OK");

 
  pinMode(neo_data, OUTPUT);
  digitalWrite(neo_data, LOW);

  neo.Setup();
 
  Serial.println("Init OK\n");

}

void loop() {
  // put your main code here, to run repeatedly:
  if(debug_once){
    Serial.println("Entering Loop\n");
  }
  timer = millis();

  if(button.pressed){
    Serial.println("Button pressed");
    //delay(200);
    if(pressed){
      neo.led.setPixelColor(0, BLACK);
      neo.led.setPixelColor(1, BLACK);
      pressed = false;
    } else {
      neo.led.setPixelColor(0, PURPLE);
      neo.led.setPixelColor(1, WHITE);
      pressed = true;
    }
 
  }

  neo.Loop();

  button.Update();
  //if(millis() - timer >= 3) Serial.println(millis() - timer);

  debug_once = false;

}


input_pcf.h
Code: [Select]

//@(#) input_pcf.h

#ifndef INPUT_PCF_H
#define INPUT_PCF_H

#include "PCF8574.h"


class input_pcf
{
  private:

    PCF8574& pcf;
    const uint16_t pin;
    unsigned long timer = 0;
    boolean state = false;
    boolean state_long = false;


  public:
 
    boolean pressed_long = false;
    boolean pressed = false;


    input_pcf(const uint16_t pin, PCF8574& pcf_ref) : pin(pin), pcf(pcf_ref){
    }
   
    void Update(){ //button input debouncing and press duration detection
   
   
      pressed = false;
      pressed_long = false;

      //button pressed
      if(!pcf.digitalRead(pin) && !state && millis() - timer >= 50){
        state = true;
        timer = millis();
      }
      //button pressed long
      else if(!pcf.digitalRead(pin) && state && !state_long && millis() - timer >= 1000){
        state_long = true;
        pressed_long = true;
      }
      //button pressed short
      else if(pcf.digitalRead(pin) && state && millis() - timer >= 50){
        if(millis() - timer < 1000) pressed = true;
        state_long = false;
        state = false;
        timer = millis();
      }
    }
   
};

#endif


neo.h
Code: [Select]

//@(#) neo.h

#ifndef NEO_H
#define NEO_H

#include <Adafruit_NeoPixel.h>          //WS2812 library
#include "WS2812_Definitions.h"


class neo
{
     
  private:

    unsigned long neo_show_timer = 0;
    const uint16_t neo_show_delay = 75;

   
    const uint16_t led_count;
    const uint16_t led_pin;




  public:

    Adafruit_NeoPixel led;

    //constructor
    neo(const uint16_t &count,const uint16_t &pin) : led_count(count), led_pin(pin), led(Adafruit_NeoPixel(this->led_count, this->led_pin, NEO_GRB + NEO_KHZ800)){
     
      //this->led = new Adafruit_NeoPixel(this->led_count, this->led_pin, NEO_GRB + NEO_KHZ800);
    }



    //Sets all LEDs to off, but DOES NOT update the display;
    void clearLEDs(){
      for (uint16_t i=0; i<led.numPixels(); i++){
        led.setPixelColor(i, 0);
      }
    }


    //setup
    void Setup(){
      led.begin();
      clearLEDs();
      led.show();
    }
   
    //mainloop   
    void Loop(){
   
      //update rgb LED ring
      if(millis() - neo_show_timer >= neo_show_delay){   
        led.show(); 
        neo_show_timer = millis();
      }
    }
};


//leds.setPixelColor(i, color);
//leds.setPixelColor(i, red, green, blue);

#endif

blh64

Typically, you call the begin() function before any other functions for the device.
Code: [Select]

  pcf.pinMode(btn, INPUT);
  pcf.digitalWrite(btn, HIGH);
  pcf.begin();

You seem to be doing it the other way around which may or may not be the problem since you just provided the .h files

Also, you neo.h file contains setup() and loop() !?!?!?!

edsaib

Typically, you call the begin() function before any other functions for the device.
Code: [Select]

  pcf.pinMode(btn, INPUT);
  pcf.digitalWrite(btn, HIGH);
  pcf.begin();

You seem to be doing it the other way around which may or may not be the problem since you just provided the .h files

Also, you neo.h file contains setup() and loop() !?!?!?!
The examples of the PCF library first set the pinModes/digitalWrites and then call the begin() function, also this has never been a problem in prior projects.

The setup() and loop() functions in neo.h are just void functions which should not be interpreted like the setup() and loop() constructs in Arduino sketches. The setup() function is just called once, which basically behaves like a "begin" function in any other lib and the loop function just "updates" the state (it's not looping in itself). I know, I should probably refractor the code a little but I am pretty sure this is not the cause of my problem.

Thanks for your help anyways!
Best regards!

Go Up