OpenChargeMicro/Software/src/oled_ssd1306/oled_ssd1306.cpp

260 lines
6.3 KiB
C++

/*
* Created: 19.06.2016 11:38:00
* Author: Ulrich
* From: https://www.ulrichradig.de/home/index.php/avr/oled-display-ssd1306
*/
#include "oled_ssd1306.h"
#include "font.h"
static uint8_t oled_x = 0, oled_y = 0, font_size = 0;
const uint8_t ssd1306_init_cmd [] PROGMEM = {
SET_DISPLAY_OFF,
COMMAND_NO_OPERATION,
SET_MEMORY_ADDR_MODE, HORIZONTAL_ADDRESSING_MODE,
SET_PAGE_START,
SET_COM_OUTPUT_REMAPPED,
SET_LOWER_COLUMN,
SET_HIGHER_COLUMN,
SET_DISPLAY_START_LINE,
ENTIRE_DISPLAY_ON,
SET_SEGMENT_REMAP_O2,
SET_DISPLAY_NORMAL,
SET_CONTRAST_CONTROL, 0xFF,
SET_MULTIPLEX_RATIO, 0x3F,
SET_DISPLAY_OFFSET, 0x00,
SET_DISPLAY_CLOCK, 0xF0,
SET_PRECHARGE_PERIOD, 0x22,
SET_COM_PINS, 0x12,
SET_VCOMH_DESELECT, 0x20,
CHARGE_BUMB_SETTING, 0x14,
SET_DISPLAY_ON };
oled_ssd1306::oled_ssd1306(){
}
oled_ssd1306::~oled_ssd1306(){
}
//***************************************************************************************
void oled_ssd1306::i2c_init(void){
I2C_PORT |= (1 << SDA_PIN | 1 << SCL_PIN); //Port Pullup
TWCR = 0;
TWSR = 0;
TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
_delay_ms(50);
}
//***************************************************************************************
uint8_t oled_ssd1306::i2c_start (void){
uint8_t timeout = 0;
TWCR = (1 << TWINT | 1 << TWSTA | 1 << TWEN);
while(!(TWCR & (1<<TWINT))){
if((timeout++) > 100) return 1;
}
TWDR = OLED_I2C_ADDR;
TWCR = (1 << TWINT | 1 << TWEN);
timeout = 0;
while(!(TWCR & (1<<TWINT))){
if((timeout++) > 100) return 1;
}
return 0;
}
//***************************************************************************************
uint8_t oled_ssd1306::i2c_byte (uint8_t byte){
uint8_t timeout = 0;
TWDR = byte;
TWCR = (1 << TWINT | 1 << TWEN);
while(!(TWCR & (1<<TWINT))){
if((timeout++) > 100) return 1;
}
return 0;
}
//***************************************************************************************
void oled_ssd1306::i2c_stop (void){
TWCR = (1 << TWINT | 1 << TWSTO | 1 << TWEN);
TWCR = 0;
}
//***************************************************************************************
void oled_ssd1306::oled_init (void){
i2c_init();
i2c_start();
i2c_byte(COMMAND);
for (uint8_t tmp = 0; tmp< sizeof(ssd1306_init_cmd); tmp++) {
i2c_byte(pgm_read_byte(&ssd1306_init_cmd[tmp]));
}
i2c_stop();
oled_clear_screen();
}
//***************************************************************************************
void oled_ssd1306::oled_clear_screen (void){
oled_gotoxy(0,0);
i2c_start();
i2c_byte(DATA);
for (uint16_t i = 0; i < 128<<4 ; i++) { // 128 * (64 / Byte)
i2c_byte(0);
}
i2c_stop();
oled_gotoxy(0,0);
}
//***************************************************************************************
void oled_ssd1306::oled_gotoxy (uint8_t x, uint8_t y){
oled_x = x;
oled_y = y;
i2c_start();
i2c_byte(COMMAND);
i2c_byte(SET_PAGE_START|y);
i2c_byte(SET_COLUMN_ADDRESS);
i2c_byte(x * 8);
i2c_byte(SET_DISPLAY_START_LINE|0x3F);
i2c_stop();
}
//***************************************************************************************
void oled_ssd1306::oled_font_size (uint8_t byte){
font_size = byte;
}
//***************************************************************************************
void oled_ssd1306::oled_write_char (char c){
if(font_size != 0){
uint8_t tmp = 0;
oled_gotoxy(oled_x,oled_y);
i2c_start();
i2c_byte(DATA);
for (uint8_t count = 0; count < 8; count++){
tmp = pgm_read_byte(&font[(unsigned char)c][count]);
tmp = tmp & 0x0f;
tmp = ((tmp&0x01)*3)+(((tmp&0x02)<<1)*3)+(((tmp&0x04)<<2)*3)+(((tmp&0x08)<<3)*3);
i2c_byte(tmp);
i2c_byte(tmp);
}
i2c_stop();
oled_gotoxy(oled_x,oled_y + 1);
i2c_start();
i2c_byte(DATA);
for (uint8_t count = 0; count < 8; count++){
tmp = pgm_read_byte(&font[(unsigned char)c][count]);
tmp = (tmp & 0xf0)>>4;
tmp = ((tmp&0x01)*3)+(((tmp&0x02)<<1)*3)+(((tmp&0x04)<<2)*3)+(((tmp&0x08)<<3)*3);
i2c_byte(tmp);
i2c_byte(tmp);
}
i2c_stop();
oled_x +=2;
oled_y -=1;
}else{
oled_gotoxy(oled_x,oled_y);
i2c_start();
i2c_byte(DATA);
for (uint8_t count = 0; count < 8; count++){
i2c_byte(pgm_read_byte(&font[(unsigned char)c][count]));
}
i2c_stop();
oled_x +=1;
}
}
//***************************************************************************************
void oled_ssd1306::oled_write_str (char* str){
while (*str) {
oled_write_char(*str++);
}
}
//***************************************************************************************
void oled_ssd1306::oled_write_P (const char *Buffer,...)
{
va_list ap;
va_start (ap, Buffer);
int format_flag;
char str_buffer[10];
char str_null_buffer[10];
char move = 0;
char Base = 0;
int tmp = 0;
char by;
char *ptr;
//Ausgabe der Zeichen
for(;;){
by = pgm_read_byte(Buffer++);
if(by==0) break; // end of format string
if (by == '%'){
by = pgm_read_byte(Buffer++);
if (isdigit(by)>0){
str_null_buffer[0] = by;
str_null_buffer[1] = '\0';
move = atoi(str_null_buffer);
by = pgm_read_byte(Buffer++);
}
switch (by){
case 's':
ptr = va_arg(ap,char *);
while(*ptr) { oled_write_char(*ptr++); }
break;
case 'b':
Base = 2;
goto ConversionLoop;
case 'c':
//Int to char
format_flag = va_arg(ap,int);
oled_write_char (format_flag++);
break;
case 'i':
Base = 10;
goto ConversionLoop;
case 'o':
Base = 8;
goto ConversionLoop;
case 'x':
Base = 16;
//****************************
ConversionLoop:
//****************************
itoa(va_arg(ap,int),str_buffer,Base);
int b=0;
while (str_buffer[b++] != 0){};
b--;
if (b<move){
move -=b;
for (tmp = 0;tmp<move;tmp++){
str_null_buffer[tmp] = '0';
}
//tmp ++;
str_null_buffer[tmp] = '\0';
strcat(str_null_buffer,str_buffer);
strcpy(str_buffer,str_null_buffer);
}
oled_write_str (str_buffer);
move =0;
break;
}
}else{
oled_write_char (by);
}
}
va_end(ap);
}