Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 2 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
Hand tools and fabrication machines | ||||||
| ||||||
|
While reading some of the comments on DIY Simple Measuring Wheel with Rotary Encoder by Mirko Pavleski, one in particular stood out. The comment by soorajts suggesting "squeezing it into an attiny and oled display" got me wondering whether I could not only do this but fit all the components inside the hub of the wheel itself.
One idea was to do something like my Twist-to-Set Kitchen Timer. The problem then comes how to connect the handle. Also the gearing would limit how small the hub could be.
The final design that I settled on is still very compact. It eliminates all the exposed wiring and has a easy to read OLED display showing both imperial and metric measurements.
DemonstrationSchematicThe circuit is designed around a ATtiny1614 microprocessor. It uses very little power when in sleep mode. The rotary encoder contains two sets of contacts which can become quite noisy resulting in incorrect readings. I added a RC network and Schmitt trigger between each contact and microprocessor. This removes any noise generated by the contacts and provides clean switch change signals to the microprocessor. The result is precise and accurate readings. The circuit is powered by a 3.7V 120mA LIPO battery.
The STL files are included. Either take these to a 3D print shop or if you have your own printer, run them through your slicing software. I used a 0.2mm layer height. Supports touching the build plate are required for "Wheel - Top.stl" and "Wheel - Wheel.stl".
The PCBTo minimize the space required, the board has been designed to use Surface Mount Devices (SMD) where possible.
The Eagle files have been included should you wish to have the board commercially made or you can do as I did and make it yourself. I used the Toner method.
Assembly - Step 1Start by adding the SMD components. I find it easier to use solder paste rather than use solder from a reel when soldering SMD components.
Add the rotary encoder and 3 pin UPDI right-angle pin header to the top side. Cut off any excess pins and file them flat to remove any sharp edges that may puncture the battery. Add the JST 2-pin right-angle battery socket to the copper side of the board.
Assembly - Step 2Add a 4 pin male machined pin header to the 0.96 OLED display. Also add a 4 pin female machined pin header to the copper side of the PCB.
Add two wires to the top two pins of the tactile switch (the pins exit the switch on the same side). Cut off the bottom two pins. Glue the whole assembly into the case using hot glue.
Cut the wires allowing sufficient length to insert and remove the PCB assembly and solder them to the PCB.
Add the 3.7V 120mA battery between the OLED PCB and rotary encoder PCB.
Add the board assembly to the case.
The ATtiny1614 is part of the new breed of ATtiny microprocessors. Unlike the earlier series such as the ATtiny85, the new breed use the RESET pin to program the CPU. To program it you need a UPDI programmer. I made one using a Arduino Nano. You can find complete build instructions at Create Your Own UPDI Programmer. It also contains the instructions for adding the megaTinyCore boards to your IDE.
Since the battery is already connected, only connect the ground and UPDI wires (leave the 5V wire unconnected).
Once the board has been installed in the IDE, select it from the Tools menu.
Select board, chip (ATtiny1614), clock speed (8MHz) and the COM port that the Arduino Nano is connected to.
The Programmer needs to be set to jtag2updi (megaTinyCore).
Open the sketch and upload it to the ATtiny1614.
Assembly - Step 6The case bottom screws onto the top. Once added, add the washer and nut to the rotary encoder.
For the wheel to measure distances with accuracy, it must not slip or slide on the surface that it is measuring. I used a rubber tire from a wheel I got from eBay.
Remove the tire from the wheel and add it to the 3D printed wheel. You could also use large O-rings instead.
Fit the wheel to the rotary encoder.
These measuring wheels are designed to be used over distances where rulers and tape measures are no longer practical. Even though it uses a rotary encoder with only 20 steps per revolution, it can still provide good quality results when measuring for example the size of a room.
A special thanks to Mirko Pavleski for the concept and inspiration for this project. The case design proved a bit of a challenge judging by the number of prints that ended up in the rubbish bin. Overall though, I am happy with the final result.
/**************************************************************************
Measuring Wheel
Based on "DIY Simple Measuring Wheel with Rotary Encoder" by Mirko Pavleski
2021-05-03 John Bradnam (jbrad2089@gmail.com)
Create program for ATtiny1614
--------------------------------------------------------------------------
Arduino IDE:
--------------------------------------------------------------------------
BOARD: ATtiny1614/1604/814/804/414/404/214/204
Chip: ATtiny1614
Clock Speed: 1MHz
Programmer: jtag2updi (megaTinyCore)
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)
+--------+
PA0 to PA7 can be analog or digital
PWM on D0, D1, D6, D7, D10
**************************************************************************/
#include "Tiny8kOLED.h"
#include <Wire.h>
#define BUTTON 10 //PA3
#define ENC_B 1 //PA5
#define ENC_A 5 //PB2
//Uncomment next line to clear out EEPROM and reset all high scores
//#define RESET_EEPROM
#define SLEEP_TIMEOUT 10000 //Amount of time no switch is pressed before going to sleep
uint32_t sleepTimeout = 0; //Used to timeout mode switch function to sleep function
bool volatile ignoreNextPress = false;
int8_t volatile rotaryDirection = 0;
bool volatile lastRotA = false;
#define MAX_ROTARY_COUNT 25374 //999 inches
long volatile ruler = 0; //ruler measurement
bool volatile rulerChanged = false;
#define PI 3.14
#define WHEEL_RADIUS 3.00 //in cm
#define RESOLUTION 20 //Steps per revolution
//--------------------------------------------------------------------
//Program Setup
void setup()
{
pinMode(BUTTON, INPUT_PULLUP);
pinMode(ENC_A, INPUT);
pinMode(ENC_B, INPUT);
//Attach interrupt handlers for handling rotary encoder
attachRotaryPinChangeInterrupt();
//Attach interrupt handler to wake up from sleep mode
attachInterrupt(digitalPinToInterrupt(BUTTON),switchInterrupt,CHANGE);
oled.begin();
rulerChanged = true; //force display update
sleepTimeout = millis() + SLEEP_TIMEOUT;
}
//--------------------------------------------------------------------
//Handle pin change interrupt when button is pressed
void switchInterrupt()
{
}
//--------------------------------------------------------
// Attach the pin change interrupts for the rotary encoder
void attachRotaryPinChangeInterrupt()
{
attachInterrupt(ENC_A, rotaryInterrupt, CHANGE);
}
//--------------------------------------------------------
// Detach the pin change interrupts for the rotary encoder
void detachRotaryPinChangeInterrupt()
{
detachInterrupt(ENC_A);
}
//---------------------------------------------------------------------
// Interrupt Handler: Rotary encoder has moved
void rotaryInterrupt()
{
if (!digitalRead(ENC_A) && lastRotA)
{
if (digitalRead(ENC_B))
{
ruler = min(ruler + 1, MAX_ROTARY_COUNT - 1);
}
else
{
ruler = max(ruler - 1, 0);
}
rulerChanged = true;
}
lastRotA = digitalRead(ENC_A);
}
//--------------------------------------------------------------------
//Program Loop
void loop()
{
if (millis() >= sleepTimeout)
{
system_sleep();
}
else if (digitalRead(BUTTON) == LOW)
{
delay(10); //Debounce
if (digitalRead(BUTTON) == LOW)
{
//Zero ruler
ruler = 0;
displayRuler();
//Wait for button release
while (digitalRead(BUTTON) == LOW)
{
yield();
}
}
sleepTimeout = millis() + SLEEP_TIMEOUT;
}
else if (rulerChanged)
{
displayRuler();
rulerChanged = false;
sleepTimeout = millis() + SLEEP_TIMEOUT;
}
else
{
delay(100);
}
}
//--------------------------------------------------------------------
// display current distance
void displayRuler()
{
float cm = (2 * PI * WHEEL_RADIUS * ruler) / RESOLUTION;
long mm10 = floor(cm * 100 + 0.5);
//oled.clear(); //all black
oled.setFont(FONT16X32);
oled.setCursor(4,0);
displayNumber(mm10,true);
oled.setCursor(4,4);
displayNumber(mm10 * 100 / 254,false);
oled.setFont(FONT8X16);
oled.setCursor(108,2);
oled.print("mm");
oled.setCursor(108,6);
oled.print("in");
}
//--------------------------------------------------------------------
// display current distance
void displayNumber(uint32_t number, bool isMM)
{
char buffer[10];
if (isMM)
{
sprintf(buffer,"%4d\x2e%01d",(int)number / 10, (int)(number % 10));
}
else
{
sprintf(buffer, "%3d\x2e%02d", (int)(number / 100), (int)(number % 100));
}
oled.print(buffer);
}
//--------------------------------------------------------------------
//Shut down OLED and put ATtiny to sleep
//Will wake up when LEFT button is pressed
void system_sleep()
{
detachRotaryPinChangeInterrupt();
interrupts();
oled.ssd1306_sleep();
delay(100);
attachRotaryPinChangeInterrupt();
sleepTimeout = millis() + SLEEP_TIMEOUT;
}
/*
* 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
* Modified by M.V. Predoi 2018-09-25
*/
#include <stdint.h>
#include <Arduino.h>
#include <Wire.h>
#include <util/delay.h>
/* Uncomment from the 3 line below this note, the fonts you intend to use:
* FONT6X8 = 764 bytes
* FONT8X16 = 1776 bytes
* FONT16X32= 1334 bytes
*/
#define FONT6X8 0
#define FONT8X16 1
#define FONT16X32 2
// ----------------------------------------------------------------------------
#ifndef SSD1306
#define SSD1306 0x3C // Slave address
#endif
// ----------------------------------------------------------------------------
class SSD1306Device: public Print {
public:
SSD1306Device(void);
void begin(void);
void setFont(uint8_t font);
void ssd1306_send_command(uint8_t command);
void ssd1306_send_data_byte(uint8_t byte);
void ssd1306_send_data_start(void);
void ssd1306_send_data_stop(void);
void setCursor(uint8_t x, uint8_t y);
void fill(uint8_t fill);
void clear(void);
void bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]);
void ssd1306_send_command_start(void);
void ssd1306_send_command_stop(void);
void ssd1306_char_f8x16(uint8_t x, uint8_t y, const char ch[]);
void ssd1306_sleep();
virtual size_t write(byte c);
using Print::write;
};
extern SSD1306Device oled;
// ----------------------------------------------------------------------------
/*
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
*
* @created: 2014-08-12
* @author: Neven Boyanov
* @modifications: John Bradnam 2021-05-03
* - modified for ATtiny1614
* - added sleep method
* - rotated display 180%
*/
// ----------------------------------------------------------------------------
#include <stdlib.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/pgmspace.h>
#include "Tiny8kOLED.h"
#ifdef FONT6X8 // In case font6x8 is defined: load it
#include "font6x8.h"
#endif
#ifdef FONT8X16 // In case font8x16 is defined: load it
#include "font8x16.h"
#endif
#ifdef FONT16X32 // In case font16x32 is defined: load it
#include "font16x32.h"
#endif
// ----------------------------------------------------------------------------
const uint8_t ssd1306_init_sequence [] PROGMEM = { // Initialization Sequence
0xAE, // Display OFF (sleep mode)
0x20, 0b00, // Set Memory Addressing Mode
// 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
// 10=Page Addressing Mode (RESET); 11=Invalid
0xB0, // Set Page Start Address for Page Addressing Mode, 0-7
0xC0, // Set COM Output Scan Direction (INC or DEC 0xC0 or 0xC8) <==
0x00, // ---set low column address
0x10, // ---set high column address
0x40, // --set start line address
0x81, 0x3F, // Set contrast control register
0xA0, // Set Segment Re-map. (A0=address mapped; A1=address 127 mapped) <==
0xA6, // Set display mode. A6=Normal; A7=Inverse
0xA8, 0x3F, // Set multiplex ratio(1 to 64)
0xA4, // Output RAM to Display
// 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
0xD3, 0x00, // Set display offset. 00 = no offset
0xD5, // --set display clock divide ratio/oscillator frequency
0xF0, // --set divide ratio
0xD9, 0x22, // Set pre-charge period
0xDA, 0x12, // Set com pins hardware configuration
0xDB, // --set vcomh
0x20, // 0x20,0.77xVcc
0x8D, 0x14, // Set DC-DC enable
0xAF // Display ON in normal mode
};
uint8_t oledFont, ci, oledX, oledY;
SSD1306Device::SSD1306Device(void){}
void SSD1306Device::begin(void)
{
Wire.begin();
for (uint8_t i = 0; i < sizeof (ssd1306_init_sequence); i++) {
ssd1306_send_command(pgm_read_byte(&ssd1306_init_sequence[i]));
}
clear();
}
void SSD1306Device::setFont(uint8_t font)
{
oledFont = font;
}
void SSD1306Device::ssd1306_send_command_start(void) {
Wire.beginTransmission(SSD1306);
Wire.write(0x00); // write command
}
void SSD1306Device::ssd1306_send_command_stop(void) {
Wire.endTransmission();
}
void SSD1306Device::ssd1306_send_data_byte(uint8_t byte)
{
/*
//if(Wire.writeAvailable()){
ssd1306_send_data_stop();
ssd1306_send_data_start();
//}
*/
Wire.write(byte);
}
void SSD1306Device::ssd1306_send_command(uint8_t command)
{
ssd1306_send_command_start();
Wire.write(command);
ssd1306_send_command_stop();
}
void SSD1306Device::ssd1306_send_data_start(void)
{
Wire.beginTransmission(SSD1306);
Wire.write(0x40); //write data
}
void SSD1306Device::ssd1306_send_data_stop(void)
{
Wire.endTransmission();
}
void SSD1306Device::setCursor(uint8_t x, uint8_t y)
{
ssd1306_send_command_start();
Wire.write(0xb0 + y);
Wire.write(((x & 0xf0) >> 4) | 0x10); // | 0x10
Wire.write((x & 0x0f) | 0x01); // | 0x01
ssd1306_send_command_stop();
oledX = x;
oledY = y;
}
void SSD1306Device::clear(void)
{
fill(0x00);
}
void SSD1306Device::fill(uint8_t fill)
{
uint8_t m,n,o;
for (m = 0; m < 8; m++)
{
ssd1306_send_command(0xb0 + m); // page0 - page1
ssd1306_send_command(0x00); // low column start address
ssd1306_send_command(0x10); // high column start address
ssd1306_send_data_start();
for (n = 0, o = 0; n < 128; n++)
{
ssd1306_send_data_byte(fill);
o++;
if (o == BUFFER_LENGTH - 1)
{
ssd1306_send_data_stop();
ssd1306_send_data_start();
o = 0;
}
}
ssd1306_send_data_stop();
}
setCursor(0, 0);
}
size_t SSD1306Device::write(byte c) {
// This function is modified to work also with 16x32 fonts for digits
// Useful to display only numerical results in Largest Size!
//=================================================================
#ifdef FONT16X32
if (oledFont==2) {
// If "font16x32.h" contains only 10 symbols (0..9) rotated 90deg. right, then:
ci = c - 44; // Only symbols ,-./0...9: are available in 13kB file [0=char(16)]
if (oledX > 112){ // long numbers are cut to max 8 digits
return 1;
}
for (uint8_t j = 3; j > 1 ; j--) { // Send from top to bottom 2*16 bytes on rows
ssd1306_send_data_start();
for (uint8_t i = 0; i < 16; i++) { // Send 16 bytes as rows, at the same y position
Wire.write(pgm_read_byte(&ssd1306xled_font16x32[ci * 64 + 4*i +j]));
}
ssd1306_send_data_stop();
setCursor(oledX, oledY + 4-j); // Prepare position of next row of 16 bytes under the first one
}
setCursor(oledX, oledY-1); // Return a row higher
for (uint8_t j = 3; j > 1 ; j--) { // Send from the lower half 2*16 bytes on rows
ssd1306_send_data_start();
for (uint8_t i = 0; i < 16; i++) { // Send from top to bottom 2*16 bytes
Wire.write(pgm_read_byte(&ssd1306xled_font16x32[ci * 64 + 4*i +j -2]));
}
ssd1306_send_data_stop();
setCursor(oledX, oledY+1); // Relative move lower by 1 byte for last 16 bytes
}
setCursor(oledX+16, oledY-4); // Move cursor for next digit
}
#endif
//==================================================================
#ifdef FONT8X16
if(oledFont==1) {
if (c == '\n') {
oledY++;
if (oledY > 6) {
oledY = 6;
}
setCursor(0, oledY);
return 1;
}
ci = c - 32;
if (oledX > 120) {
oledY+=2;
if (oledY > 6) {
oledY = 6;
}
setCursor(0, oledY);
}
ssd1306_send_data_start();
for (uint8_t i = 0; i < 8; i++) {
Wire.write(pgm_read_byte(&ssd1306xled_font8x16[ci * 16 + i]));
}
ssd1306_send_data_stop();
setCursor(oledX, oledY + 1);
ssd1306_send_data_start();
for (uint8_t i = 0; i < 8; i++) {
Wire.write(pgm_read_byte(&ssd1306xled_font8x16[ci * 16 + i + 8]));
}
ssd1306_send_data_stop();
setCursor(oledX + 8, oledY - 1);
}
#endif
//==================================================================
#ifdef FONT6X8
if(oledFont== 0) {
if (c == '\n') {
if (oledFont == FONT6X8) {
oledY++;
if (oledY > 7) {
oledY = 7;
}
setCursor(0, oledY);
return 1;
}
}
ci = c - 32;
if (oledX > 122) {
oledY++;
if (oledY > 7) {
oledY = 7;
}
setCursor(0, oledY);
}
ssd1306_send_data_start();
for (uint8_t i= 0; i < 6; i++) {
ssd1306_send_data_byte(pgm_read_byte(&ssd1306xled_font6x8[ci * 6 + i]));
}
ssd1306_send_data_stop();
oledX+=6; // we don't need to call setCursor for every character.
}
#endif
//==================================================================
return 1;
}
void SSD1306Device::bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[])
{
uint16_t j = 0;
uint8_t y, x;
// if (y1 % 8 == 0) y = y1 / 8; // else y = y1 / 8 + 1; // tBUG :: this does nothing as y is initialized below
// THIS PARAM rule on y makes any adjustment here WRONG //usage oled.bitmap(START X IN PIXELS, START Y IN ROWS OF 8 PIXELS, END X IN PIXELS, END Y IN ROWS OF 8 PIXELS, IMAGE ARRAY);
for (y = y0; y < y1; y++)
{
setCursor(x0,y);
ssd1306_send_data_start();
for (x = x0; x < x1; x++)
{
ssd1306_send_data_byte(pgm_read_byte(&bitmap[j++]));
}
ssd1306_send_data_stop();
}
setCursor(0, 0);
}
//--------------------- Extra -------------------------------
//Shut down OLED and put ATtiny to sleep
//Will wake up when LEFT button is pressed
void SSD1306Device::ssd1306_sleep()
{
clear();
ssd1306_send_command(0xAE);
//cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
sleep_mode(); // System actually sleeps here
sleep_disable(); // System continues execution here when watchdog timed out
//sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
ssd1306_send_command(0xAF);
}
SSD1306Device oled;
// ----------------------------------------------------------------------------
/*
* 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
* modified for 16x32 fonts: 2017-01-12 @author: M. V. Predoi
*/
// ----------------------------------------------------------------------------
#include <avr/pgmspace.h>
// ----------------------------------------------------------------------------
/* Standard ASCII 16x32 font */
const uint8_t ssd1306xled_font16x32 [] PROGMEM = {
// @0 ',' (16 pixels wide)
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x40, 0x00, 0x00, 0x00, // #
0xE3, 0x80, 0x00, 0x00, // ### ###
0x7F, 0x80, 0x00, 0x00, // ########
0x3F, 0x80, 0x00, 0x00, // #######
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
// @32 '-' (16 pixels wide)
0x00, 0x00, 0x00,0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0xE0, 0x00, // ###
0x00, 0x00, 0xE0, 0x00, // ###
0x00, 0x00, 0xE0, 0x00, // ###
0x00, 0x00, 0xE0, 0x00, // ###
0x00, 0x00, 0xE0, 0x00, // ###
0x00, 0x00, 0xE0, 0x00, // ###
0x00, 0x00, 0xE0, 0x00, // ###
0x00, 0x00, 0xE0, 0x00, // ###
0x00, 0x00, 0xE0, 0x00, // ###
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
// @48 '.' (16 pixels wide)
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0xE0, 0x00, 0x00, 0x00, // ###
0xE0, 0x00, 0x00, 0x00, // ###
0xE0, 0x00, 0x00, 0x00, // ###
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
// @64 '/' (16 pixels wide)
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x80, 0x00, 0x00, 0x00, // #
0xF8, 0x00, 0x00, 0x00, // #####
0xFF, 0x80, 0x00, 0x00, // #########
0x7F, 0xF8, 0x00, 0x00, // ############
0x07, 0xFF, 0x80, 0x00, // ############
0x00, 0x7F, 0xF8, 0x00, // ############
0x00, 0x07, 0xFF, 0x80, // ############
0x00, 0x00, 0x7F, 0xF8, // ############
0x00, 0x00, 0x07, 0xF8, // ########
0x00, 0x00, 0x00, 0x78, // ####
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
// @128 '0' (16 pixels wide)
0x00, 0xFF, 0xF8, 0x00, // #############
0x0F, 0xFF, 0xFF, 0x00, // ####################
0x1F, 0xFF, 0xFF, 0xC0, // #######################
0x3F, 0x00, 0x07, 0xE0, // ###### ######
0x78, 0x00, 0x00, 0xF0, // #### ####
0xF0, 0x00, 0x00, 0x78, // #### ####
0xE0, 0x00, 0x00, 0x38, // ### ###
0xE0, 0x00, 0x00, 0x38, // ### ###
0xE0, 0x00, 0x00, 0x38, // ### ###
0xF0, 0x00, 0x00, 0x78, // #### ####
0x78, 0x00, 0x00, 0xF0, // #### ####
0x3F, 0x00, 0x07, 0xE0, // ###### ######
0x1F, 0xFF, 0xFF, 0xC0, // #######################
0x07, 0xFF, 0xFF, 0x00, // ###################
0x00, 0xFF, 0xF8, 0x00, // #############
0x00, 0x00, 0x00, 0x00, //
// @192 '1' (16 pixels wide)
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x38, 0x00, // ###
0x00, 0x00, 0x1C, 0x00, // ###
0x00, 0x00, 0x0E, 0x00, // ###
0x00, 0x00, 0x0F, 0x00, // ####
0x00, 0x00, 0x07, 0x80, // ####
0x00, 0x00, 0x03, 0xC0, // ####
0xFF, 0xFF, 0xFF, 0xF0, // ############################
0xFF, 0xFF, 0xFF, 0xF8, // #############################
0xFF, 0xFF, 0xFF, 0xF8, // #############################
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
// @256 '2' (16 pixels wide)
0xE0, 0x00, 0x0E, 0x00, // ### ###
0xF8, 0x00, 0x0F, 0xC0, // ##### ######
0xFE, 0x00, 0x0F, 0xE0, // ####### #######
0xFF, 0x00, 0x01, 0xF0, // ######## #####
0xEF, 0x80, 0x00, 0x70, // ### ##### ###
0xE7, 0xC0, 0x00, 0x78, // ### ##### ####
0xE1, 0xE0, 0x00, 0x38, // ### #### ###
0xE0, 0xF0, 0x00, 0x38, // ### #### ###
0xE0, 0x78, 0x00, 0x38, // ### #### ###
0xE0, 0x3E, 0x00, 0x38, // ### ##### ###
0xE0, 0x1F, 0x00, 0x78, // ### ##### ####
0xE0, 0x0F, 0xC1, 0xF0, // ### ###### #####
0xE0, 0x03, 0xFF, 0xE0, // ### #############
0xE0, 0x01, 0xFF, 0xC0, // ### ###########
0xE0, 0x00, 0x3F, 0x00, // ### ######
0x00, 0x00, 0x00, 0x00, //
// @320 '3' (16 pixels wide)
0x07, 0x00, 0x03, 0x00, // ### ##
0x1F, 0x00, 0x03, 0xC0, // ##### ####
0x3F, 0x00, 0x03, 0xE0, // ###### #####
0x7C, 0x00, 0x00, 0xF0, // ##### ####
0x70, 0x00, 0x00, 0x78, // ### ####
0xE0, 0x00, 0x00, 0x38, // ### ###
0xE0, 0x03, 0x80, 0x38, // ### ### ###
0xE0, 0x03, 0x80, 0x38, // ### ### ###
0xE0, 0x03, 0x80, 0x38, // ### ### ###
0xF0, 0x03, 0xC0, 0x78, // #### #### ####
0x70, 0x07, 0xE0, 0xF0, // ### ###### ####
0x7C, 0x1F, 0xFF, 0xE0, // ##### ################
0x3F, 0xFE, 0x7F, 0xC0, // ############# #########
0x1F, 0xFC, 0x1F, 0x80, // ########### ######
0x03, 0xF0, 0x00, 0x00, // ######
0x00, 0x00, 0x00, 0x00, //
// @384 '4' (16 pixels wide)
0x01, 0xE0, 0x00, 0x00, // ####
0x01, 0xF8, 0x00, 0x00, // ######
0x01, 0xFE, 0x00, 0x00, // ########
0x01, 0xDF, 0x80, 0x00, // ### ######
0x01, 0xC7, 0xE0, 0x00, // ### ######
0x01, 0xC1, 0xF0, 0x00, // ### #####
0x01, 0xC0, 0x7C, 0x00, // ### #####
0x01, 0xC0, 0x3F, 0x00, // ### ######
0x01, 0xC0, 0x0F, 0xC0, // ### ######
0x01, 0xC0, 0x03, 0xF0, // ### ######
0xFF, 0xFF, 0xFF, 0xF8, // #############################
0xFF, 0xFF, 0xFF, 0xF8, // #############################
0xFF, 0xFF, 0xFF, 0xF8, // #############################
0x01, 0xC0, 0x00, 0x00, // ###
0x01, 0xC0, 0x00, 0x00, // ###
0x01, 0xC0, 0x00, 0x00, // ###
// @448 '5' (16 pixels wide)
0x07, 0x03, 0xC0, 0x00, // ### ####
0x1F, 0x03, 0xFF, 0x80, // ##### ###########
0x3F, 0x03, 0xFF, 0xF8, // ###### ###############
0x7C, 0x01, 0xFF, 0xF8, // ##### ##############
0x70, 0x00, 0xE0, 0x78, // ### ### ####
0xE0, 0x00, 0x70, 0x38, // ### ### ###
0xE0, 0x00, 0x70, 0x38, // ### ### ###
0xE0, 0x00, 0x70, 0x38, // ### ### ###
0xE0, 0x00, 0x70, 0x38, // ### ### ###
0xF0, 0x00, 0xF0, 0x38, // #### #### ###
0x78, 0x01, 0xE0, 0x38, // #### #### ###
0x7E, 0x03, 0xE0, 0x38, // ###### ##### ###
0x1F, 0xFF, 0xC0, 0x38, // ############### ###
0x0F, 0xFF, 0x80, 0x38, // ############# ###
0x01, 0xFC, 0x00, 0x00, // #######
0x00, 0x00, 0x00, 0x00, //
// @512 '6' (16 pixels wide)
0x00, 0xFF, 0xF0, 0x00, // ############
0x0F, 0xFF, 0xFF, 0x00, // ####################
0x1F, 0xFF, 0xFF, 0xC0, // #######################
0x3E, 0x07, 0x83, 0xE0, // ##### #### #####
0x78, 0x01, 0xC0, 0xF0, // #### ### ####
0xF0, 0x01, 0xC0, 0x70, // #### ### ###
0xE0, 0x00, 0xE0, 0x38, // ### ### ###
0xE0, 0x00, 0xE0, 0x38, // ### ### ###
0xE0, 0x00, 0xE0, 0x38, // ### ### ###
0xF0, 0x01, 0xE0, 0x38, // #### #### ###
0x78, 0x01, 0xC0, 0x78, // #### ### ####
0x7C, 0x07, 0xC0, 0xF0, // ##### ##### ####
0x3F, 0xFF, 0x83, 0xE0, // ############### #####
0x0F, 0xFF, 0x03, 0xC0, // ############ ####
0x03, 0xFC, 0x03, 0x00, // ######## ##
0x00, 0x00, 0x00, 0x00, //
// @576 '7' (16 pixels wide)
0x00, 0x00, 0x00, 0x38, // ###
0x00, 0x00, 0x00, 0x38, // ###
0x00, 0x00, 0x00, 0x38, // ###
0xF8, 0x00, 0x00, 0x38, // ##### ###
0xFF, 0xC0, 0x00, 0x38, // ########## ###
0xFF, 0xF8, 0x00, 0x38, // ############# ###
0x07, 0xFF, 0x00, 0x38, // ########### ###
0x00, 0x3F, 0xC0, 0x38, // ######## ###
0x00, 0x07, 0xF0, 0x38, // ####### ###
0x00, 0x00, 0xFC, 0x38, // ###### ###
0x00, 0x00, 0x3F, 0x38, // ###### ###
0x00, 0x00, 0x0F, 0xB8, // ##### ###
0x00, 0x00, 0x03, 0xF8, // #######
0x00, 0x00, 0x00, 0xF8, // #####
0x00, 0x00, 0x00, 0x38, // ###
0x00, 0x00, 0x00, 0x00, //
// @640 '8' (16 pixels wide)
0x07, 0xF0, 0x00, 0x00, // #######
0x1F, 0xFC, 0x1F, 0x80, // ########### ######
0x3F, 0xFE, 0x7F, 0xE0, // ############# ##########
0x7C, 0x1E, 0xFF, 0xF0, // ##### #### ############
0x70, 0x07, 0xE0, 0xF0, // ### ###### ####
0xF0, 0x03, 0xC0, 0x78, // #### #### ####
0xE0, 0x03, 0x80, 0x38, // ### ### ###
0xE0, 0x03, 0x80, 0x38, // ### ### ###
0xE0, 0x03, 0x80, 0x38, // ### ### ###
0xE0, 0x07, 0xC0, 0x78, // ### ##### ####
0x70, 0x07, 0xE0, 0xF0, // ### ###### ####
0x7C, 0x1E, 0xFF, 0xF0, // ##### #### ############
0x3F, 0xFC, 0x7F, 0xC0, // ############ #########
0x1F, 0xF8, 0x1F, 0x80, // ########## ######
0x07, 0xF0, 0x00, 0x00, // #######
0x00, 0x00, 0x00, 0x00, //
// @704 '9' (16 pixels wide)
0x06, 0x00, 0xFE, 0x00, // ## #######
0x1E, 0x07, 0xFF, 0xC0, // #### #############
0x7E, 0x0F, 0xFF, 0xE0, // ###### ###############
0x78, 0x1F, 0x03, 0xF0, // #### ##### ######
0xF0, 0x1C, 0x00, 0xF0, // #### ### ####
0xE0, 0x3C, 0x00, 0x78, // ### #### ####
0xE0, 0x38, 0x00, 0x38, // ### ### ###
0xE0, 0x38, 0x00, 0x38, // ### ### ###
0xE0, 0x38, 0x00, 0x38, // ### ### ###
0x70, 0x1C, 0x00, 0x78, // ### ### ####
0x78, 0x1C, 0x00, 0xF0, // #### ### ####
0x3E, 0x0F, 0x01, 0xE0, // ##### #### ####
0x1F, 0xFF, 0xFF, 0xC0, // #######################
0x07, 0xFF, 0xFF, 0x80, // ####################
0x00, 0x7F, 0xF8, 0x00, // ############
0x00, 0x00, 0x00, 0x00, //
// @768 ':' (16 pixels wide)
0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0xE0, 0x00, 0x38, // ### ###
0x00, 0xE0, 0x00, 0x38, // ### ###
0x00, 0xE0, 0x00, 0x38, // ### ###
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, //
};
/*
* 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
};
// ----------------------------------------------------------------------------
/*
* 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
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // horiz lines
};
// ----------------------------------------------------------------------------
Comments