Connecting IIC/SPI OLED to Arduino Nano (BIG NOOB)

Hey Everyone,

We'll start off with I have no idea what im doing, or the correct search terms to solve my problems.

I have followed a guide to build a fuel content sensor, the board works and the car's ecu can read the output from the board, great!

However, I would also like to remote mount a small oled to display the data.

This code I am using from the guide.

/*******************************************************
This program will sample a 50-150hz signal depending on ethanol 
content, and output a 0-5V signal via PWM.
The LCD (for those using an Arduino Uno + LCD shield) will display ethanol content, hz input, mv output, fuel temp

Connect PWM output to TGV. 3.3kOhm resistor works fine.

Input pin 8 (PB0) ICP1 on Atmega328
Output pin 3 or 11, defined below

If LCD Keypad shield is used, solder jumper from Pin 8 - Pin 2,
and snip leg from pin 8 http://i.imgur.com/KdlLmye.png
********************************************************/

// include the library code:
#include <LiquidCrystal.h> //LCD plugin

// initialize the library with the numbers of the interface pins 
LiquidCrystal lcd(2, 9, 4, 5, 6, 7); //LCD Keypad Shield

int inpPin = 8;     //define input pin to 8
int outPin = 11;    //define PWM output, possible pins with LCD and 32khz freq. are 3 and 11 (Nano and Uno)

//Define global variables
volatile uint16_t revTick;    //Ticks per revolution
uint16_t pwm_output  = 0;     //integer for storing PWM value (0-255 value)
int HZ;                   //unsigned 16bit integer for storing HZ input
int ethanol = 0;              //Store ethanol percentage here
float expectedv;              //store expected voltage here - range for typical GM sensors is usually 0.5-4.5v

int duty;                     //Duty cycle (0.0-100.0)
float period;                 //Store period time here (eg.0.0025 s)
float temperature = 0;        //Store fuel temperature here
int fahr = 0;
int cels = 0;
static long highTime = 0;
static long lowTime = 0;
static long tempPulse;

void setupTimer()	 // setup timer1
{           
	TCCR1A = 0;      // normal mode
	TCCR1B = 132;    // (10000100) Falling edge trigger, Timer = CPU Clock/256, noise cancellation on
	TCCR1C = 0;      // normal mode
	TIMSK1 = 33;     // (00100001) Input capture and overflow interupts enabled
	TCNT1 = 0;       // start from 0
}

ISR(TIMER1_CAPT_vect)    // PULSE DETECTED!  (interrupt automatically triggered, not called by main program)
{
	revTick = ICR1;      // save duration of last revolution
	TCNT1 = 0;	     // restart timer for next revolution
}

ISR(TIMER1_OVF_vect)    // counter overflow/timeout
{ revTick = 0; }        // Ticks per second = 0


void setup()
{
  Serial.begin(9600);
  pinMode(inpPin,INPUT);
  setPwmFrequency(outPin,1); //Modify frequency on PWM output
 setupTimer();
   // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Initial screen formatting
  lcd.setCursor(0, 0);
  lcd.print("Ethanol:    %");
  lcd.setCursor(0, 1);
  lcd.print("     Hz       C");
}
 
void loop()
{
  getfueltemp(inpPin); //read fuel temp from input duty cycle
  
  if (revTick > 0) // Avoid dividing by zero, sample in the HZ
		{HZ = 62200 / revTick;}     // 3456000ticks per minute, 57600 per second 
		else                     
		{HZ = 0;}                   //needs real sensor test to determine correct tickrate

  //calculate ethanol percentage
		if (HZ > 50) // Avoid dividing by zero
		{ethanol = (HZ-50);}
		else
		{ethanol = 0;}

if (ethanol > 99) // Avoid overflow in PWM
{ethanol = 99;}

  expectedv = ((((HZ-50.0)*0.01)*4)+0.5);
  //Screen calculations
  pwm_output = 1.1 * (255 * (expectedv/5.0)); //calculate output PWM for ECU
  
  lcd.setCursor(10, 0);
  lcd.print(ethanol);
  
  lcd.setCursor(2, 1);
  lcd.print(HZ);
  
  lcd.setCursor(8, 1); 
  lcd.print(temperature); //Use this for celsius

  //PWM output
  analogWrite(outPin, pwm_output); //write the PWM value to output pin

  delay(100);  //make screen more easily readable by not updating it too often

  Serial.println(ethanol);
  Serial.println(pwm_output);
  Serial.println(expectedv);
  Serial.println(HZ);
  delay(1000);

  
}

void getfueltemp(int inpPin){ //read fuel temp from input duty cycle
highTime = 0;
lowTime = 0;

tempPulse = pulseIn(inpPin,HIGH);
  if(tempPulse>highTime){
  highTime = tempPulse;
  }

tempPulse = pulseIn(inpPin,LOW);
  if(tempPulse>lowTime){
  lowTime = tempPulse;
  }

duty = ((100*(highTime/(double (lowTime+highTime))))); //Calculate duty cycle (integer extra decimal)
float T = (float(1.0/float(HZ)));             //Calculate total period time
float period = float(100-duty)*T;             //Calculate the active period time (100-duty)*T
float temp2 = float(10) * float(period);      //Convert ms to whole number
temperature = ((40.25 * temp2)-81.25);        //Calculate temperature for display (1ms = -40, 5ms = 80)
int cels = int(temperature);
cels = cels*0.1;
float fahrtemp = ((temperature*1.8)+32);
fahr = fahrtemp*0.1;

}

void setPwmFrequency(int pin, int divisor) { //This code snippet raises the timers linked to the PWM outputs
  byte mode;                                 //This way the PWM frequency can be raised or lowered. Prescaler of 1 sets PWM output to 32KHz (pin 3, 11)
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x7; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }
}

And this is the screen I have

The display GND VCC CLK MOSI RES DC C5 but all the guides I can find show the screens with SCL/SDA

There is this code which i belive is for an oled screen, but im unsure of what wires from the screen I need to connect to A4 and A5

// Adafruit_SSD1306 - Version: Latest 
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

int inpPin = 8;

//Define global variables
volatile uint16_t revTick;    //Ticks per revolution
uint16_t pwm_output  = 0;      //integer for storing PWM value (0-255 value)
int HZ = 0;                  //unsigned 16bit integer for storing HZ input
int ethanol = 0;              //Store ethanol percentage here
float expectedv;              //store expected voltage here - range for typical GM sensors is usually 0.5-4.5v
uint16_t voltage = 0;              //store display millivoltage here (0-5000)
//temperature variables
int duty;                     //Duty cycle (0.0-100.0)
float period;                 //Store period time here (eg.0.0025 s)
float temperature = 0;        //Store fuel temperature here
int fahr = 0;
int cels = 0;
int celstemp = 0;
float fahrtemp = 0;
static long highTime = 0;
static long lowTime = 0;
static long tempPulse;

void setupTimer()	 // setup timer1
{           
	TCCR1A = 0;      // normal mode
	TCCR1B = 132;    // (10000100) Falling edge trigger, Timer = CPU Clock/256, noise cancellation on
	TCCR1C = 0;      // normal mode
	TIMSK1 = 33;     // (00100001) Input capture and overflow interupts enabled
	
	TCNT1 = 0;       // start from 0
}

ISR(TIMER1_CAPT_vect)    // PULSE DETECTED!  (interrupt automatically triggered, not called by main program)
{
	revTick = ICR1;      // save duration of last revolution
	TCNT1 = 0;	     // restart timer for next revolution
}

ISR(TIMER1_OVF_vect)    // counter overflow/timeout
{ revTick = 0; }        // Ticks per second = 0



void setup() {
  setupTimer();
  Serial.begin(9600);

  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
  // init done
}

void loop() {
  getfueltemp(inpPin); //read fuel temp from input duty cycle
  
  if (revTick > 0) // Avoid dividing by zero, sample in the HZ
  		{HZ = 62200 / revTick;}     // 3456000ticks per minute, 57600 per second 
  		else                        // 62200 calibrated for more accuracy
  		{HZ = 0;}                   
  
    //calculate ethanol percentage
  		if (HZ > 50) // Avoid dividing by zero
  		{ethanol = HZ-50;}
  		else
  		{ethanol = 0;}
  
  if (ethanol > 99) // Avoid overflow in PWM
  {ethanol = 99;}
  
    //Screen calculations
    display.display();
    display.clearDisplay();
    display.setCursor(0,16);
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.print("Eth:  ");
    display.print(ethanol);
    display.print("%");
    display.setCursor(0,36);
    display.print("Temp: ");
    display.print(cels);
    display.print("C");
    
    delay(250);
}

void getfueltemp(int inpPin){ //read fuel temp from input duty cycle
  highTime = 0;
  lowTime = 0;
  
  tempPulse = pulseIn(inpPin,HIGH);
    if(tempPulse>highTime){
    highTime = tempPulse;
    }
  
  tempPulse = pulseIn(inpPin,LOW);
    if(tempPulse>lowTime){
    lowTime = tempPulse;
    }
  
  duty = ((100*(highTime/(double (lowTime+highTime))))); //Calculate duty cycle (integer extra decimal)
  float T = (float(1.0/float(HZ)));             //Calculate total period time
  float period = float(100-duty)*T;             //Calculate the active period time (100-duty)*T
  float temp2 = float(10) * float(period);      //Convert ms to whole number
  temperature = ((40.25 * temp2)-81.25);        //Calculate temperature for display (1ms = -40, 5ms = 80)
  celstemp = int(temperature);
  cels = celstemp;
  fahrtemp = ((temperature*1.8)+32);
  fahr = fahrtemp;
}

There is already code for a screen but I belive it is for a different screen.

Any help would be apprecited in getting this working.

So you have a working I2C LCD device, and want to add your remote OLED? Problem is, your OLED is SPI, not I2C, so it will need to be connected to the SPI pins (10,11,13 I think), and VCC and GND. That's on the hardware side.
Software side, you'll need an SPI library for OLED. No experience here, but there must be some.
See the manual pages here:

(edit - pin number correction, and reference to manual)

Thank you for your reply, would it be better to just buy a compatible screen like this?

Easier, probably, but what you have will work IF you have the available pins. If you're running out of pins due to other devices, yes, an I2C OLED would be better. HOWEVER, be advised that both SPI and I2C busses have their length limitations, somewhere between 30 cm and 10m depending on conditions, design, and luck.

From your Link use U8G2 for that Oled.

image

There should be a JUMPER for IIC/ SPI selection the Oled is sold as SPI.