John Bradnam
Published © GPL3+

Servo Tester with Ammeter

Manually or automatically sweep the arm of a servo through a specified range while showing average operating current of that servo

IntermediateFull instructions provided12 hours489
Servo Tester with Ammeter

Things used in this project

Hardware components

Microchip ATtiny1614 Microprocessor
×1
OLED Display 128x64 0.96 inch, I2C Interface
DIYables OLED Display 128x64 0.96 inch, I2C Interface
×1
General Purpose Dual Op-Amp
Texas Instruments General Purpose Dual Op-Amp
SOIC variant
×1
Linear Regulator (7805)
Linear Regulator (7805)
×1
Rotary Encoder with Push-Button
Rotary Encoder with Push-Button
×1
Rotary Potentiometer, 10 kohm
Rotary Potentiometer, 10 kohm
PTV09A-4025F
×1
1N5819 – 1A Schottky Barrier Rectifier
1N5819 – 1A Schottky Barrier Rectifier
×1
Passive Components
2 x 4K7 1/8W resistors, 3 x 10K 0805 resistors, 1 x 2K2 0805 resistor, 1 x 100K 0805 resistor, 1 x 0.01 ohm 1% 1206 resistor, 2 x 0.1uF 0805 capacitors, 3 x 22nF 0805 capacitors, 1 x 0.1uF 1206 capacitor, 1 x 100uF 10V 6032 tantalum capacitor
×1
Servo Motor SG90 180 degree
DIYables Servo Motor SG90 180 degree
Used to test unit
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

STL Files

Files for 3D printing

Schematics

Schematic

PCB

Eagle files

Schematic & PCB in Eagle format

Code

ServoTesterAmmeterV4.ino

C/C++
/**
 * ATtiny1614 Servo Tester & Ammeter
 * based on Smart Servo Motor Tester with mAmp meter from Science 3D 
 * (https://www.hackster.io/science3d/smart-servo-motor-tester-with-mamp-meter-f1fd42)
 * 
 * John Bradnam (jbrad2089@gmail.com)
 * 2022-12-15 - Initial Code Base
 *            - Rewrote for ATtiny1614
 *            - Redesigned display libaries to reduced footprint
 * ---------------------------------------
 * ATtiny1614 Pins mapped to Ardunio Pins
 *
 *             +--------+
 *         VCC + 1   14 + GND
 * (SS)  0 PA4 + 2   13 + PA3 10 (SCK)
 *       1 PA5 + 3   12 + PA2 9  (MISO)
 * (DAC) 2 PA6 + 4   11 + PA1 8  (MOSI)
 *       3 PA7 + 5   10 + PA0 11 (UPDI)
 * (RXD) 4 PB3 + 6    9 + PB0 7  (SCL)
 * (TXD) 5 PB2 + 7    8 + PB1 6  (SDA)
 *             +--------+
 *             
 *             
 * BOARD: ATtiny1614/1604/814/804/414/404/214/204
 * Chip: ATtiny1614
 * Clock Speed: 20MHz
 * millis()/micros(): "TCD0 (1 series only, default there)"
 * Programmer: jtag2updi (megaTinyCore)
 * ----------------------------------------
 */
#include <Wire.h>
#include "font6x8.h"
#include "font8x16.h"
#include "SSD1306_ATtiny1614.h"
#include <Servo_megaTinyCore.h>

#define ENCA_PIN 1    //PA5
#define ENCB_PIN 0    //PA4
#define ENCS_PIN 2    //PA6
#define SDA_PIN 6     //PB1
#define SCL_PIN 7     //PB0
#define A_PIN 8       //PA1
#define POT_PIN 9     //PA2
#define SERVO_PIN 10  //PA3

//Running average variables to monitor current
#define AMP_SIZE 128
#define AMP_MASK 0x7F
uint32_t ampTotal = 0;
uint16_t ampCount = 0;
uint8_t ampHead = 0; 
uint8_t ampTail = 0;
uint16_t ampValues[AMP_SIZE];
uint16_t ampMaximum = 0;
int oldCurrent = -1;

//Running average variables for potentiometer
#define POT_SIZE 16
#define POT_MASK 0x0F
uint32_t potTotal = 0;
uint16_t potCount = 0;
uint8_t potHead = 0; 
uint8_t potTail = 0;
uint16_t potValues[POT_SIZE];

//Rotary encoder
volatile int rotaryDirection = 0;
volatile bool rotarySwitchPressed = false;
bool volatile lastRotA = false;                               // Used to determine direction of rotary encoder
bool volatile lastRotB = false;                               // Used to determine direction of rotary encoder

//Display
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 64
//Adafruit_SSD1306 display(DISPLAY_WIDTH, DISPLAY_HEIGHT, &Wire, -1);

//Menus
#define TOTAL_MENU_ITEMS 6
#define MAX_TEXT_LEN 11
enum MENU_ENUM { SERVO_MIN, SERVO_MAX, MODE_SWEEP, MODE_POT, CENTER, RESET };
char menuItems[TOTAL_MENU_ITEMS][MAX_TEXT_LEN] = {{"SERVO MIN"},{"SERVO MAX"},{"MODE SWEEP"},{"MODE POT"},{"CENTER"},{"RESET"}};
MENU_ENUM currentMenuItem;
MENU_ENUM previousMenuItem;
bool inMenuSelect = true;
char charBuf[MAX_TEXT_LEN];
char horzLine[] = "{{{{{{{{{{{{{{{{{{{{";

//Servo
Servo servo;
int servoPosition = 0;
int servoMinAngle = 0;
int servoMaxAngle = 180;
bool servoMiddle = false;
bool servoAuto = false;
bool servoDirection = false;
int oldPosition = -1;
int oldServoMin = -1;
int oldServoMax = -1;
bool oldServoAuto = false;

//--------------------------------------------------------------------
//Program Setup
void setup() 
{

  //Setup rotary encoder
  pinMode(ENCS_PIN, INPUT_PULLUP);
  pinMode(ENCA_PIN, INPUT);
  pinMode(ENCB_PIN, INPUT);
  attachInterrupt(ENCA_PIN, rotaryInterrupt, CHANGE);
  //attachInterrupt(ENCB_PIN, rotaryInterrupt, CHANGE);
  attachInterrupt(ENCS_PIN,switchInterrupt,CHANGE);

  //Setup ammeter
  pinMode(A_PIN, INPUT);

  //Setup angle potentiometer
  pinMode(POT_PIN, INPUT);
  
  //Setup display
  ssd1306_init();
  ssd1306_fillscreen(0x00);

  //Setup servo
  pinMode(SERVO_PIN, OUTPUT);
  servo.attach(SERVO_PIN);    //PWM pin
  resetServoParameters();
  
  inMenuSelect = true;
  currentMenuItem = SERVO_MIN;
  previousMenuItem = SERVO_MIN;
  displayMenu(true);
}

//---------------------------------------------------------------------
//Main program loop
void loop()
{
  if (inMenuSelect)
  {
    //Check if rotary encoder has moved
    if (rotaryDirection == -1 && currentMenuItem != SERVO_MIN)
    {
      previousMenuItem = currentMenuItem;
      currentMenuItem = (MENU_ENUM)((int)currentMenuItem - 1);
      displayMenu(false);
    }
    else if (rotaryDirection == 1 && currentMenuItem != RESET)
    {
      previousMenuItem = currentMenuItem;
      currentMenuItem = (MENU_ENUM)((int)currentMenuItem + 1);
      displayMenu(false);
    }
    rotaryDirection = 0;      

    //Check if switch is pressed
    if (rotarySwitchPressed && (digitalRead(ENCS_PIN) == LOW))
    {
      if (servoMiddle)
      {
        servoMiddle = false;
      }
      else
      {
        switch (currentMenuItem)
        {
          case SERVO_MIN: servoMinAngle = servoPosition; currentMenuItem = MODE_POT; break;
          case SERVO_MAX: servoMaxAngle = servoPosition; currentMenuItem = MODE_POT; break;
          case MODE_SWEEP: servoAuto = true; break;
          case MODE_POT:  servoAuto = false; break;
          case CENTER: servoCenter(); currentMenuItem = MODE_POT; break;
          case RESET: resetServoParameters(); currentMenuItem = MODE_POT; break;
        }
        displayStatus(true);
        inMenuSelect = false;
      }
    }
  }
  else
  {
    displayStatus(false);
    if (rotarySwitchPressed && (digitalRead(ENCS_PIN) == LOW))
    {
      displayMenu(true);
      inMenuSelect = true;
      rotaryDirection = 0;      
    }
  }
  rotarySwitchPressed = false;
}


//---------------------------------------------------------------------
// Interrupt Handler: Rotary encoder has moved
void rotaryInterrupt()
{
  bool a = (digitalRead(ENCA_PIN) == LOW);
  bool b = (digitalRead(ENCB_PIN) == LOW);
  if (a != lastRotA) 
  {
    lastRotA = a;
    if (b != lastRotB) 
    {
      lastRotB = b;
      if (b)
      {
        rotaryDirection = ((a == b) ? -1 : 1);
      }
    }
  }
}

//--------------------------------------------------------------------
//Handle pin change interrupt when button is pressed

void switchInterrupt()
{
  rotarySwitchPressed = true;
}

//--------------------------------------------------------------------
//Display the menu and highlight the current selection
// repaintScreen - true to redraw the whole screen

void displayMenu(bool repaintScreen)
{
  if (repaintScreen)
  {
    displayHeader(); 
    
    for(int i=0, y=2; i<TOTAL_MENU_ITEMS; i++, y++)
    {
      ssd1306_char_f6x8(10, y, (i == (int)currentMenuItem) ? "|" : " ");
      ssd1306_char_f6x8(22, y, menuItems[i]);
    }
  }
  else
  {
    ssd1306_char_f6x8(10, 2 + (int)previousMenuItem, " ");
    ssd1306_char_f6x8(10, 2 + (int)currentMenuItem, "|");
  }
}

//--------------------------------------------------------------------
//Display the status screen
// repaintScreen - true to redraw the whole screen

void displayStatus(bool repaintScreen)
{
  if (repaintScreen)
  {
    displayHeader();
    ssd1306_char_f6x8(65, 2, "AVG mA");
    ssd1306_char_f6x8(0, 4, horzLine);
    ssd1306_char_f6x8(0, 5, "MIN");
    ssd1306_char_f6x8(50, 5, "MAX");
    ssd1306_char_f6x8(94, 5, "MODE");
  }

  int curPos = (servoMiddle) ? (servoMinAngle + servoMaxAngle) / 2 : servoPosition;
  if (repaintScreen || oldPosition != curPos)
  {
    sprintf(charBuf, "%d  ", curPos);
    ssd1306_char_f8x16(0, 2, charBuf);
    oldPosition = curPos;
  }
    
  int current = readCurrent();
  if (repaintScreen || oldCurrent != current)
  {
    sprintf(charBuf, "%d  ", current);
    ssd1306_char_f6x8(65, 3, charBuf);
    oldCurrent = current;
  }

  if (repaintScreen || oldServoMin != servoMinAngle)
  {
    sprintf(charBuf, "%d  ", servoMinAngle);
    ssd1306_char_f6x8(0, 6, charBuf);
    oldServoMin = servoMinAngle;
  }

  if (repaintScreen || oldServoMax != servoMaxAngle)
  {
    sprintf(charBuf, "%d  ", servoMaxAngle);
    ssd1306_char_f6x8(50, 6, charBuf);
    oldServoMax = servoMaxAngle;
  }

  ssd1306_setpos(94, 6);
  if (servoAuto)
  {
    if (!servoMiddle)
    {
      servoSweep();
    }
    if (repaintScreen || oldServoAuto != servoAuto)
    {
      ssd1306_string_font6x8("SWEEP");
      oldServoAuto = servoAuto;
    }
  }
  else
  {
    if (!servoMiddle)
    {
      servoKnob();
    }
    if (repaintScreen || oldServoAuto != servoAuto)
    {
      ssd1306_string_font6x8("POT  ");
      oldServoAuto = servoAuto;
    }
  }
}

//--------------------------------------------------------------------
//Displays the screen header

void displayHeader()
{ 
  ssd1306_fillscreen(0x00);
  ssd1306_char_f6x8(14, 0, "Servo Controller");
  ssd1306_char_f6x8(0, 1, horzLine);
}

//--------------------------------------------------------------------
//Sweep the servo between min and max values

void servoSweep()
{
  int yy = map(analogRead(POT_PIN), 1022, 0, 10, 1);     // scale it to use it with the servo

  if (servoPosition > servoMaxAngle)
  {
    servoPosition = servoMaxAngle;
    delay(10);
    servoDirection = false;   //start decreasing angle
  }
  else if (servoPosition < servoMinAngle)
  {
    servoPosition = servoMinAngle;
    delay(10);
    servoDirection = true;   //start increasing angle
  }

  if (servoDirection)  //increasing
  {
    if ((servoPosition + (yy / 2)) >= servoMaxAngle)
    {
      yy = round(abs(servoMaxAngle - servoPosition) / 3);
    }
    if (yy < 1)
    {
      yy = 1;
    }
    servoPosition = servoPosition + yy;
    servo.write(180 - servoPosition);              // tell servo to go to position in variable 'pos'
  }
  else //decreasing
  {
    if ((servoPosition - (yy / 2)) <= servoMinAngle)
    {
      yy = round(abs(servoPosition - servoMinAngle) / 3);
    }
    if (yy < 1)
    {
      yy = 1;
    }
    servoPosition = servoPosition - yy;
    servo.write(180 - servoPosition);              // tell servo to go to position in variable 'pos'
  }
}

//--------------------------------------------------------------------
// Manual movement of servo

void servoKnob()
{
  servoPosition = readPot();
  if (servoPosition > servoMaxAngle)
  {
    servoPosition = servoMaxAngle;
  }
  else if (servoPosition < servoMinAngle)
  {
    servoPosition = servoMinAngle;
  }
  servo.write(180 - servoPosition);            // sets the servo position according to the scaled value
}

//--------------------------------------------------------------------
// Center the servo

void servoCenter()
{
  servoAuto = false;
  servoMiddle = true;
  servo.write(180 - ((servoMinAngle + servoMaxAngle) / 2));
  potTotal = 90;
  potCount = 1;
  potHead = 1; 
  potTail = 0;
  potValues[0] = 90;
}

//--------------------------------------------------------------------
// Reset servo parameters to their defaults

void resetServoParameters()
{
  servoMinAngle = 0;
  servoMaxAngle = 180;
  servoMiddle = false;
  servoAuto = false;
  ampTotal = 0;
  ampCount = 0;
  ampHead = 0; 
  ampTail = 0;
  ampMaximum = 0;
  potTotal = 0;
  potCount = 0;
  potHead = 0; 
  potTail = 0;
}

//-------------------------------------------------------------
// Read the current
// Add to the running total
// Returns current running average in mA

int readCurrent()
{
  // taking the average for stable readings
  unsigned long current = 0;

  for (int i=0; i<16; i++) 
  {
    current = current + analogRead(A_PIN);
  }
  current = (current >> 4);
  int amp = round(current * 5.5); // calibration value,to be changed according to components used
  
  if (ampCount == AMP_SIZE)
  {
    //Remove oldest value from running total
    ampTotal = ampTotal - ampValues[ampTail];
    ampTail = (ampTail + 1) & AMP_MASK;
    ampCount--;
  }
  //Add new value to running total
  ampValues[ampHead] = amp;
  ampHead = (ampHead + 1) & AMP_MASK;
  ampTotal = ampTotal + amp;
  ampCount++;
  
  ampMaximum = max(ampMaximum, (uint16_t)amp);
  return (int)round(ampTotal / ampCount);
}

//-------------------------------------------------------------
// Reads the Potentiometer value
// Returns current running average (0 to 1023)

int readPot()
{
  // taking the average for stable readings
  int pot = analogRead(POT_PIN);
  pot = map(pot, 1022, 0, 180, 0);    // scale it to use it with the servo (value between 0 and 180)
  if (potCount == POT_SIZE)
  {
    //Remove oldest value from running total
    potTotal = potTotal - potValues[potTail];
    potTail = (potTail + 1) & POT_MASK;
    potCount--;
  }
  //Add new value to running total
  potValues[potHead] = pot;
  potHead = (potHead + 1) & POT_MASK;
  potTotal = potTotal + pot;
  potCount++;
  return (int)round(potTotal / potCount);
}

SSD1306_ATtiny1614.h

C Header File
/*--------------------------------------------------------
 * I2C SSD1306 128x64 OLED support routines for ATtiny1614
 * 
 * @created: 2020-05-12
 * @author: John Bradnam
 *
 * Based on Adafruit_SSD1306.h
 */

 
#pragma once

#include <Wire.h>

//---------------------- ATtiny1614 ----------------------

#define SSD1306_SA    0x3C  // Slave address

#if (ARDUINO >= 157)
  #define TRANSACTION_START Wire.setClock(200000UL);    ///< Set before I2C transfer
  #define TRANSACTION_END Wire.setClock(100000UL); ///< Restore after I2C xfer
#else // setClock() is not present in older Arduino Wire lib (or WICED)
  #define TRANSACTION_START ///< Dummy stand-in define
  #define TRANSACTION_END ///< keeps compiler happy
#endif

#if defined(BUFFER_LENGTH)
#define WIRE_MAX BUFFER_LENGTH ///< AVR or similar Wire lib
#elif defined(SERIAL_BUFFER_SIZE)
#define WIRE_MAX (SERIAL_BUFFER_SIZE - 1) ///< Newer Wire uses RingBuffer
#else
#define WIRE_MAX 32 ///< Use common Arduino core default
#endif

#define LCD_WIDTH 128
#define LCD_HEIGHT 64

//----------------- Forward references -------------------

void ssd1306_init(void);
void ssd1306_xfer_start(void);
void ssd1306_xfer_stop(void);
void ssd1306_send_byte(uint8_t byte);
void ssd1306_send_command(uint8_t command);
void ssd1306_send_command_list(const uint8_t *c, uint8_t n) ;
void ssd1306_send_data_start(void);
void ssd1306_send_data_stop(void);
void ssd1306_send_data_list(const uint8_t *c, uint8_t n);
void ssd1306_setpos(uint8_t x, uint8_t y);
void ssd1306_fillscreen(uint8_t fill_Data);
void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char *s);
void ssd1306_char_font6x8(char ch) ;
void ssd1306_string_font6x8(const char *s); 
void ssd1306_char_f8x16(uint8_t x, uint8_t y, const char *s);
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]);

//----------------- Functions -------------------

const uint8_t ssd1306_init_sequence [] PROGMEM = {  // Initialization Sequence
  0xAE, //SSD1306_DISPLAYOFF
  0xD5, //SSD1306_SETDISPLAYCLOCKDIV
  0x80, // the suggested ratio 0x80
  0xA8, //SSD1306_SETMULTIPLEX};
  LCD_HEIGHT - 1,
  0xD3, //SSD1306_SETDISPLAYOFFSET
  0x00, // no offset
  0x40, //SSD1306_SETSTARTLINE | 0x0
  0x8D, //SSD1306_CHARGEPUMP};
#ifdef SSD1306_EXTERNALVCC
  0x10,
#else  
  0x14,
#endif  
  0x20, //SSD1306_MEMORYMODE
  0x00, // 0x0 act like ks0108
  0xA1, //SSD1306_SEGREMAP | 0x1
  0xC8, //SSD1306_COMSCANDEC
  0xDA, //SSD1306_SETCOMPINS
  0x12, //128x64 resolution
#ifdef SSD1306_EXTERNALVCC
  0x81, //SSD1306_SETCONTRAST
  0x9F, //contrast
  0xD9, //SSD1306_SETPRECHARGE
  0x22,
#else  
  0x81, //SSD1306_SETCONTRAST
  0xCF, //contrast
  0xD9, //SSD1306_SETPRECHARGE
  0xF1,
#endif  
  0xDB, //SSD1306_SETVCOMDETECT
  0x40,
  0xA4, //SSD1306_DISPLAYALLON_RESUME
  0xA6, //SSD1306_NORMALDISPLAY
  0x2E, //SSD1306_DEACTIVATE_SCROLL
  0xAF  //SSD1306_DISPLAYON   // Main screen turn on
};

void ssd1306_init(void)
{
  Wire.begin();
  TRANSACTION_START
  ssd1306_send_command_list(ssd1306_init_sequence, sizeof (ssd1306_init_sequence));
  TRANSACTION_END
}

void ssd1306_xfer_start(void)
{
  Wire.beginTransmission(SSD1306_SA);
}

void ssd1306_xfer_stop(void)
{
  Wire.endTransmission();
}  

void ssd1306_send_byte(uint8_t byte)
{
  Wire.write(byte);
}

void ssd1306_send_command(uint8_t command)
{
  ssd1306_xfer_start();
  Wire.write(byte(0x00));  // write command
  Wire.write(byte(command));
  ssd1306_xfer_stop();
}

void ssd1306_send_command_list(const uint8_t *c, uint8_t n) 
{
  ssd1306_xfer_start();
  Wire.write(byte(0x00));  // Co = 0, D/C = 0
  uint8_t bytesOut = 1;
  while (n--) 
  {
    if (bytesOut >= WIRE_MAX) 
    {
      ssd1306_xfer_stop();
      ssd1306_xfer_start();
      Wire.write(byte(0x00));  // Co = 0, D/C = 0
      bytesOut = 1;
    }
    Wire.write(pgm_read_byte(c++));
    bytesOut++;
  }
  ssd1306_xfer_stop();
}

void ssd1306_send_data_start(void)
{
  ssd1306_xfer_start();
  Wire.write(byte(0x40));  //write data
}

void ssd1306_send_data_stop(void)
{
  ssd1306_xfer_stop();
}

void ssd1306_send_data_list(const uint8_t *c, uint8_t n)
{
  ssd1306_send_data_start();
  uint8_t bytesOut = 1;
  while (n--) 
  {
    if (bytesOut >= WIRE_MAX) 
    {
      ssd1306_send_data_stop();
      ssd1306_send_data_start();
      bytesOut = 1;
    }
    Wire.write(pgm_read_byte(c++));
    bytesOut++;
  }
  ssd1306_send_data_stop();
}

void ssd1306_setpos(uint8_t x, uint8_t y)
{
  ssd1306_xfer_start();
  Wire.write(byte(0x00));  //write command

  Wire.write(byte(0xb0+y));
  Wire.write(byte(((x&0xf0)>>4)|0x10)); // |0x10
  Wire.write(byte((x&0x0f)|0x01)); // |0x01

  ssd1306_xfer_stop(); 
}

void ssd1306_fillscreen(uint8_t fill_Data)
{
  TRANSACTION_START
  static const uint8_t PROGMEM dlist1[] = 
  {
      0x22, //SSD1306_PAGEADDR
      0x00, // Page start address
      0xFF, // Page end (not really, but works here)
      0x21, //SSD1306_COLUMNADDR  
      0x00, //Column start address
      LCD_WIDTH - 1 // Column end address
  }; 
  ssd1306_send_command_list(dlist1, sizeof(dlist1));
  
  uint16_t count = LCD_WIDTH * ((LCD_HEIGHT + 7) / 8);
  ssd1306_send_data_start();
  uint8_t bytesOut = 1;
  for(uint16_t n=0; n<count; n++) 
  {
    if (bytesOut >= WIRE_MAX) 
    {
      ssd1306_send_data_stop();
      ssd1306_send_data_start();
      bytesOut = 1;
    }
    ssd1306_send_byte(fill_Data);
    bytesOut++;
  }
  ssd1306_send_data_stop();
  TRANSACTION_END
}

void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char *s)
{
  while(*s)
  {
    if(x>126)
    {
      x=0;
      y++;
    }
    ssd1306_setpos(x,y);
    ssd1306_char_font6x8(*s++);
    x += 6;
  }
}

void ssd1306_char_font6x8(char ch) 
{
  uint8_t c = ch - 32;
  ssd1306_send_data_list(&ssd1306xled_font6x8[c * 6], 6);
}

void ssd1306_string_font6x8(const char *s) 
{
  while (*s) 
  {
    ssd1306_char_font6x8(*s++);
  }
}

void ssd1306_char_f8x16(uint8_t x, uint8_t y, const char *s)
{
  uint8_t c, i = 0;
  while (*s)
  {
    c = *s++ - 32;
    if (x > 120)
    {
      x = 0;
      y++;
    }
    ssd1306_setpos(x, y);
    ssd1306_send_data_start();
    for (i = 0; i < 8; i++)
    {
      ssd1306_send_byte(pgm_read_byte(&ssd1306xled_font8x16[c * 16 + i]));
    }
    ssd1306_send_data_stop();
    ssd1306_setpos(x, y + 1);
    ssd1306_send_data_start();
    for (i = 0; i < 8; i++)
    {
      ssd1306_send_byte(pgm_read_byte(&ssd1306xled_font8x16[c * 16 + i + 8]));
    }
    ssd1306_send_data_stop();
    x += 8;
  }
}

void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[])
{
  uint8_t y, x;
  const uint8_t* p = bitmap;
  y = y1 >> 3;
  if (y1 & 0x07) 
    y++;
  for (y = y0; y < y1; y++)
  {
    x = x1 - x0;
    ssd1306_setpos(x0,y);
    ssd1306_send_data_list(p, x);
    p += x;
  }
}

font6x8.h

C Header File
/*
 * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
 *
 * @created: 2014-08-12
 * @author: Neven Boyanov
 *
 * Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
 *
 */

// ----------------------------------------------------------------------------

#include <avr/pgmspace.h>

// ----------------------------------------------------------------------------

/* Standard ASCII 6x8 font */
const uint8_t ssd1306xled_font6x8 [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
  0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
  0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
  0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
  0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
  0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
  0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
  0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
  0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
  0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
  0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
  0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
  0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
  0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
  0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
  0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
  0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
  0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
  0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
  0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
  0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
  0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
  0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
  0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
  0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
  0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
  0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
  0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
  0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
  0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
  0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
  0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
  0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
  0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
  0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
  0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
  0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
  0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
  0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
  0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
  0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
  0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
  0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
  0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
  0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
  0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
  0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
  0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
  0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
  0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
  0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
  0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
  0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
  0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
  0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
  0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
  0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
  0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
  0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
  0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
  0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
  0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
  0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
  0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
  0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
  0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
  0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
  0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
  0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
  0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
  0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
  0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
  0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
  0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
  0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
  0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
  0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
  0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
  0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
  0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
  0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
  0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
  0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
  0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
  0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
  0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
  0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
  0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
  0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
  0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
  0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z
  0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // { horz line
  0x00, 0x7F, 0x3E, 0x1C, 0x08, 0x00, // | arrow head
  0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // } double line
};

// ----------------------------------------------------------------------------

font8x16.h

C Header File
/*
 * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
 *
 * @created: 2014-08-12
 * @author: Neven Boyanov
 *
 * Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
 *
 */

// ----------------------------------------------------------------------------

#include <avr/pgmspace.h>

// ----------------------------------------------------------------------------

/* Standard ASCII 8x16 font */
const uint8_t ssd1306xled_font8x16 [] PROGMEM = {
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0
  0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00, // ! 1
  0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // " 2
  0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00, // # 3
  0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00, // $ 4
  0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00, // % 5
  0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10, // & 6
  0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ' 7
  0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00, // ( 8
  0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00, // ) 9
  0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00, // * 10
  0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00, // + 11
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00, // , 12
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01, // - 13
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00, // . 14
  0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00, // / 15
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, // 0 16
  0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // 1 17
  0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00, // 2 18
  0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00, // 3 19
  0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00, // 4 20
  0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00, // 5 21
  0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00, // 6 22
  0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00, // 7 23
  0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00, // 8 24
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00, // 9 25
  0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00, // : 26
  0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00, // ; 27
  0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00, // < 28
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00, // = 29
  0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00, // > 30
  0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00, // ? 31
  0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00, // @ 32
  0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20, // A 33
  0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00, // B 34
  0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00, // C 35
  0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00, // D 36
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00, // E 37
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00, // F 38
  0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00, // G 39
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20, // H 40
  0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // I 41
  0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00, // J 42
  0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00, // K 43
  0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00, // L 44
  0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00, // M 45
  0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00, // N 46
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00, // O 47
  0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00, // P 48
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00, // Q 49
  0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20, // R 50
  0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00, // S 51
  0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00, // T 52
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00, // U 53
  0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00, // V 54
  0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00, // W 55
  0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20, // X 56
  0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00, // Y 57
  0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00, // Z 58
  0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00, // [ 59
  0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00, // \ 60
  0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00, // ] 61
  0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^ 62
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, // _ 63
  0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ` 64
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20, // a 65
  0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00, // b 66
  0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00, // c 67
  0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20, // d 68
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00, // e 69
  0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // f 70
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00, // g 71
  0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20, // h 72
  0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // i 73
  0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00, // j 74
  0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00, // k 75
  0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // l 76
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F, // m 77
  0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20, // n 78
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00, // o 79
  0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00, // p 80
  0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80, // q 81
  0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00, // r 82
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00, // s 83
  0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00, // t 84
  0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20, // u 85
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00, // v 86
  0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00, // w 87
  0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00, // x 88
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00, // y 89
  0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00, // z 90
  0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40, // { 91
  0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00, // | 92
  0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00, // } 93
  0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~ 94
};

// ----------------------------------------------------------------------------

Credits

John Bradnam

John Bradnam

145 projects • 178 followers
Thanks to Science 3D.

Comments