Integrating SH1106 into project

I'm working on making a coffee machine, I have implemented the following code, and it seems to work. Keep in mind I'm not a coder so I'm sure a lot of what I'm doing is not necessarily the best way to do it. here's the schematic.




currently everything works from a hardware perspective, and I can get all the systems to work on there own, and I can get the code I have now to work. However now I want to add the OLED display, and when I do ( see the commented out portions) the code just gets locked up and nothing happens, I know I'm using a bunch of If statements for logic in state 2, which I'm guessing is causing some errors, not really sure how to change that logic. Again I can get the OLED to work if I run the SH1106 example sketch, but I'm not a coder so I don't really know what I'm doing. Any help would be appreciated.

for reference, I'm using a ds1820 temp sensor, simple push buttons for the switches, and the water tank sw is just a water level probe, the SSR goes through a opto Isolator. The motorOn header goes to a separate motor controller.


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

#include <PID_v1.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels
#define OLED_RESET -1     // Reset pin # (or -1 if sharing Arduino reset pin)
#define i2c_Address 0x3c  ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


// Pin Definitions
#define ONE_WIRE_BUS 6
#define FAULT_PIN 2
#define POWER_ON_PIN 3
#define TEMP_UP_PIN 5
#define TEMP_DOWN_PIN 4
#define BREW_SW_PIN 7
#define MOTOR_PIN 8
#define WATER_TANK_PIN A2
#define SSR_PIN A3




// Constants
double setTemp = 200;  // Set temperature

// Initialize OneWire and DallasTemperature objects
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Initialize PID variables
double Input, Output;
double Kp = 22, Ki = 1.5, Kd = 20;
PID myPID(&Input, &Output, &setTemp, Kp, Ki, Kd, DIRECT);

// Define state enumeration
enum State {
  STATE_1,
  STATE_2,
  STATE_3,
  STATE_4,
  STATE_5,
  STATE_6
};

// Global variable for current state
State currentState = STATE_1;

// Function prototypes

void handleState1();
void handleState2();
void handleState3();
void handleState4();
void handleState5();
void handleState6();


void setup() {
  Serial.begin(9600);
  delay(2000);  // wait for the OLED to power up
  display.begin(i2c_Address, true);
  display.display();

  pinMode(FAULT_PIN, INPUT);
  pinMode(POWER_ON_PIN, INPUT);
  pinMode(TEMP_UP_PIN, INPUT);
  pinMode(TEMP_DOWN_PIN, INPUT);
  pinMode(BREW_SW_PIN, INPUT);
  pinMode(MOTOR_PIN, OUTPUT);
  pinMode(WATER_TANK_PIN, INPUT_PULLUP);
  pinMode(SSR_PIN, OUTPUT);

  digitalWrite(MOTOR_PIN, LOW);
  digitalWrite(SSR_PIN, LOW);

  myPID.SetMode(AUTOMATIC);  // Set PID to automatic mode
  

  sensors.begin();

}

void loop() {
  switch (currentState) {

    case STATE_1:
      handleState1();
      break;
    case STATE_2:
      handleState2();
      break;
    case STATE_3:
      handleState3();
      break;
    case STATE_4:
      handleState4();
      break;
    case STATE_5:
      handleState5();
      break;
    case STATE_6:
      handleState6();
      break;
  }
}



void handleState1() {
  // check to make sure there is water in the boiler. 
  Serial.println("State: STATE_1");
  if (digitalRead(WATER_TANK_PIN) == LOW) {
    currentState = STATE_2;
  } else {
    currentState = STATE_5;
  }
}

void handleState2() {

  Serial.println("State: STATE_2");
  sensors.requestTemperatures(); 
  float temp = sensors.getTempFByIndex(0); // get the temp of the water 
  Input = temp; // send the temp to the pid 
  Serial.print("Temperature: ");
  Serial.println(temp);
  Serial.println(setTemp);
  // because of the delay in the temp reading, if the temp is not within 10 deg of the set temp turn on the SSR
  if (temp + 10 < setTemp) { 
    digitalWrite(SSR_PIN, HIGH);
    // display.clearDisplay();
    // display.setTextSize(2);              // Normal 1:1 pixel scale
    // display.setTextColor(SH110X_WHITE);  // Draw white text
    // display.setCursor(10, 10);
    // display.print("HEATING...");
    // display.display();
  } else if (temp + 10 > setTemp) { // if the temp is within 10 deg use PID 
    myPID.Compute(); // calculate the PID
    sendPWM(Output); // send the PWM to the 
    Serial.println("sendmess"); 
    sendMess(setTemp);// send the set temp to the screen 
  }

  if (digitalRead(TEMP_UP_PIN) == HIGH) { // if the temp up sw is pressed increase the temp 
    currentState = STATE_3;
  } else if (digitalRead(TEMP_DOWN_PIN) == HIGH) { // vise versa for the temp down switch. 
    currentState = STATE_4;
  } else if (digitalRead(BREW_SW_PIN) == HIGH) { // check if the brew sw is pressed 
    currentState = STATE_6;
  }
  if (digitalRead(WATER_TANK_PIN) == HIGH) { // check if theres water in the tank 
    currentState = STATE_5;
  }
}

void handleState3() {
  Serial.println("State: STATE_3");
  // logic for increasing temperature 
  // dont let the temp go above 209 deg 
  if (setTemp < 209) {
    setTemp++;
    // sendMess(setTemp);
    sendMess(setTemp); // send the new set temp to the screen
    currentState = STATE_2;
  }
  delay(100);
  currentState = STATE_2;
}
void handleState4() {
  Serial.println("State: STATE_4");
  // Add logic for decreasing temperature
  // dont let the set temp go below 195 deg
  if (setTemp > 195) {
    setTemp--;
    //sendMess(setTemp);
    sendMess(setTemp);
    Serial.println(setTemp);
    currentState = STATE_2;
  }
  delay(100);
  currentState = STATE_2;
}

void handleState5() {
  Serial.println("State: STATE_5");

  //  logic for handling water tank being filled
  while (digitalRead(WATER_TANK_PIN) == HIGH) {  // Check if WATER_TANK_PIN is HIGH
    digitalWrite(MOTOR_PIN, HIGH);// Turn on the motor until tank is full
    digitalWrite(SSR_PIN, LOW);  // dont let the SSR turn on while the motot is on 
  }
  digitalWrite(MOTOR_PIN, LOW);  // Turn off the motor
  currentState = STATE_2;        // Transition to STATE_2
}

void handleState6() {
  Serial.println("State: STATE_6");
  // logic for handling brew switch state
  while (digitalRead(WATER_TANK_PIN) == LOW && digitalRead(BREW_SW_PIN) == HIGH) { // the brew switch needs to be high and the water tank needs to be filled. 
    digitalWrite(MOTOR_PIN, HIGH);// Turn on the motor until brew switch is low. 
    digitalWrite(SSR_PIN, LOW);// dont let the SSR turn on while the motot is on 
  }
  digitalWrite(MOTOR_PIN, LOW);// Turn off the motor
  currentState = STATE_2;
}



///////////////////// other functions

/* send the pwm out to the SSR 
the PID sends an output of 0-255 however the SSR needs to have PWM with a period of around 
250-300 to work, so to do this the Duty cycle of the PWM is defined by the PID
*/

void sendPWM(int duty) {
  // because the PWM logic makes the SSR turn on even for a mS this code is added so if the Duty cycle is 0 the SSR is off. 
  if (duty >= 0) { 
    Serial.print("send pwm");
    Serial.println(duty);
    analogWrite(A3, 255);  // turn on the SSR 
    delay(duty); // wait for the duty cycle 
    analogWrite(A3, 0); // tunr off the SSR 
    delay(255 - duty); // wait for the rest of the duty cycle. 
  
  } else if (duty = 0) {
    analogWrite(A3, 0);
  }
}

void sendMess(float temp) {
  // send the set temp on the screen. 

  // display.display();
  // display.clearDisplay();
  // display.setTextSize(1);              // Normal 1:1 pixel scale
  // display.setTextColor(SH110X_WHITE);  // Draw white text
  // display.setCursor(10, 1);
  // display.print("Set Temp :");
  // display.setTextSize(2);              // Normal 1:1 pixel scale
  // display.setTextColor(SH110X_WHITE);  // Draw white text
  // display.setCursor(10, 10);
  // display.println(temp);
  // display.setCursor(90, 10);
  // display.print("F");
  // display.display();
}

In the sendPWM function, you have a logical error in the else if condition: else if (duty = 0) . This should be == for comparison, not assignment. It should be else if (duty == 0) .

You have commented out the code related to displaying the temperature on the OLED screen in the sendMess function. If you want to display the temperature, you should uncomment and adapt that code as needed.

What your RAM usage like? Like the Adafruit_SSD1306 library, the Adafruit_SH1106G library appears to want to allocate a 1024 byte screen buffer at runtime (the actual allocation is buried in Adafruit_GrayOLED::_init). Unlike the SSD1306 library, the SH1106G library throws away the result of this allocation attempt and just continues merrily on its way whether the allocation succeeds or fails.

If the "Global variables use..." line at the end of the compile doesn't show well in excess of 1024 bytes (by at least a few hundred) left for local variables, that's quite likely the root of your problem. Your sketch has run out of RAM.

It’s currently shows
Global variables use 845 bytes (41%)
1203 for local variables

So with the 1K buffer you've still got 179 bytes of RAM left over. As long as none of the other libraries make large run time allocations of RAM you ought to be okay.

One easy change to buy yourself some more RAM is to use the F() macro on any string constants in Serial.print(...) and println(...) statements, like so:

Serial.print(F("Temperature: "));

That prevents the compiler from copying the string constant into RAM. Doing it on that line alone saves you 13 bytes of RAM. Do it to all the string constants you're printing and you could likely save 100+ bytes. And if RAM really is the issue, that might be enough to get things working.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.