Snippets

Peter Scargill Experimental NANO OLED based Power Supply Control

You are viewing an old version of this snippet. View the current version.
Revised by Peter Scargill 7c939c4
// See blog entry here http://tech.scargill.net/gpio-the-hard-way/

#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"

// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C

SSD1306AsciiWire oled;

#define LIGHT 12
#define RELAY 11
#define WARNING 10

#define WAITING 60
#define ONDELAY 20

#define SWITCHON 3.7
#define SWITCHOFF 3.1

uint32_t secs=0;
uint32_t upSecs=0;
uint32_t downSecs=0;

void LcdP(char *fmt, ...)
{
  char buf[128]; // resulting string limited to 128 chars
  va_list args;
  va_start(args, fmt);
  vsnprintf(buf, 128, fmt, args);
  va_end(args);
  oled.print(buf);
}

uint32_t mymillis = 0;
uint8_t lightState = 0;
uint8_t state = 0; // 0 is power up, 1 is on, 2 is turning off
float vol;
uint8_t onDelay = 0;

uint16_t lightOnSet = 2;
uint16_t lightOffSet = 1022;

float offVoltage = SWITCHOFF;
float onVoltage = SWITCHON;

float average=0;

char *theState = "standby";

float voltage()
{
  // read the input on analog pin 0
  int sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float vols = sensorValue * (5.0 / 1023.0);
  // print out the value you read:
  return (vols);
}

void p(char *fmt, ...)
{
  char buf[128]; // resulting string limited to 128 chars
  va_list args;
  va_start(args, fmt);
  vsnprintf(buf, 128, fmt, args);
  va_end(args);
  Serial.print(buf);
}

void gotoXY(int x, int y)
{
  oled.setCursor(x,y);
}

//------------------------------------------------------------------------------
void setup() {
  Wire.begin();         
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
  oled.set400kHz();  
  oled.setFont(Adafruit5x7);  

  uint32_t m = micros();

  Serial.begin(57600);
  digitalWrite(LIGHT, LOW);
  digitalWrite(RELAY, LOW);
  digitalWrite(WARNING, LOW);
  pinMode(LIGHT, OUTPUT);
  pinMode(RELAY, OUTPUT);
  pinMode(WARNING, OUTPUT);

  average=voltage();
  
  oled.clear(); 
  LcdP("Init....\r\n");
  //oled.println("Hello world!");
 // oled.println("A long line");
  //oled.println();
  //oled.set2X();
 // oled.println("2X demo");
 // oled.set1X();
  //oled.print("\nmicros: ");
 // oled.print(micros() - m);
}
//------------------------------------------------------------------------------
void loop()
{
  // put your main code here, to run repeatedly:

  if (mymillis <= millis())
  {
    vol=voltage();
    average+=(vol/16.0);
    average=average*16.0/17.0;
    vol=average;
    if (state == 0)
    {
      if (vol > onVoltage)
      {
        if (onDelay == 0)
        {
          onDelay = ONDELAY*2;
          theState = "starting";
        }
      }
    }
    else if (state == 1)
    {  
      if (vol < offVoltage)
      {
        state = (WAITING*2) + 2;
        theState = "warning ";
      }
    }
    else if (state > 2)
    {
      digitalWrite(WARNING, HIGH);
      state--;
      if (state == 2)
      {
        state = 0;
        digitalWrite(RELAY, LOW); downSecs=0;
        //analogWrite(PIN_PWM,255); // only 3v3 intended so this will likely do
        theState = "standby ";
      }
    }
    else
      digitalWrite(WARNING, LOW);

    if (vol > onVoltage)
    {
      if (onDelay)
      {
        if (--onDelay == 0)
        {
          state = 1;
          //analogWrite(PIN_PWM,128); // only 3v3 intended so this will likely do
          theState = "active  "; upSecs=0;
        }
      }
    }
else
  {
      if (onDelay)
      {
        onDelay=0; theState = "standby "; state=0;
      }    
  }
  
    if (lightState == 0)
    {
     p("{\"voltage\":");
      Serial.print(vol);
      p(",\"status\":\"%s\"}\r\n", theState); // sadly printf here does not support floats
      
      gotoXY(0,0); LcdP("POWER SUPPLY CONTROL");
      
      gotoXY(0,2); LcdP("Current volts: %d.%d",int(vol),((int(vol*100))%100)/10);
      gotoXY(0,3); LcdP("State: %s",theState);
      gotoXY(0,4); LcdP("High: %d.%d Low: %d.%d ",int(onVoltage),((int(onVoltage*100))%100)/10,int(offVoltage),((int(offVoltage*100))%100)/10);
      gotoXY(0,5); LcdP("On:    %05ld:%02ld:%02ld",upSecs/3600,(upSecs%3600)/60, upSecs%60);      
      gotoXY(0,6); LcdP("Off:   %05ld:%02ld:%02ld",downSecs/3600,(downSecs%3600)/60, downSecs%60);  
      gotoXY(0,7); LcdP("Total: %05ld:%02ld:%02ld",secs/3600,(secs%3600)/60, secs%60);

      lightState = 1;
      digitalWrite(LIGHT, HIGH);
      switch (state)
      {
      case 0:
        if (onDelay)
        {
          lightOnSet = 80;
          lightOffSet = 944;
        }
        else
        {
          lightOnSet = 1;
          lightOffSet = 1023;
        }
        digitalWrite(RELAY, LOW);
        break; // battery is low
      case 1:
        lightOnSet = 980;
        lightOffSet = 44;
        digitalWrite(RELAY, HIGH);
        break; // battery is ok
      default:
        lightOnSet = 512;
        lightOffSet = 512;
        break; // intermediate state;
      }
      mymillis = millis() + lightOnSet;
    }
    else
    {  
      lightState = 0;
      digitalWrite(LIGHT, LOW);
      mymillis = millis() + lightOffSet;
      secs++;
      if (state==1) upSecs++; else downSecs++;
    }
  }
}
HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.