// OLED VOLTMETER.
// By moty22.co.uk
// PIC12F675

#include <htc.h>  // default library
#include "oled_font.c"

#pragma config WDTE=OFF, MCLRE=OFF, BOREN=OFF, FOSC=INTRCIO, CP=OFF, CPD=OFF    //,INTRCIO

#define _XTAL_FREQ 4000000
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

#define SCL GP4 //pin3
#define SDA GP5 //pin2

//prototypes
void command( unsigned char comm);
void oled_init();
void clrScreen();
void sendData(unsigned char dataB);
void startBit(void);
void stopBit(void);
void clock(void);
void drawChar2(char fig, unsigned char y, unsigned char x);

unsigned char addr=0x78;  //0b0111 1000

void main(void){
        unsigned char d[4];
    unsigned int count;

        // PIC I/O init
    CMCON = 0b111;              //comparator off
    TRISIO = 0b00001111;   //SCL, SDA, input
    ANSEL = 0b01010100;   // 101=Fosc/16, 0100=AN2 GP2
        ADCON0 = 0b10001001;    //1=right justified, 0,0,0, 10=AN2, 0, 1 =ADC on
    SCL=1;
    SDA=1;

    __delay_ms(500);
    oled_init();

    clrScreen();       // clear screen
    drawChar2(10, 1, 7);  //V
    drawChar2(12, 1, 2);  //.

        while(1) {
        GO_DONE = 1;                            //start ADC
        while(GO_DONE){};

        count=((ADRESH << 8) + ADRESL)*5;  // (0 - 1023) * 5 = 0 - 5115

        d[0]=(count/1000) %10;  //digit on left
        d[1]=(count/100) %10;
        d[2]=(count/10) %10;
        d[3]=count %10;        //  digit on right

        drawChar2(d[0], 1, 1);
        drawChar2(d[1], 1, 3);
        drawChar2(d[2], 1, 4);
        drawChar2(d[3], 1, 5);

        __delay_ms(500);
        }

}

   //size 2 chars
void drawChar2(char fig, unsigned char y, unsigned char x)
{
    unsigned char i, line, btm, top;    //

    command(0x20);    // vert mode
    command(0x01);

    command(0x21);     //col addr
    command(13 * x); //col start
    command(13 * x + 9);  //col end
    command(0x22);    //0x22
    command(y); // Page start
    command(y+1); // Page end

    startBit();
    sendData(addr);            // address
    sendData(0x40);

    for (i = 0; i < 5; i++){
        line=font[5*(fig)+i]; // font [5 x 5 + i] = 0x27, 0x45, 0x45, 0x45, 0x39
        btm=0; top=0;

// 128x32 OLED has 4 pages (0-3) starting in column 0 and ending in column 127  
// top = top page (page1 y) of 5 columns wide and 8 rows deep
// btm = bottom page (page2 y+1) of 5 columns wide and 8 rows deep
// when 1 byte is written the pointer moves to the next column automatically

// the 4 bits on the left determine the top page column
// the 4 bits on the right determine the bottom page column
// 0x93 means  top page from top downwards white,white,white,black  and bottom page white,black,black,white
if(line & 8) {top +=192;}  //
if(line & 4) {top +=48;}   //
if(line & 2) {top +=12;}   //
if(line & 1) {top +=3;}  //

if(line & 128) {btm +=192;} //
if(line & 64) {btm +=48;} //
if(line & 32) {btm +=12;} //
if(line & 16) {btm +=3;}  //

/* original code
            // expend char
        if(line & 64) {btm +=192;} // line & 0100  bottom + 192
        if(line & 32) {btm +=48;}  // line & 0010 bottom + 48 ->  48
        if(line & 16) {btm +=12;}  // line & 0001 bottom + 12
        if(line & 8) {btm +=3;}    // line & 1000 bottom + 3

        if(line & 4) {top +=192;}  // line & 0100 top + 192  -> 252
        if(line & 2) {top +=48;}  // line & 0010 top + 48
        if(line & 1) {top +=12;}  // line & 0001 top + 12
*/
         sendData(top); //top page (page 1)
         sendData(btm);  // page below top (page 2)
         sendData(top);  // top page, but next column
         sendData(btm);  // bottom page, but next column
         //  this means 1 byte for 2 columns in 2 pages (16 bits)
    }
    stopBit();

    command(0x20);      // horizontal mode
    command(0x00);

}

void clrScreen()    //fill screen with 0
{
    unsigned char y, i;

    for ( y = 0; y < 8; y++ ) {
        command(0x21);     //col addr
        command(0); //col start
        command(127);  //col end
        command(0x22);    //0x22
        command(y); // Page start
        command(y+1); // Page end
        startBit();
        sendData(addr);            // address
        sendData(0x40);
        for (i = 0; i < 128; i++){
             sendData(0x00);
        }
        stopBit();
    }
}

//Software I2C
void sendData(unsigned char dataB)
{
    for(unsigned char b=0;b<8;b++){
       SDA=(dataB >> (7-b)) % 2;
       clock();
    }
    TRISIO5=1;   //SDA input
    clock();
    __delay_us(5);
    TRISIO5=0;   //SDA output

}

void clock(void)
{
   __delay_us(1);
   SCL=1;
   __delay_us(5);
   SCL=0;
   __delay_us(1);
}

void startBit(void)
{
    SDA=0;
    __delay_us(5);
    SCL=0;

}

void stopBit(void)
{
    SCL=1;
    __delay_us(5);
    SDA=1;

}

void command( unsigned char comm){

    startBit();
    sendData(addr);            // address
    sendData(0x00);
    sendData(comm);             // command code
    stopBit();
}

void oled_init() {

    command(0xAE);   // DISPLAYOFF
    command(0x8D);         // CHARGEPUMP *
    command(0x14);     //0x14-pump on
    command(0x20);         // MEMORYMODE
    command(0x0);      //0x0=horizontal, 0x01=vertical, 0x02=page
    command(0xA1);        //SEGREMAP * A0/A1=top/bottom
    command(0xC8);     //COMSCANDEC * C0/C8=left/right
    command(0xDA);         // SETCOMPINS *
    command(0x22);   //0x22=4rows, 0x12=8rows
    command(0x81);        // SETCONTRAST
    command(0xFF);     //0x8F
    //next settings are set by default
//    command(0xD5);  //SETDISPLAYCLOCKDIV
//    command(0x80);
//    command(0xA8);       // SETMULTIPLEX
//    command(0x3F);     //0x1F
//    command(0xD3);   // SETDISPLAYOFFSET
//    command(0x0);
//    command(0x40); // SETSTARTLINE
//    command(0xD9);       // SETPRECHARGE
//    command(0xF1);
//    command(0xDB);      // SETVCOMDETECT
//    command(0x40);
//    command(0xA4);     // DISPLAYALLON_RESUME
 //   command(0xA6);      // NORMALDISPLAY
    command(0xAF);          //DISPLAYON

}


// ----oled_font.c-----------------------
static const unsigned char  font[] = {
0x7E,0xC1,0x81,0x83,0x7E,
0x82,0x83,0xFF,0x80,0x80,
0xC2,0xA1,0x91,0x89,0x46,
0x42,0x81,0x99,0x99,0x7E,
0x18,0x14,0x92,0xFF,0x90,
0xC7,0x89,0x89,0x99,0x70,
0xEE,0x91,0x91,0x91,0x70,
0x01,0xC1,0x31,0x19,0x06,
0x66,0x99,0x99,0x99,0x66,
0x0E,0x91,0x91,0x91,0x7E,
0x0C,0x30,0xC0,0x30,0x0C,
0x00, 0x00, 0x00, 0x00, 0x00,// (space)
0x00,0xC0,0xC0,0xC0,0x00
};