John Bradnam
Published © GPL3+

3S Battery Charger

Build your own Li-Po & Li-ion Balance Charger for under $10

IntermediateFull instructions provided8 hours2,911
3S Battery Charger

Things used in this project

Hardware components

Microchip ATtiny1614 Microprocessor
×1
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
×1
Passive Components
3 x 3000 ohm 1% 0805 resistors, 3 x 1000 ohm 1% 0805 resistors, 3 x 0.1uF 0805 capacitors
×1
HX-3S-HJ20 3S Battery Balancing Module
×1
1117-50 Regulator
5V SOT223 regulator
×1
4 Pin JST 2.54mm socket
×1
DC Panel socket
×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

3S_Battery_Charger_V1.ino

C/C++
/**************************************************************************
 ATtiny1614 3S Battery Charger

 2021-08-10 John Bradnam (jbrad2089@gmail.com)
   Create program for ATtiny1614

 --------------------------------------------------------------------------
 Arduino IDE:
 --------------------------------------------------------------------------
  BOARD: ATtiny1614/1604/814/804/414/404/214/204
  Chip: ATtiny1614
  Clock Speed: 20MHz
  millis()/micros(): "Enabled (default timer)"
  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)
              +--------+
  
 **************************************************************************/

#include "Tiny8kOLED.h"   // This is the modified library (M.V. Predoi)
#include <Wire.h>

//Inputs
#define C3_PIN 10   //PA3
#define C2_PIN 1    //PA5
#define C1_PIN 2    //PA6

#define ADC_C3 ADC_MUXPOS_AIN3_gc
#define ADC_C2 ADC_MUXPOS_AIN5_gc
#define ADC_C1 ADC_MUXPOS_AIN6_gc

float supplyVoltage = 0;            //VDD from 5V regulator
float C3Voltage = 0;                //Last reading from C3 (12.6)
float C2Voltage = 0;                //Last reading from C2 (8.4)
float C1Voltage = 0;                //Last reading from C1 (4.7)

char sBuf[32];

//-------------------------------------------------------------------------
// Initialise Hardware
void setup(void)
{
  pinMode(C3_PIN, INPUT);
  pinMode(C2_PIN, INPUT);
  pinMode(C1_PIN, INPUT);

  //Setup ADC
  VREF.CTRLA = VREF_ADC0REFSEL_1V1_gc;
  ADC0.CTRLC = ADC_REFSEL_VDDREF_gc | ADC_PRESC_DIV256_gc; // 78kHz clock
  ADC0.CTRLA = ADC_ENABLE_bm;                              // Single, 10-bit

  measureSupplyVoltage();

  oled.begin();
  oled.clear();
  oled.setFont(FONT8X16);
  oled.setCursor(0,0);
  oled.print(F("C3:"));
  oled.setCursor(0,2);
  oled.print(F("C2:"));
  oled.setCursor(0,4);
  oled.print(F("C1:"));

}

//--------------------------------------------------------------------
// Main program loop
void loop(void)
{

  //Input voltages are feed through a voltage divider which
  //divides the input voltage by 4 so they need to be multiplied by 4. 
  C3Voltage = measureVoltage(ADC_C3) * 4;
  C2Voltage = measureVoltage(ADC_C2) * 4;
  C1Voltage = measureVoltage(ADC_C1) * 4;

  oled.setCursor(30,0);
  oled.print(String(C3Voltage,2)+"  ");
  oled.setCursor(80,0);
  oled.print(String(C3Voltage-C2Voltage,2)+" ");
  
  oled.setCursor(30,2);
  oled.print(String(C2Voltage,2)+"  ");
  oled.setCursor(80,2);
  oled.print(String(C2Voltage-C1Voltage,2)+" ");
  
  oled.setCursor(30,4);
  oled.print(String(C1Voltage,2)+"  ");
  oled.setCursor(80,4);
  oled.print(String(C1Voltage,2)+" ");

  delay(1000);
  
}

//--------------------------------------------------------------------------
// Measure supply voltage
// Source: David Johnson-Davies - www.technoblogy.com - 13th April 2021
void measureSupplyVoltage() 
{
  ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc;                  // Measure INTREF
  ADC0.COMMAND = ADC_STCONV_bm;                        // Start conversion
  while (ADC0.COMMAND & ADC_STCONV_bm);                // Wait for completion
  uint16_t adc_reading = ADC0.RES;                     // ADC conversion result
  supplyVoltage = 1126.4 / adc_reading;
}

//--------------------------------------------------------------------------
// Measure voltage of a given pin
// adcMux - ADC_Ax constant for the pin to measure
float measureVoltage(uint8_t adcMux) 
{
  ADC0.MUXPOS = adcMux;                                // Measure Analog pin
  ADC0.COMMAND = ADC_STCONV_bm;                        // Start conversion
  while (ADC0.COMMAND & ADC_STCONV_bm);                // Wait for completion
  uint16_t adc_reading = ADC0.RES;                     // ADC conversion result
  return supplyVoltage * adc_reading / 1024;
}

Tiny8kOLED.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
 * 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[]);
		virtual size_t write(byte c);
  		using Print::write;


};


extern SSD1306Device oled;

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

Tiny8kOLED.cpp

C/C++
/*
 * 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 <stdlib.h>
#include <avr/io.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
	0xC8,			// Set COM Output Scan Direction
	0x00,			// ---set low column address
	0x10,			// ---set high column address
	0x40,			// --set start line address
	0x81, 0x3F,		// Set contrast control register
	0xA1,			// 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;

// Program:    5248 bytes

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);
}


SSD1306Device oled;

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

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

141 projects • 167 followers

Comments