Arduino_STM32/STM32F1/libraries/OLED_I2C/OLED_I2C.cpp

863 lines
14 KiB
C++

/*
OLED_I2C.cpp - Arduino/chipKit library support for 128x64 pixel SSD1306 OLEDs
Copyright (C)2015 Rinky-Dink Electronics, Henning Karlsen. All right reserved
This library has been made to make it easy to use 128x64 pixel OLED displays
based on the SSD1306 controller chip with an Arduino or a chipKit.
You can always find the latest version of the library at
http://www.RinkyDinkElectronics.com/
This library is free software; you can redistribute it and/or
modify it under the terms of the CC BY-NC-SA 3.0 license.
Please see the included documents for further information.
Commercial use of this library requires you to buy a license that
will allow commercial use. This includes using the library,
modified or not, as a tool to sell products.
The license applies to all part of the library including the
examples and tools supplied with the library.
*/
#include "OLED_I2C.h"
#if defined(__AVR__)
#include <avr/pgmspace.h>
#include "hardware/avr/HW_AVR.h"
#elif defined(__PIC32MX__)
#pragma message("Compiling for PIC32 Architecture...")
#include "hardware/pic32/HW_PIC32.h"
/*
#elif defined(__arm__)
#pragma message("Compiling for ARM Architecture...")
#include "hardware/arm/HW_ARM.h"
*/
#elif defined (__STM32F1__)
#pragma message("Compiling for STM32F1 Architecture...")
#include "hardware/arm/HW_STM32.h"
#endif
OLED::OLED(uint8_t data_pin, uint8_t sclk_pin, uint8_t rst_pin)
{
_sda_pin = data_pin;
_scl_pin = sclk_pin;
_rst_pin = rst_pin;
}
OLED::OLED(uint8_t data_pin, uint8_t sclk_pin)
{
_sda_pin = data_pin;
_scl_pin = sclk_pin;
_rst_pin = RST_NOT_IN_USE;
}
void OLED::begin()
{
if (_rst_pin != RST_NOT_IN_USE)
{
pinMode(_rst_pin, OUTPUT);
digitalWrite(_rst_pin, HIGH);
delay(1);
digitalWrite(_rst_pin, LOW);
delay(10);
digitalWrite(_rst_pin, HIGH);
}
#if defined(SDA1) & defined(SCL1)
if (((_sda_pin == SDA) and (_scl_pin == SCL)) or ((_sda_pin == SDA1) and (_scl_pin == SCL1)))
#else
if ((_sda_pin == SDA) and (_scl_pin == SCL))
#endif
{
_use_hw = true;
#pragma message("I2C HW mode enabled")
_initTWI();
}
else
{
_use_hw = false;
pinMode(_scl_pin, OUTPUT);
#pragma message("SCL pinmode OUTPUT")
}
_sendTWIcommand(SSD1306_DISPLAY_OFF);
_sendTWIcommand(SSD1306_SET_DISPLAY_CLOCK_DIV_RATIO);
_sendTWIcommand(0x80);
_sendTWIcommand(SSD1306_SET_MULTIPLEX_RATIO);
_sendTWIcommand(0x3F);
_sendTWIcommand(SSD1306_SET_DISPLAY_OFFSET);
_sendTWIcommand(0x0);
_sendTWIcommand(SSD1306_SET_START_LINE | 0x0);
_sendTWIcommand(SSD1306_CHARGE_PUMP);
_sendTWIcommand(0x14);
_sendTWIcommand(SSD1306_MEMORY_ADDR_MODE);
_sendTWIcommand(0x00);
_sendTWIcommand(SSD1306_SET_SEGMENT_REMAP | 0x1);
_sendTWIcommand(SSD1306_COM_SCAN_DIR_DEC);
_sendTWIcommand(SSD1306_SET_COM_PINS);
_sendTWIcommand(0x12);
_sendTWIcommand(SSD1306_SET_CONTRAST_CONTROL);
_sendTWIcommand(0xCF);
_sendTWIcommand(SSD1306_SET_PRECHARGE_PERIOD);
_sendTWIcommand(0xF1);
_sendTWIcommand(SSD1306_SET_VCOM_DESELECT);
_sendTWIcommand(0x40);
_sendTWIcommand(SSD1306_DISPLAY_ALL_ON_RESUME);
_sendTWIcommand(SSD1306_NORMAL_DISPLAY);
_sendTWIcommand(SSD1306_DISPLAY_ON);
clrScr();
update();
cfont.font=0;
}
void OLED::clrScr()
{
memset(scrbuf, 0, 1024);
}
void OLED::fillScr()
{
memset(scrbuf, 255, 1024);
}
void OLED::setBrightness(uint8_t value)
{
_sendTWIcommand(SSD1306_SET_CONTRAST_CONTROL);
_sendTWIcommand(value);
}
void OLED::invert(bool mode)
{
if (mode==true)
_sendTWIcommand(SSD1306_INVERT_DISPLAY);
else
_sendTWIcommand(SSD1306_NORMAL_DISPLAY);
}
void OLED::setPixel(uint16_t x, uint16_t y)
{
int by, bi;
if ((x>=0) and (x<128) and (y>=0) and (y<64))
{
by=((y/8)*128)+x;
bi=y % 8;
scrbuf[by]=scrbuf[by] | (1<<bi);
}
}
void OLED::clrPixel(uint16_t x, uint16_t y)
{
int by, bi;
if ((x>=0) and (x<128) and (y>=0) and (y<64))
{
by=((y/8)*128)+x;
bi=y % 8;
scrbuf[by]=scrbuf[by] & ~(1<<bi);
}
}
void OLED::invPixel(uint16_t x, uint16_t y)
{
int by, bi;
if ((x>=0) and (x<128) and (y>=0) and (y<64))
{
by=((y/8)*128)+x;
bi=y % 8;
if ((scrbuf[by] & (1<<bi))==0)
scrbuf[by]=scrbuf[by] | (1<<bi);
else
scrbuf[by]=scrbuf[by] & ~(1<<bi);
}
}
void OLED::invertText(bool mode)
{
if (mode==true)
cfont.inverted=1;
else
cfont.inverted=0;
}
void OLED::print(char *st, int x, int y)
{
unsigned char ch;
int stl;
stl = strlen(st);
if (x == RIGHT)
x = 128-(stl*cfont.x_size);
if (x == CENTER)
x = (128-(stl*cfont.x_size))/2;
for (int cnt=0; cnt<stl; cnt++)
_print_char(*st++, x + (cnt*(cfont.x_size)), y);
}
void OLED::print(String st, int x, int y)
{
char buf[st.length()+1];
st.toCharArray(buf, st.length()+1);
print(buf, x, y);
}
void OLED::printNumI(long num, int x, int y, int length, char filler)
{
char buf[25];
char st[27];
boolean neg=false;
int c=0, f=0;
if (num==0)
{
if (length!=0)
{
for (c=0; c<(length-1); c++)
st[c]=filler;
st[c]=48;
st[c+1]=0;
}
else
{
st[0]=48;
st[1]=0;
}
}
else
{
if (num<0)
{
neg=true;
num=-num;
}
while (num>0)
{
buf[c]=48+(num % 10);
c++;
num=(num-(num % 10))/10;
}
buf[c]=0;
if (neg)
{
st[0]=45;
}
if (length>(c+neg))
{
for (int i=0; i<(length-c-neg); i++)
{
st[i+neg]=filler;
f++;
}
}
for (int i=0; i<c; i++)
{
st[i+neg+f]=buf[c-i-1];
}
st[c+neg+f]=0;
}
print(st,x,y);
}
void OLED::printNumF(double num, byte dec, int x, int y, char divider, int length, char filler)
{
char st[27];
boolean neg=false;
if (num<0)
neg = true;
_convert_float(st, num, length, dec);
if (divider != '.')
{
for (int i=0; i<sizeof(st); i++)
if (st[i]=='.')
st[i]=divider;
}
if (filler != ' ')
{
if (neg)
{
st[0]='-';
for (int i=1; i<sizeof(st); i++)
if ((st[i]==' ') || (st[i]=='-'))
st[i]=filler;
}
else
{
for (int i=0; i<sizeof(st); i++)
if (st[i]==' ')
st[i]=filler;
}
}
print(st,x,y);
}
void OLED::_print_char(unsigned char c, int x, int y)
{
if ((cfont.y_size % 8) == 0)
{
int font_idx = ((c - cfont.offset)*(cfont.x_size*(cfont.y_size/8)))+4;
for (int rowcnt=0; rowcnt<(cfont.y_size/8); rowcnt++)
{
for(int cnt=0; cnt<cfont.x_size; cnt++)
{
for (int b=0; b<8; b++)
if ((fontbyte(font_idx+cnt+(rowcnt*cfont.x_size)) & (1<<b))!=0)
if (cfont.inverted==0)
setPixel(x+cnt, y+(rowcnt*8)+b);
else
clrPixel(x+cnt, y+(rowcnt*8)+b);
else
if (cfont.inverted==0)
clrPixel(x+cnt, y+(rowcnt*8)+b);
else
setPixel(x+cnt, y+(rowcnt*8)+b);
}
}
}
else
{
int font_idx = ((c - cfont.offset)*((cfont.x_size*cfont.y_size/8)))+4;
int cbyte=fontbyte(font_idx);
int cbit=7;
for (int cx=0; cx<cfont.x_size; cx++)
{
for (int cy=0; cy<cfont.y_size; cy++)
{
if ((cbyte & (1<<cbit)) != 0)
if (cfont.inverted==0)
setPixel(x+cx, y+cy);
else
clrPixel(x+cx, y+cy);
else
if (cfont.inverted==0)
clrPixel(x+cx, y+cy);
else
setPixel(x+cx, y+cy);
cbit--;
if (cbit<0)
{
cbit=7;
font_idx++;
cbyte=fontbyte(font_idx);
}
}
}
}
}
void OLED::setFont(uint8_t* font)
{
cfont.font=font;
cfont.x_size=fontbyte(0);
cfont.y_size=fontbyte(1);
cfont.offset=fontbyte(2);
cfont.numchars=fontbyte(3);
cfont.inverted=0;
}
void OLED::drawHLine(int x, int y, int l)
{
int by, bi;
if ((x>=0) and (x<128) and (y>=0) and (y<64))
{
for (int cx=0; cx<l; cx++)
{
by=((y/8)*128)+x;
bi=y % 8;
scrbuf[by+cx] |= (1<<bi);
}
}
}
void OLED::clrHLine(int x, int y, int l)
{
int by, bi;
if ((x>=0) and (x<128) and (y>=0) and (y<64))
{
for (int cx=0; cx<l; cx++)
{
by=((y/8)*128)+x;
bi=y % 8;
scrbuf[by+cx] &= ~(1<<bi);
}
}
}
void OLED::drawVLine(int x, int y, int l)
{
int by, bi;
if ((x>=0) and (x<128) and (y>=0) and (y<64))
{
for (int cy=0; cy<l; cy++)
{
setPixel(x, y+cy);
}
}
}
void OLED::clrVLine(int x, int y, int l)
{
int by, bi;
if ((x>=0) and (x<128) and (y>=0) and (y<64))
{
for (int cy=0; cy<l; cy++)
{
clrPixel(x, y+cy);
}
}
}
void OLED::drawLine(int x1, int y1, int x2, int y2)
{
int tmp;
double delta, tx, ty;
double m, b, dx, dy;
if (((x2-x1)<0))
{
tmp=x1;
x1=x2;
x2=tmp;
tmp=y1;
y1=y2;
y2=tmp;
}
if (((y2-y1)<0))
{
tmp=x1;
x1=x2;
x2=tmp;
tmp=y1;
y1=y2;
y2=tmp;
}
if (y1==y2)
{
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
drawHLine(x1, y1, x2-x1);
}
else if (x1==x2)
{
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
drawVLine(x1, y1, y2-y1);
}
else if (abs(x2-x1)>abs(y2-y1))
{
delta=(double(y2-y1)/double(x2-x1));
ty=double(y1);
if (x1>x2)
{
for (int i=x1; i>=x2; i--)
{
setPixel(i, int(ty+0.5));
ty=ty-delta;
}
}
else
{
for (int i=x1; i<=x2; i++)
{
setPixel(i, int(ty+0.5));
ty=ty+delta;
}
}
}
else
{
delta=(float(x2-x1)/float(y2-y1));
tx=float(x1);
if (y1>y2)
{
for (int i=y2+1; i>y1; i--)
{
setPixel(int(tx+0.5), i);
tx=tx+delta;
}
}
else
{
for (int i=y1; i<y2+1; i++)
{
setPixel(int(tx+0.5), i);
tx=tx+delta;
}
}
}
}
void OLED::clrLine(int x1, int y1, int x2, int y2)
{
int tmp;
double delta, tx, ty;
double m, b, dx, dy;
if (((x2-x1)<0))
{
tmp=x1;
x1=x2;
x2=tmp;
tmp=y1;
y1=y2;
y2=tmp;
}
if (((y2-y1)<0))
{
tmp=x1;
x1=x2;
x2=tmp;
tmp=y1;
y1=y2;
y2=tmp;
}
if (y1==y2)
{
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
clrHLine(x1, y1, x2-x1);
}
else if (x1==x2)
{
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
clrVLine(x1, y1, y2-y1);
}
else if (abs(x2-x1)>abs(y2-y1))
{
delta=(double(y2-y1)/double(x2-x1));
ty=double(y1);
if (x1>x2)
{
for (int i=x1; i>=x2; i--)
{
clrPixel(i, int(ty+0.5));
ty=ty-delta;
}
}
else
{
for (int i=x1; i<=x2; i++)
{
clrPixel(i, int(ty+0.5));
ty=ty+delta;
}
}
}
else
{
delta=(float(x2-x1)/float(y2-y1));
tx=float(x1);
if (y1>y2)
{
for (int i=y2+1; i>y1; i--)
{
clrPixel(int(tx+0.5), i);
tx=tx+delta;
}
}
else
{
for (int i=y1; i<y2+1; i++)
{
clrPixel(int(tx+0.5), i);
tx=tx+delta;
}
}
}
}
void OLED::drawRect(int x1, int y1, int x2, int y2)
{
int tmp;
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
drawHLine(x1, y1, x2-x1);
drawHLine(x1, y2, x2-x1);
drawVLine(x1, y1, y2-y1);
drawVLine(x2, y1, y2-y1+1);
}
void OLED::clrRect(int x1, int y1, int x2, int y2)
{
int tmp;
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
clrHLine(x1, y1, x2-x1);
clrHLine(x1, y2, x2-x1);
clrVLine(x1, y1, y2-y1);
clrVLine(x2, y1, y2-y1+1);
}
void OLED::drawRoundRect(int x1, int y1, int x2, int y2)
{
int tmp;
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
if ((x2-x1)>4 && (y2-y1)>4)
{
setPixel(x1+1,y1+1);
setPixel(x2-1,y1+1);
setPixel(x1+1,y2-1);
setPixel(x2-1,y2-1);
drawHLine(x1+2, y1, x2-x1-3);
drawHLine(x1+2, y2, x2-x1-3);
drawVLine(x1, y1+2, y2-y1-3);
drawVLine(x2, y1+2, y2-y1-3);
}
}
void OLED::clrRoundRect(int x1, int y1, int x2, int y2)
{
int tmp;
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
if ((x2-x1)>4 && (y2-y1)>4)
{
clrPixel(x1+1,y1+1);
clrPixel(x2-1,y1+1);
clrPixel(x1+1,y2-1);
clrPixel(x2-1,y2-1);
clrHLine(x1+2, y1, x2-x1-3);
clrHLine(x1+2, y2, x2-x1-3);
clrVLine(x1, y1+2, y2-y1-3);
clrVLine(x2, y1+2, y2-y1-3);
}
}
void OLED::drawCircle(int x, int y, int radius)
{
int f = 1 - radius;
int ddF_x = 1;
int ddF_y = -2 * radius;
int x1 = 0;
int y1 = radius;
char ch, cl;
setPixel(x, y + radius);
setPixel(x, y - radius);
setPixel(x + radius, y);
setPixel(x - radius, y);
while(x1 < y1)
{
if(f >= 0)
{
y1--;
ddF_y += 2;
f += ddF_y;
}
x1++;
ddF_x += 2;
f += ddF_x;
setPixel(x + x1, y + y1);
setPixel(x - x1, y + y1);
setPixel(x + x1, y - y1);
setPixel(x - x1, y - y1);
setPixel(x + y1, y + x1);
setPixel(x - y1, y + x1);
setPixel(x + y1, y - x1);
setPixel(x - y1, y - x1);
}
}
void OLED::clrCircle(int x, int y, int radius)
{
int f = 1 - radius;
int ddF_x = 1;
int ddF_y = -2 * radius;
int x1 = 0;
int y1 = radius;
char ch, cl;
clrPixel(x, y + radius);
clrPixel(x, y - radius);
clrPixel(x + radius, y);
clrPixel(x - radius, y);
while(x1 < y1)
{
if(f >= 0)
{
y1--;
ddF_y += 2;
f += ddF_y;
}
x1++;
ddF_x += 2;
f += ddF_x;
clrPixel(x + x1, y + y1);
clrPixel(x - x1, y + y1);
clrPixel(x + x1, y - y1);
clrPixel(x - x1, y - y1);
clrPixel(x + y1, y + x1);
clrPixel(x - y1, y + x1);
clrPixel(x + y1, y - x1);
clrPixel(x - y1, y - x1);
}
}
void OLED::drawBitmap(int x, int y, uint8_t* bitmap, int sx, int sy)
{
int bit;
byte data;
for (int cy=0; cy<sy; cy++)
{
bit= cy % 8;
for(int cx=0; cx<sx; cx++)
{
data=bitmapbyte(cx+((cy/8)*sx));
if ((data & (1<<bit))>0)
setPixel(x+cx, y+cy);
else
clrPixel(x+cx, y+cy);
}
}
}
// Private
void OLED::_sendStart(byte addr)
{
pinMode(_sda_pin, OUTPUT);
digitalWrite(_sda_pin, HIGH);
digitalWrite(_scl_pin, HIGH);
digitalWrite(_sda_pin, LOW);
digitalWrite(_scl_pin, LOW);
shiftOut(_sda_pin, _scl_pin, MSBFIRST, addr);
}
void OLED::_sendStop()
{
pinMode(_sda_pin, OUTPUT);
digitalWrite(_sda_pin, LOW);
digitalWrite(_scl_pin, HIGH);
digitalWrite(_sda_pin, HIGH);
pinMode(_sda_pin, INPUT);
}
void OLED::_sendNack()
{
pinMode(_sda_pin, OUTPUT);
digitalWrite(_scl_pin, LOW);
digitalWrite(_sda_pin, HIGH);
digitalWrite(_scl_pin, HIGH);
digitalWrite(_scl_pin, LOW);
pinMode(_sda_pin, INPUT);
}
void OLED::_sendAck()
{
pinMode(_sda_pin, OUTPUT);
digitalWrite(_scl_pin, LOW);
digitalWrite(_sda_pin, LOW);
digitalWrite(_scl_pin, HIGH);
digitalWrite(_scl_pin, LOW);
pinMode(_sda_pin, INPUT);
}
void OLED::_waitForAck()
{
pinMode(_sda_pin, INPUT);
digitalWrite(_scl_pin, HIGH);
while (digitalRead(_sda_pin)==HIGH) {}
digitalWrite(_scl_pin, LOW);
}
void OLED::_writeByte(uint8_t value)
{
pinMode(_sda_pin, OUTPUT);
shiftOut(_sda_pin, _scl_pin, MSBFIRST, value);
}