Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
Hand tools and fabrication machines | ||||||
| ||||||
|
This project is my make of Smart Servo Motor Tester with mAmp meter by fellow Hackster Science 3D. This build has a redesigned schematic, PCB, 3D printed case and software. The outward appearance and its operation is similar to the original.
DemonstrationThe STL files required for 3D printing are included. You can either print them yourself if you have access to a 3D printed or take them to a commercial 3D print shop.
The recommend Slicer settings are as follows:
"Case - Bottom V2.stl" - 0.2 layer height, no supports
"Case - Lid V2.stl" - 0.2 layer height, no supports
"Case - Text V2.stl" - 0.2 layer height, no supports, switch to contrasting color at start of layer 4.
"Case - Knobs V2.stl" - 0.1 layer height, no supports, switch to contrasting color at start of layer 140
"Case - Spacers V2.stl" - 0.1 layer height, no supports
Using double sided tape or glue, fix "Case - Text V2.stl" to "Case - Lid V2.stl". Drill out the four PCB mounts using a 2.5mm drill and create a thread using a 3mm tap.
SchematicThe following changes were made to the original design:
- Replaced Arduino Nano with a ATtiny1614 microprocessor
- Added a RC network to de-bounce the rotary encoder contacts and its switch contacts
- Changed the powering of the unit to use a standard power brick rather than the supply voltage from an ESC.
- Replaced the ammeter circuit from using a MAX471 3A to a simple LM358 OP-AMP circuit.
The PCB was designed for parts I already had around the workshop. The board contains a mixture of through hole components and Surface Mount Devices (SMD).
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.
NOTE:
0.96in OLED modules can come with the GND and VCC connections reversed. The PCB is designed for the module that has a pin layout of GND, VCC, SCL, SDA.
PCB is designed for OLED module on the left (note the change in position of GND & VCC)
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. I used my SMD Reflow Hot Plate to reflow the solder paste under the SMD components.
Add the links if your board is single-sided.
Add a 4 pin right angle male header to the copper side of the board. This header is only used to program the ATtiny1614.
Add a polarized 2 pin right angle male header to the copper side of the board. This is where the wires from the DC panel socket plug in.
On the component side add the two 4, 700 ohm 1/8W resistors, a 1N5819 1A Schottky diode, a 7805 5V regulator, 3 pin right-angle male header for the servo connection and a 4 pin straight female header for the OLED display module.
3D print "Case - Spacers V2.stl" and super glue them to the PCB as shown below.
Add the rotary encoder with switch and the potentiometer.
Plug in the OLED screen.
Screw the board to the case using four 6mm M4 screws.
You will probably need to trim the shaft of the potentiometer. Place the printed knob on first and measure the extra height that needs to be removed. Remove the knob and cut the measured amount from the end of the shaft with a Dremel rotary tool or similar. Chamfer the edges of the cut so the knob doesn't catch on any rough edges.
Add the DC panel socket and wire up to a 2 pin female polarized plug.
Dab some paint above the servo connector opening to identify the orientation of the servo plug.
Before closing up the case, connect the programmer to the pins and upload the software (see next section). On the picture below I used dabs of paint to help identify what the pins are. Red - 5V, Gray - UPDI, Blue - TX (not used) and black or unpainted is GND.
Unlike the earlier ATtiny series such as the ATtiny85, the ATtiny1614 uses 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.
Once the board has been installed in the IDE, select it from the Tools menu.
Select the ATtiny1614 board in your IDE
Select Board, chip, clock speed, COM port the Arduino Nano is connected and the programmer
The Programmer needs to be set to jtag2updi (megaTinyCore).
Open the sketch and upload it to the ATtiny1614.
ConclusionThis is a very useful tool. Maybe the ammeter part is a bit of an overkill (never really had the need for it before) but functionally it contains everything I need when building projects containing servos.
Thanks Science 3D for the inspiration for this project. It has been a rewarding build. 😃
/**
* 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);
}
/*--------------------------------------------------------
* 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;
}
}
/*
* 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
};
// ----------------------------------------------------------------------------
/*
* 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
};
// ----------------------------------------------------------------------------
Comments