Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 2 | ||||
| × | 7 | ||||
| × | 6 | ||||
| × | 6 | ||||
| × | 2 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
Hand tools and fabrication machines | ||||||
|
Perusing Thingiverse, I came across an Electronic Etch-a-sketch by liteul. It uses potentiometers for its X and Y drawing controls. While probably OK for sketching, they don't offer precise positioning like a rotary encoder can. So with this build I decided to replace the potentiometers with rotary encoders. Because the rotary encoders also incorporate push switches, this meant I could add more functionality.
Noise, Noisier, NoisestThe problem with any form of mechanical switch is that the contacts "bounce" when contact is made or broken. This is referred to as noise. Usually all switches have it in some form and a rotary encoder, being a pair of switches, is no different.
One way to handle bounce is through software via a debounce routine. When you detect a switch state change, you wait around 10mS and test the state of the switch again. If they don't match, the original state was caused by a contact bounce.
Hardware debouncing uses a RC (Resistor-Capacitor) network to suppress the contact bounces. The resistor and capacitor values are chosen to produce a 10mS delay. By adding a Schmitt trigger to the RC network, the result will be accurate and precise state changes.
I designed a simple circuit board that holds the electronic components, rotary encoders and the tactile switch used to clear the drawing canvas. The Eagle files have been included should you wish to have the board commercially made or do as I did and make it yourself. I used the Toner method.
The PCB is fixed to the top via the rotary encoders. I had to use a couple of washers between the rotary encoder and top so that the push button had sufficient room.
Wiring up the Nokia 5110 LCD displaySCLK to D13
DIN to D12
DC to D11
CS to D9
RST to D10
LIGHT to A0 via a 220 ohm resistor
Wiring up the Encoder boardLeft encoder A pin to D3
Left encoder B pin to D2
Left encoder Switch pin to D4
Right encoder A pin to D8
Right encoder B pin to D7
Right encoder Switch pin to D6
Reset switch to D5
Wiring up the battery and switchPositive battery terminal to RAW
Negative battery terminal to GND via ON/OFF switch
The code uses a modified LCD5110_Graphic library from Rinky-Dink Electronics. I added an extra screen buffer and a couple of functions to control it.
void updateFromCanvas(); //Transfers canvas buffer to screen buffer
void setCanvasMode(bool on); //On - writes to screen buffer also written to canvas
The
rotary encoder and switches are all interrupt driven using the pin change interrupt. The following variables are automatically updated by the interrupt handers:
int horzPosition;
int vertPosition;
bool leftEncoderPressed;
bool rightEncoderPressed;
bool switchPressed;
Because the interrupt handlers can update these variables at any time, any non-interrupt handler code that uses these variables needs to disable interrupts while processing them. Beware, the delay() function relies on interrupts and will block if interrupts are disabled when you invoke it.
Using the Etch-A-SketchThe Etch-A-Sketch has 4 drawing modes set by pressing the left knob:
DRAW mode
In Draw mode, the left knob will move the cursor left and right and the right knob will move the cursor up and down. By pressing the right knob, you can cycle between PEN DOWN, PEN UP or ERASE pen modes.
LINE mode
In Line mode, the left and right knobs will move the cursor left/right and up/down respectively and a flashing line is drawn between the start position and the current cursor position. Pressing the right button will permanently lock the line in place and start a new line. You can exit the current line by changing the drawing mode.
RECTANGLE mode
In Rectangle mode, the left and right knobs will move the cursor left/right and up/down respectively and a flashing rectangle is drawn between the start position and the current cursor position. Pressing the right button will permanently lock the rectangle in place and return you to DRAW mode.
CIRCLE mode
In Circle mode, the left and right knobs will move the cursor left/right and up/down respectively and a flashing circle is drawn centered on the start position with a radius to the current cursor position. Pressing the right button will permanently lock the circle in place and return you to DRAW mode. Note: the Nokia 5110 LCD doesn't have a 1:1 pixel width/height ratio. The circle won't be round.
Centre button
The centre button will clear the canvas.
Final thoughtsThere is plenty of Flash and RAM to extend the code. This project was a nice diversion from the boredom of home isolation during this pandemic.
// Etch-A-Sketch V1
// by John Bradnam (jbrad2089@gmail.com)
//Modified LCD5110_Graph to have extra buffer for canvas and the ability to read from screen buffer
//New functions:
// void updateFromCanvas(); //Transfers canvas buffer to screen buffer
// void setCanvasMode(bool on); //On - writes to screen buffer also written to canvas
// bool getPixel(uint16_t x, uint16_t y); //Returns true if pixel at x,y is on in the screen buffer
#include "LCD5110_Graph_Ex.h"
//Nokia 5110
#define SCLK 13
#define DIN 12
#define DC 11
#define CS_LCD 9
#define RST 10
#define LIGHT A0
//Left encoder
#define E1S 4
#define E1A 3
#define E1B 2
//Right encoder
#define E2S 6
#define E2A 8
#define E2B 7
//Switch - Active LOW
#define SWITCH 5
#define SCREEN_WIDTH 84
#define SCREEN_HEIGHT 48
#define DRAW_AREA_MAX_WIDTH 79
#define DRAW_AREA_MAX_HEIGHT 43
bool lastE1A = false;
bool lastE2A = false;
bool lastSWITCH = false;
int horzPosition = SCREEN_WIDTH / 2;
int vertPosition = SCREEN_HEIGHT / 2;
int lastHorzPosition = -1;
int lastVertPosition = -1;
uint16_t switchDebounceTimeout = 0;
bool leftEncoderPressed = false;
bool rightEncoderPressed = false;
bool switchPressed = false;
int lineHorzPosition = 0; //Start coordinates of line in line mode
int lineVertPosition = 0;
#define LINE_FLASH_DELAY 100;
uint16_t lineFlashTimeout = 0;
bool lineVisible = false;
enum DRAW_MODE { DRAW, LINE, RECT, CIRCLE };
DRAW_MODE drawMode = DRAW;
enum PEN_MODE { PEN_DOWN, PEN_UP, ERASER };
PEN_MODE penMode = PEN_DOWN;
LCD5110 myGLCD(SCLK,DIN,DC,RST,CS_LCD);
extern uint8_t SmallFont[];
//extern unsigned char TinyFont[];
struct point {
uint8_t x;
uint8_t y;
};
point cursorCordinates[8] = {{0,2},{1,2},{3,2},{4,2},{2,0},{2,1},{2,3},{2,4}};
void pciSetup(byte pin)
{
*digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin
PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}
void setup()
{
Serial.begin(115200);
pinMode(E1A,INPUT);
pinMode(E1B,INPUT);
pinMode(E1S,INPUT);
pinMode(E2A,INPUT);
pinMode(E2B,INPUT);
pinMode(E2S,INPUT);
pinMode(SWITCH,INPUT);
pinMode(LIGHT, OUTPUT);
digitalWrite(LIGHT, HIGH);
myGLCD.InitLCD();
myGLCD.setContrast(65); //Default 70
myGLCD.setFont(SmallFont);
randomSeed(analogRead(7));
pciSetup(E1A);
pciSetup(E1S);
pciSetup(E2A);
pciSetup(E2S);
pciSetup(SWITCH);
interrupts();
myGLCD.clrScr();
myGLCD.drawLine(0,1,83,1);
myGLCD.print("ETCH-A-SKETCH", CENTER, 4);
myGLCD.drawLine(0,14,83,14);
myGLCD.print("Design by", CENTER, 25);
myGLCD.print("John Bradnam", CENTER, 35);
myGLCD.update();
delay(3000);
//Start out in draw mode
resetCanvas();
}
//Main program loop
void loop()
{
switch(drawMode)
{
case DRAW: drawLoop(); break;
case LINE: lineLoop(); break;
case RECT: rectLoop(); break;
case CIRCLE: circleLoop(); break;
}
//Reset button
if (switchPressed)
{
switchPressed = false;
resetCanvas();
}
//Test if user wants menu
if (leftEncoderPressed)
{
leftEncoderPressed = false;
//Change draw status
rightEncoderPressed = false;
drawMode = (drawMode == CIRCLE) ? DRAW : (DRAW_MODE)((int)drawMode + 1);
flashDrawStatus();
//Initialise incase of line mode
lineHorzPosition = horzPosition;
lineVertPosition = vertPosition;
lineFlashTimeout = millis() + LINE_FLASH_DELAY;
}
}
//------------------------------------------------------------------------------------
// Interrupt handlers
//------------------------------------------------------------------------------------
ISR (PCINT0_vect) // handle pin change interrupt for D8 to D13 here
{
if (!digitalRead(E2A) && lastE2A)
{
vertPosition = min(max(vertPosition + ((digitalRead(E2B)) ? 1 : -1), 0), DRAW_AREA_MAX_HEIGHT);
}
lastE2A = digitalRead(E2A);
}
ISR (PCINT2_vect) // handle pin change interrupt for D0 to D7 here
{
if (!digitalRead(E1A) && lastE1A)
{
horzPosition = min(max(horzPosition + ((digitalRead(E1B)) ? 1 : -1), 0), DRAW_AREA_MAX_WIDTH);
}
else if (digitalRead(E1S))
{
leftEncoderPressed = true;
}
else if (digitalRead(E2S))
{
rightEncoderPressed = true;
}
else //if (digitalRead(SWITCH) != lastSWITCH)
{
/*
if (digitalRead(SWITCH) == LOW)
{
switchDebounceTimeout = millis() + 10;
}
else if (switchDebounceTimeout > 0 && millis() > switchDebounceTimeout)
{
switchDebounceTimeout = 0;
switchPressed = true;
}
*/
if (digitalRead(SWITCH) == LOW)
{
if (switchDebounceTimeout > 0 && millis() > switchDebounceTimeout)
{
switchDebounceTimeout = 0;
switchPressed = true;
}
else
{
switchDebounceTimeout = millis() + 10;
}
}
}
lastE1A = digitalRead(E1A);
lastSWITCH = digitalRead(SWITCH);
}
//------------------------------------------------------------------------------------
// Reset button handler
//------------------------------------------------------------------------------------
//Clear screen and draw border
void resetCanvas()
{
noInterrupts();
lastHorzPosition = -1;
lastVertPosition = -1;
myGLCD.setCanvasMode(true);
myGLCD.clrScr();
myGLCD.drawRect(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
myGLCD.setCanvasMode(false);
interrupts();
myGLCD.update();
drawMode = DRAW;
}
//Clears the white space aroud the boarder
void clearBorderSpace()
{
myGLCD.clrRect(1, 1, SCREEN_WIDTH - 2, SCREEN_HEIGHT - 2);
}
//------------------------------------------------------------------------------------
// draw mode loop
//------------------------------------------------------------------------------------
void drawLoop()
{
if (lastHorzPosition != horzPosition || lastVertPosition != vertPosition)
{
noInterrupts();
if (lastHorzPosition != -1)
{
drawCursor(lastHorzPosition, lastVertPosition, false);
}
drawCursor(horzPosition, vertPosition, true);
if (penMode != PEN_UP && lastHorzPosition != -1)
{
//Serial.println("X1,Y1,X2,Y2: " + String(lastHorzPosition + 2) + ", " + String(lastVertPosition + 2) + ", " + String(horzPosition + 2) + ", " + String(vertPosition + 2));
myGLCD.setCanvasMode(true);
switch (penMode)
{
case PEN_DOWN:
myGLCD.setPixel(lastHorzPosition + 2, lastVertPosition + 2);
myGLCD.drawLine(lastHorzPosition + 2, lastVertPosition + 2, horzPosition + 2,vertPosition + 2);
myGLCD.setPixel(horzPosition + 2,vertPosition + 2);
break;
case ERASER:
myGLCD.clrPixel(lastHorzPosition + 2, lastVertPosition + 2);
myGLCD.clrLine(lastHorzPosition + 2, lastVertPosition + 2, horzPosition + 2,vertPosition + 2);
myGLCD.clrPixel(horzPosition + 2, vertPosition + 2);
break;
}
myGLCD.setCanvasMode(false);
}
lastHorzPosition = horzPosition;
lastVertPosition = vertPosition;
interrupts();
myGLCD.update();
}
if (rightEncoderPressed)
{
//Change pen status
rightEncoderPressed = false;
penMode = (penMode == ERASER) ? PEN_DOWN : (PEN_MODE)((int)penMode + 1);
flashPenStatus();
}
delay(100);
}
//Draws a cursor at x, y
void drawCursor(uint8_t x, uint8_t y, bool on)
{
myGLCD.updateFromCanvas();
if (on)
{
for (int i = 0; i < 8; i++)
{
myGLCD.setPixel(cursorCordinates[i].x + x, cursorCordinates[i].y + y);
}
}
}
//flash the pen status
void flashPenStatus()
{
switch (penMode)
{
case PEN_DOWN: myGLCD.print(" PEN DOWN ", CENTER, 20); break;
case PEN_UP: myGLCD.print(" PEN UP ", CENTER, 20); break;
case ERASER: myGLCD.print(" ERASER ", CENTER, 20); break;
}
myGLCD.update();
delay(250);
noInterrupts();
myGLCD.updateFromCanvas();
lastHorzPosition = -1;
lastVertPosition = -1;
interrupts();
}
//flash the draw status
void flashDrawStatus()
{
switch (drawMode)
{
case DRAW: myGLCD.print(" DRAW ", CENTER, 20); break;
case LINE: myGLCD.print(" LINE ", CENTER, 20); break;
case RECT: myGLCD.print(" RECTANGLE ", CENTER, 20); break;
case CIRCLE: myGLCD.print(" CIRCLE ", CENTER, 20); break;
}
myGLCD.update();
delay(250);
noInterrupts();
myGLCD.updateFromCanvas();
lastHorzPosition = -1;
lastVertPosition = -1;
interrupts();
}
//------------------------------------------------------------------------------------
// line mode loop
//------------------------------------------------------------------------------------
void lineLoop()
{
if (lastHorzPosition != horzPosition || lastVertPosition != vertPosition || millis() > lineFlashTimeout)
{
lineVisible = !lineVisible;
noInterrupts();
if (lastHorzPosition != -1)
{
drawCursor(lastHorzPosition, lastVertPosition, false);
}
if (lineVisible)
{
drawCursor(horzPosition, vertPosition, true);
myGLCD.drawLine(lineHorzPosition + 2, lineVertPosition + 2, horzPosition + 2,vertPosition + 2);
myGLCD.setPixel(horzPosition + 2,vertPosition + 2);
lastHorzPosition = horzPosition;
lastVertPosition = vertPosition;
}
interrupts();
myGLCD.update();
lineFlashTimeout = millis() + LINE_FLASH_DELAY;
}
if (rightEncoderPressed)
{
//Draw line on canvas
rightEncoderPressed = false;
noInterrupts();
myGLCD.setCanvasMode(true);
myGLCD.setPixel(lineHorzPosition + 2, lineVertPosition + 2);
myGLCD.drawLine(lineHorzPosition + 2, lineVertPosition + 2, horzPosition + 2,vertPosition + 2);
myGLCD.setPixel(horzPosition + 2,vertPosition + 2);
myGLCD.setCanvasMode(false);
lineHorzPosition = horzPosition;
lineVertPosition = vertPosition;
interrupts();
myGLCD.update();
}
delay(100);
}
//------------------------------------------------------------------------------------
// rectangle loop
//------------------------------------------------------------------------------------
void rectLoop()
{
if (lastHorzPosition != horzPosition || lastVertPosition != vertPosition || millis() > lineFlashTimeout)
{
lineVisible = !lineVisible;
noInterrupts();
if (lastHorzPosition != -1)
{
drawCursor(lastHorzPosition, lastVertPosition, false);
}
if (lineVisible)
{
drawCursor(horzPosition, vertPosition, true);
myGLCD.drawRect(lineHorzPosition + 2, lineVertPosition + 2, horzPosition + 2,vertPosition + 2);
myGLCD.setPixel(horzPosition + 2,vertPosition + 2);
lastHorzPosition = horzPosition;
lastVertPosition = vertPosition;
}
interrupts();
myGLCD.update();
lineFlashTimeout = millis() + LINE_FLASH_DELAY;
}
if (rightEncoderPressed)
{
//Draw line on canvas
rightEncoderPressed = false;
noInterrupts();
myGLCD.setCanvasMode(true);
myGLCD.setPixel(lineHorzPosition + 2, lineVertPosition + 2);
myGLCD.drawRect(lineHorzPosition + 2, lineVertPosition + 2, horzPosition + 2,vertPosition + 2);
myGLCD.setPixel(horzPosition + 2,vertPosition + 2);
myGLCD.setCanvasMode(false);
interrupts();
myGLCD.update();
//Switch to draw mode
drawMode = DRAW;
flashDrawStatus();
}
delay(100);
}
//------------------------------------------------------------------------------------
// circle loop
//------------------------------------------------------------------------------------
void circleLoop()
{
if (lastHorzPosition != horzPosition || lastVertPosition != vertPosition || millis() > lineFlashTimeout)
{
lineVisible = !lineVisible;
noInterrupts();
if (lastHorzPosition != -1)
{
drawCursor(lastHorzPosition, lastVertPosition, false);
}
if (lineVisible)
{
drawCursor(horzPosition, vertPosition, true);
int r = round(sqrt((horzPosition - lineHorzPosition) * (horzPosition - lineHorzPosition) + (vertPosition - lineVertPosition) * (vertPosition - lineVertPosition)));
myGLCD.drawCircle(lineHorzPosition + 2, lineVertPosition + 2, r);
clearBorderSpace();
lastHorzPosition = horzPosition;
lastVertPosition = vertPosition;
}
interrupts();
myGLCD.update();
lineFlashTimeout = millis() + LINE_FLASH_DELAY;
}
if (rightEncoderPressed)
{
//Draw line on canvas
rightEncoderPressed = false;
noInterrupts();
myGLCD.setCanvasMode(true);
int r = round(sqrt((horzPosition - lineHorzPosition) * (horzPosition - lineHorzPosition) + (vertPosition - lineVertPosition) * (vertPosition - lineVertPosition)));
myGLCD.drawCircle(lineHorzPosition + 2, lineVertPosition + 2, r);
clearBorderSpace();
myGLCD.setCanvasMode(false);
interrupts();
myGLCD.update();
//Switch to draw mode
drawMode = DRAW;
flashDrawStatus();
}
delay(100);
}
/*
LCD5110_Graph.h - Arduino/chipKit library support for Nokia 5110 compatible LCDs
Copyright (C)2015 Rinky-Dink Electronics, Henning Karlsen. All right reserved
Basic functionality of this library are based on the demo-code provided by
ITead studio. You can find the latest version of the library at
http://www.RinkyDinkElectronics.com/
This library has been made to make it easy to use the Nokia 5110 LCD module
as a graphics display on an Arduino or a chipKit.
This library is free software; you can redistribute it and/or
modify it under the terms of the CC BY-NC-SA 3.0 license.
Please see the included documents for further information.
Commercial use of this library requires you to buy a license that
will allow commercial use. This includes using the library,
modified or not, as a tool to sell products.
The license applies to all part of the library including the
examples and tools supplied with the library.
*/
#ifndef LCD5110_Graph_Ex_h
#define LCD5110_Graph_Ex_h
#define LEFT 0
#define RIGHT 9999
#define CENTER 9998
#define LCD_COMMAND 0
#define LCD_DATA 1
// PCD8544 Commandset
// ------------------
// General commands
#define PCD8544_POWERDOWN 0x04
#define PCD8544_ENTRYMODE 0x02
#define PCD8544_EXTENDEDINSTRUCTION 0x01
#define PCD8544_DISPLAYBLANK 0x00
#define PCD8544_DISPLAYNORMAL 0x04
#define PCD8544_DISPLAYALLON 0x01
#define PCD8544_DISPLAYINVERTED 0x05
// Normal instruction set
#define PCD8544_FUNCTIONSET 0x20
#define PCD8544_DISPLAYCONTROL 0x08
#define PCD8544_SETYADDR 0x40
#define PCD8544_SETXADDR 0x80
// Extended instruction set
#define PCD8544_SETTEMP 0x04
#define PCD8544_SETBIAS 0x10
#define PCD8544_SETVOP 0x80
// Display presets
#define LCD_BIAS 0x03 // Range: 0-7 (0x00-0x07)
#define LCD_TEMP 0x02 // Range: 0-3 (0x00-0x03)
#define LCD_CONTRAST 0x46 // Range: 0-127 (0x00-0x7F)
#include "Arduino.h"
#include "HW_AVR_defines.h"
struct _current_font
{
uint8_t* font;
uint8_t x_size;
uint8_t y_size;
uint8_t offset;
uint8_t numchars;
uint8_t inverted;
};
class LCD5110
{
public:
LCD5110(int SCK, int MOSI, int DC, int RST, int CS);
void InitLCD(int contrast=LCD_CONTRAST);
void setContrast(int contrast);
void enableSleep();
void disableSleep();
void update();
void updateFromCanvas();
void setCanvasMode(bool on);
void clrScr();
void fillScr();
void invert(bool mode);
bool getPixel(uint16_t x, uint16_t y);
void setPixel(uint16_t x, uint16_t y);
void clrPixel(uint16_t x, uint16_t y);
void invPixel(uint16_t x, uint16_t y);
void invertText(bool mode);
void print(char *st, int x, int y);
void print(String st, int x, int y);
void printNumI(long num, int x, int y, int length=0, char filler=' ');
void printNumF(double num, byte dec, int x, int y, char divider='.', int length=0, char filler=' ');
void setFont(uint8_t* font);
void drawBitmap(int x, int y, uint8_t* bitmap, int sx, int sy);
void drawLine(int x1, int y1, int x2, int y2);
void clrLine(int x1, int y1, int x2, int y2);
void drawRect(int x1, int y1, int x2, int y2);
void clrRect(int x1, int y1, int x2, int y2);
void drawRoundRect(int x1, int y1, int x2, int y2);
void clrRoundRect(int x1, int y1, int x2, int y2);
void drawCircle(int x, int y, int radius);
void clrCircle(int x, int y, int radius);
protected:
regtype *P_SCK, *P_MOSI, *P_DC, *P_RST, *P_CS;
regsize B_SCK, B_MOSI, B_DC, B_RST, B_CS;
uint8_t SCK_Pin, RST_Pin; // Needed for for faster MCUs
_current_font cfont;
uint8_t scrbuf[504];
uint8_t canvas[504];
boolean _sleep;
int _contrast;
boolean _drawToCanvas;
void _LCD_Write(unsigned char data, unsigned char mode);
void _print_char(unsigned char c, int x, int row);
void _convert_float(char *buf, double num, int width, byte prec);
void drawHLine(int x, int y, int l);
void clrHLine(int x, int y, int l);
void drawVLine(int x, int y, int l);
void clrVLine(int x, int y, int l);
};
#endif
/*
LCD5110_Graph.cpp - Arduino/chipKit library support for Nokia 5110 compatible LCDs
Copyright (C)2015 Rinky-Dink Electronics, Henning Karlsen. All right reserved
Basic functionality of this library are based on the demo-code provided by
ITead studio. You can find the latest version of the library at
http://www.RinkyDinkElectronics.com/
This library has been made to make it easy to use the Nokia 5110 LCD module
as a graphics display on an Arduino or a chipKit.
This library is free software; you can redistribute it and/or
modify it under the terms of the CC BY-NC-SA 3.0 license.
Please see the included documents for further information.
Commercial use of this library requires you to buy a license that
will allow commercial use. This includes using the library,
modified or not, as a tool to sell products.
The license applies to all part of the library including the
examples and tools supplied with the library.
*/
#include "LCD5110_Graph_Ex.h"
LCD5110::LCD5110(int SCK, int MOSI, int DC, int RST, int CS)
{
P_SCK = portOutputRegister(digitalPinToPort(SCK));
B_SCK = digitalPinToBitMask(SCK);
P_MOSI = portOutputRegister(digitalPinToPort(MOSI));
B_MOSI = digitalPinToBitMask(MOSI);
P_DC = portOutputRegister(digitalPinToPort(DC));
B_DC = digitalPinToBitMask(DC);
P_RST = portOutputRegister(digitalPinToPort(RST));
B_RST = digitalPinToBitMask(RST);
P_CS = portOutputRegister(digitalPinToPort(CS));
B_CS = digitalPinToBitMask(CS);
pinMode(SCK,OUTPUT);
pinMode(MOSI,OUTPUT);
pinMode(DC,OUTPUT);
pinMode(RST,OUTPUT);
pinMode(CS,OUTPUT);
SCK_Pin=SCK;
RST_Pin=RST;
}
void LCD5110::_LCD_Write(unsigned char data, unsigned char mode)
{
cbi(P_CS, B_CS);
if (mode==LCD_COMMAND)
cbi(P_DC, B_DC);
else
sbi(P_DC, B_DC);
for (unsigned char c=0; c<8; c++)
{
if (data & 0x80)
sbi(P_MOSI, B_MOSI);
else
cbi(P_MOSI, B_MOSI);
data = data<<1;
pulseClock;
}
sbi(P_CS, B_CS);
}
void LCD5110::InitLCD(int contrast)
{
if (contrast>0x7F)
contrast=0x7F;
if (contrast<0)
contrast=0;
resetLCD;
_LCD_Write(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION, LCD_COMMAND);
_LCD_Write(PCD8544_SETVOP | contrast, LCD_COMMAND);
_LCD_Write(PCD8544_SETTEMP | LCD_TEMP, LCD_COMMAND);
_LCD_Write(PCD8544_SETBIAS | LCD_BIAS, LCD_COMMAND);
_LCD_Write(PCD8544_FUNCTIONSET, LCD_COMMAND);
_LCD_Write(PCD8544_SETYADDR, LCD_COMMAND);
_LCD_Write(PCD8544_SETXADDR, LCD_COMMAND);
_LCD_Write(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL, LCD_COMMAND);
clrScr();
update();
cfont.font=0;
_sleep=false;
_contrast=contrast;
}
void LCD5110::setContrast(int contrast)
{
if (contrast>0x7F)
contrast=0x7F;
if (contrast<0)
contrast=0;
_LCD_Write(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION, LCD_COMMAND);
_LCD_Write(PCD8544_SETVOP | contrast, LCD_COMMAND);
_LCD_Write(PCD8544_FUNCTIONSET, LCD_COMMAND);
_contrast=contrast;
}
void LCD5110::enableSleep()
{
_sleep = true;
_LCD_Write(PCD8544_SETYADDR, LCD_COMMAND);
_LCD_Write(PCD8544_SETXADDR, LCD_COMMAND);
for (int b=0; b<504; b++)
_LCD_Write(0, LCD_DATA);
_LCD_Write(PCD8544_FUNCTIONSET | PCD8544_POWERDOWN, LCD_COMMAND);
}
void LCD5110::disableSleep()
{
_sleep = false;
_LCD_Write(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION, LCD_COMMAND);
_LCD_Write(PCD8544_SETVOP | _contrast, LCD_COMMAND);
_LCD_Write(PCD8544_SETTEMP | LCD_TEMP, LCD_COMMAND);
_LCD_Write(PCD8544_SETBIAS | LCD_BIAS, LCD_COMMAND);
_LCD_Write(PCD8544_FUNCTIONSET, LCD_COMMAND);
_LCD_Write(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL, LCD_COMMAND);
update();
}
void LCD5110::update()
{
if (_sleep==false)
{
_LCD_Write(PCD8544_SETYADDR, LCD_COMMAND);
_LCD_Write(PCD8544_SETXADDR, LCD_COMMAND);
for (int b=0; b<504; b++)
_LCD_Write(scrbuf[b], LCD_DATA);
}
}
void LCD5110::updateFromCanvas()
{
for (int c=0; c<504; c++)
scrbuf[c]=canvas[c];
}
void LCD5110::setCanvasMode(bool on)
{
_drawToCanvas = on;
}
void LCD5110::clrScr()
{
for (int c=0; c<504; c++)
{
scrbuf[c]=0;
if (_drawToCanvas)
{
canvas[c]=0;
}
}
}
void LCD5110::fillScr()
{
for (int c=0; c<504; c++)
{
scrbuf[c]=255;
if (_drawToCanvas)
{
canvas[c]=255;
}
}
}
void LCD5110::invert(bool mode)
{
if (mode==true)
_LCD_Write(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYINVERTED, LCD_COMMAND);
else
_LCD_Write(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL, LCD_COMMAND);
}
bool LCD5110::getPixel(uint16_t x, uint16_t y)
{
int by, bi;
bool on = false;
if ((x>=0) && (x<84) && (y>=0) && (y<48))
{
by=((y/8)*84)+x;
bi=y % 8;
on=(scrbuf[by] & (1<<bi));
}
return on;
}
void LCD5110::setPixel(uint16_t x, uint16_t y)
{
int by, bi;
if ((x>=0) and (x<84) and (y>=0) and (y<48))
{
by=((y/8)*84)+x;
bi=y % 8;
scrbuf[by]=scrbuf[by] | (1<<bi);
if (_drawToCanvas)
{
canvas[by]=canvas[by] | (1<<bi);
}
}
}
void LCD5110::clrPixel(uint16_t x, uint16_t y)
{
int by, bi;
if ((x>=0) and (x<84) and (y>=0) and (y<48))
{
by=((y/8)*84)+x;
bi=y % 8;
scrbuf[by]=scrbuf[by] & ~(1<<bi);
if (_drawToCanvas)
{
canvas[by]=canvas[by] & ~(1<<bi);
}
}
}
void LCD5110::invPixel(uint16_t x, uint16_t y)
{
int by, bi;
if ((x>=0) and (x<84) and (y>=0) and (y<48))
{
by=((y/8)*84)+x;
bi=y % 8;
scrbuf[by]=scrbuf[by] ^ (1<<bi);
if (_drawToCanvas)
{
canvas[by]=canvas[by] ^ (1<<bi);
}
}
}
void LCD5110::invertText(bool mode)
{
if (mode==true)
cfont.inverted=1;
else
cfont.inverted=0;
}
void LCD5110::print(char *st, int x, int y)
{
unsigned char ch;
int stl;
stl = strlen(st);
if (x == RIGHT)
x = 84-(stl*cfont.x_size);
if (x == CENTER)
x = (84-(stl*cfont.x_size))/2;
for (int cnt=0; cnt<stl; cnt++)
_print_char(*st++, x + (cnt*(cfont.x_size)), y);
}
void LCD5110::print(String st, int x, int y)
{
char buf[st.length()+1];
st.toCharArray(buf, st.length()+1);
print(buf, x, y);
}
void LCD5110::printNumI(long num, int x, int y, int length, char filler)
{
char buf[25];
char st[27];
boolean neg=false;
int c=0, f=0;
if (num==0)
{
if (length!=0)
{
for (c=0; c<(length-1); c++)
st[c]=filler;
st[c]=48;
st[c+1]=0;
}
else
{
st[0]=48;
st[1]=0;
}
}
else
{
if (num<0)
{
neg=true;
num=-num;
}
while (num>0)
{
buf[c]=48+(num % 10);
c++;
num=(num-(num % 10))/10;
}
buf[c]=0;
if (neg)
{
st[0]=45;
}
if (length>(c+neg))
{
for (int i=0; i<(length-c-neg); i++)
{
st[i+neg]=filler;
f++;
}
}
for (int i=0; i<c; i++)
{
st[i+neg+f]=buf[c-i-1];
}
st[c+neg+f]=0;
}
print(st,x,y);
}
void LCD5110::printNumF(double num, byte dec, int x, int y, char divider, int length, char filler)
{
char st[27];
boolean neg=false;
if (num<0)
neg = true;
_convert_float(st, num, length, dec);
if (divider != '.')
{
for (int i=0; i<sizeof(st); i++)
if (st[i]=='.')
st[i]=divider;
}
if (filler != ' ')
{
if (neg)
{
st[0]='-';
for (int i=1; i<sizeof(st); i++)
if ((st[i]==' ') || (st[i]=='-'))
st[i]=filler;
}
else
{
for (int i=0; i<sizeof(st); i++)
if (st[i]==' ')
st[i]=filler;
}
}
print(st,x,y);
}
void LCD5110::_print_char(unsigned char c, int x, int y)
{
if ((cfont.y_size % 8) == 0)
{
int font_idx = ((c - cfont.offset)*(cfont.x_size*(cfont.y_size/8)))+4;
for (int rowcnt=0; rowcnt<(cfont.y_size/8); rowcnt++)
{
for(int cnt=0; cnt<cfont.x_size; cnt++)
{
for (int b=0; b<8; b++)
if ((fontbyte(font_idx+cnt+(rowcnt*cfont.x_size)) & (1<<b))!=0)
if (cfont.inverted==0)
setPixel(x+cnt, y+(rowcnt*8)+b);
else
clrPixel(x+cnt, y+(rowcnt*8)+b);
else
if (cfont.inverted==0)
clrPixel(x+cnt, y+(rowcnt*8)+b);
else
setPixel(x+cnt, y+(rowcnt*8)+b);
}
}
}
else
{
int font_idx = ((c - cfont.offset)*((cfont.x_size*cfont.y_size/8)))+4;
int cbyte=fontbyte(font_idx);
int cbit=7;
for (int cx=0; cx<cfont.x_size; cx++)
{
for (int cy=0; cy<cfont.y_size; cy++)
{
if ((cbyte & (1<<cbit)) != 0)
if (cfont.inverted==0)
setPixel(x+cx, y+cy);
else
clrPixel(x+cx, y+cy);
else
if (cfont.inverted==0)
clrPixel(x+cx, y+cy);
else
setPixel(x+cx, y+cy);
cbit--;
if (cbit<0)
{
cbit=7;
font_idx++;
cbyte=fontbyte(font_idx);
}
}
}
}
}
void LCD5110::setFont(uint8_t* font)
{
cfont.font=font;
cfont.x_size=fontbyte(0);
cfont.y_size=fontbyte(1);
cfont.offset=fontbyte(2);
cfont.numchars=fontbyte(3);
cfont.inverted=0;
}
void LCD5110::drawHLine(int x, int y, int l)
{
int by, bi;
if ((x>=0) and (x<84) and (y>=0) and (y<48))
{
for (int cx=0; cx<l; cx++)
{
by=((y/8)*84)+x;
bi=y % 8;
scrbuf[by+cx] |= (1<<bi);
if (_drawToCanvas)
{
canvas[by+cx] |= (1<<bi);
}
}
}
}
void LCD5110::clrHLine(int x, int y, int l)
{
int by, bi;
if ((x>=0) and (x<84) and (y>=0) and (y<48))
{
for (int cx=0; cx<l; cx++)
{
by=((y/8)*84)+x;
bi=y % 8;
scrbuf[by+cx] &= ~(1<<bi);
if (_drawToCanvas)
{
canvas[by+cx] &= ~(1<<bi);
}
}
}
}
void LCD5110::drawVLine(int x, int y, int l)
{
int by, bi;
if ((x>=0) and (x<84) and (y>=0) and (y<48))
{
for (int cy=0; cy<l; cy++)
{
setPixel(x, y+cy);
}
}
}
void LCD5110::clrVLine(int x, int y, int l)
{
int by, bi;
if ((x>=0) and (x<84) and (y>=0) and (y<48))
{
for (int cy=0; cy<l; cy++)
{
clrPixel(x, y+cy);
}
}
}
void LCD5110::drawLine(int x1, int y1, int x2, int y2)
{
int tmp;
double delta, tx, ty;
double m, b, dx, dy;
if (((x2-x1)<0))
{
tmp=x1;
x1=x2;
x2=tmp;
tmp=y1;
y1=y2;
y2=tmp;
}
if (((y2-y1)<0))
{
tmp=x1;
x1=x2;
x2=tmp;
tmp=y1;
y1=y2;
y2=tmp;
}
if (y1==y2)
{
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
drawHLine(x1, y1, x2-x1);
}
else if (x1==x2)
{
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
drawVLine(x1, y1, y2-y1);
}
else if (abs(x2-x1)>abs(y2-y1))
{
delta=(double(y2-y1)/double(x2-x1));
ty=double(y1);
if (x1>x2)
{
for (int i=x1; i>=x2; i--)
{
setPixel(i, int(ty+0.5));
ty=ty-delta;
}
}
else
{
for (int i=x1; i<=x2; i++)
{
setPixel(i, int(ty+0.5));
ty=ty+delta;
}
}
}
else
{
delta=(float(x2-x1)/float(y2-y1));
tx=float(x1);
if (y1>y2)
{
for (int i=y2+1; i>y1; i--)
{
setPixel(int(tx+0.5), i);
tx=tx+delta;
}
}
else
{
for (int i=y1; i<y2+1; i++)
{
setPixel(int(tx+0.5), i);
tx=tx+delta;
}
}
}
}
void LCD5110::clrLine(int x1, int y1, int x2, int y2)
{
int tmp;
double delta, tx, ty;
double m, b, dx, dy;
if (((x2-x1)<0))
{
tmp=x1;
x1=x2;
x2=tmp;
tmp=y1;
y1=y2;
y2=tmp;
}
if (((y2-y1)<0))
{
tmp=x1;
x1=x2;
x2=tmp;
tmp=y1;
y1=y2;
y2=tmp;
}
if (y1==y2)
{
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
clrHLine(x1, y1, x2-x1);
}
else if (x1==x2)
{
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
clrVLine(x1, y1, y2-y1);
}
else if (abs(x2-x1)>abs(y2-y1))
{
delta=(double(y2-y1)/double(x2-x1));
ty=double(y1);
if (x1>x2)
{
for (int i=x1; i>=x2; i--)
{
clrPixel(i, int(ty+0.5));
ty=ty-delta;
}
}
else
{
for (int i=x1; i<=x2; i++)
{
clrPixel(i, int(ty+0.5));
ty=ty+delta;
}
}
}
else
{
delta=(float(x2-x1)/float(y2-y1));
tx=float(x1);
if (y1>y2)
{
for (int i=y2+1; i>y1; i--)
{
clrPixel(int(tx+0.5), i);
tx=tx+delta;
}
}
else
{
for (int i=y1; i<y2+1; i++)
{
clrPixel(int(tx+0.5), i);
tx=tx+delta;
}
}
}
}
void LCD5110::drawRect(int x1, int y1, int x2, int y2)
{
int tmp;
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
drawHLine(x1, y1, x2-x1);
drawHLine(x1, y2, x2-x1);
drawVLine(x1, y1, y2-y1);
drawVLine(x2, y1, y2-y1+1);
}
void LCD5110::clrRect(int x1, int y1, int x2, int y2)
{
int tmp;
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
clrHLine(x1, y1, x2-x1);
clrHLine(x1, y2, x2-x1);
clrVLine(x1, y1, y2-y1);
clrVLine(x2, y1, y2-y1+1);
}
void LCD5110::drawRoundRect(int x1, int y1, int x2, int y2)
{
int tmp;
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
if ((x2-x1)>4 && (y2-y1)>4)
{
setPixel(x1+1,y1+1);
setPixel(x2-1,y1+1);
setPixel(x1+1,y2-1);
setPixel(x2-1,y2-1);
drawHLine(x1+2, y1, x2-x1-3);
drawHLine(x1+2, y2, x2-x1-3);
drawVLine(x1, y1+2, y2-y1-3);
drawVLine(x2, y1+2, y2-y1-3);
}
}
void LCD5110::clrRoundRect(int x1, int y1, int x2, int y2)
{
int tmp;
if (x1>x2)
{
tmp=x1;
x1=x2;
x2=tmp;
}
if (y1>y2)
{
tmp=y1;
y1=y2;
y2=tmp;
}
if ((x2-x1)>4 && (y2-y1)>4)
{
clrPixel(x1+1,y1+1);
clrPixel(x2-1,y1+1);
clrPixel(x1+1,y2-1);
clrPixel(x2-1,y2-1);
clrHLine(x1+2, y1, x2-x1-3);
clrHLine(x1+2, y2, x2-x1-3);
clrVLine(x1, y1+2, y2-y1-3);
clrVLine(x2, y1+2, y2-y1-3);
}
}
void LCD5110::drawCircle(int x, int y, int radius)
{
int f = 1 - radius;
int ddF_x = 1;
int ddF_y = -2 * radius;
int x1 = 0;
int y1 = radius;
char ch, cl;
setPixel(x, y + radius);
setPixel(x, y - radius);
setPixel(x + radius, y);
setPixel(x - radius, y);
while(x1 < y1)
{
if(f >= 0)
{
y1--;
ddF_y += 2;
f += ddF_y;
}
x1++;
ddF_x += 2;
f += ddF_x;
setPixel(x + x1, y + y1);
setPixel(x - x1, y + y1);
setPixel(x + x1, y - y1);
setPixel(x - x1, y - y1);
setPixel(x + y1, y + x1);
setPixel(x - y1, y + x1);
setPixel(x + y1, y - x1);
setPixel(x - y1, y - x1);
}
}
void LCD5110::clrCircle(int x, int y, int radius)
{
int f = 1 - radius;
int ddF_x = 1;
int ddF_y = -2 * radius;
int x1 = 0;
int y1 = radius;
char ch, cl;
clrPixel(x, y + radius);
clrPixel(x, y - radius);
clrPixel(x + radius, y);
clrPixel(x - radius, y);
while(x1 < y1)
{
if(f >= 0)
{
y1--;
ddF_y += 2;
f += ddF_y;
}
x1++;
ddF_x += 2;
f += ddF_x;
clrPixel(x + x1, y + y1);
clrPixel(x - x1, y + y1);
clrPixel(x + x1, y - y1);
clrPixel(x - x1, y - y1);
clrPixel(x + y1, y + x1);
clrPixel(x - y1, y + x1);
clrPixel(x + y1, y - x1);
clrPixel(x - y1, y - x1);
}
}
void LCD5110::drawBitmap(int x, int y, uint8_t* bitmap, int sx, int sy)
{
int bit;
byte data;
for (int cy=0; cy<sy; cy++)
{
bit= cy % 8;
for(int cx=0; cx<sx; cx++)
{
data=bitmapbyte(cx+((cy/8)*sx));
if ((data & (1<<bit))>0)
setPixel(x+cx, y+cy);
else
clrPixel(x+cx, y+cy);
}
}
}
#if defined(__AVR__)
#include <avr/pgmspace.h>
#define fontdatatype const uint8_t
#elif defined(__PIC32MX__)
#define PROGMEM
#define fontdatatype const unsigned char
#elif defined(__arm__)
#define PROGMEM
#define fontdatatype const unsigned char
#endif
fontdatatype SmallFont[] PROGMEM =
{
0x06, 0x08, 0x20, 0x5f,
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, 0x23, 0x13, 0x08, 0x64, 0x62, // %
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, // [
0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, // Backslash (Checker pattern)
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x00, 0x03, 0x05, 0x00, 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
0x00, 0x00, 0x10, 0x7C, 0x82, 0x00, // {
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, // |
0x00, 0x00, 0x82, 0x7C, 0x10, 0x00, // }
0x00, 0x00, 0x06, 0x09, 0x09, 0x06 // ~ (Degrees)
};
fontdatatype MediumNumbers[] PROGMEM =
{
0x0c, 0x10, 0x2d, 0x0d,
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, // -
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, // .
0x00, 0x00, 0x02, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x02, 0x00, 0x00, 0x00, 0x00, 0x81, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x81, 0x00, 0x00, // /
0x00, 0xfc, 0x7a, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7a, 0xfc, 0x00, 0x00, 0x7e, 0xbc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbc, 0x7e, 0x00, // 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0x00, // 1
0x00, 0x00, 0x02, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x7a, 0xfc, 0x00, 0x00, 0x7e, 0xbd, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x81, 0x00, 0x00, // 2
0x00, 0x00, 0x02, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x7a, 0xfc, 0x00, 0x00, 0x00, 0x81, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xbd, 0x7e, 0x00, // 3
0x00, 0xfc, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x78, 0xfc, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x3d, 0x7e, 0x00, // 4
0x00, 0xfc, 0x7a, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x02, 0x00, 0x00, 0x00, 0x00, 0x81, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xbd, 0x7e, 0x00, // 5
0x00, 0xfc, 0x7a, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x02, 0x00, 0x00, 0x00, 0x7e, 0xbd, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xbd, 0x7e, 0x00, // 6
0x00, 0x00, 0x02, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7a, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7e, 0x00, // 7
0x00, 0xfc, 0x7a, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x7a, 0xfc, 0x00, 0x00, 0x7e, 0xbd, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xbd, 0x7e, 0x00, // 8
0x00, 0xfc, 0x7a, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x7a, 0xfc, 0x00, 0x00, 0x00, 0x81, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xbd, 0x7e, 0x00, // 9
};
fontdatatype BigNumbers[] PROGMEM =
{
0x0e, 0x18, 0x2d, 0x0d,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x10, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xe0, 0xe0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // .
0x00, 0x00, 0x02, 0x06, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0x80, 0x00, 0x00, // /
0x00, 0xfc, 0xfa, 0xf6, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0xf6, 0xfa, 0xfc, 0x00, 0x00, 0xef, 0xc7, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0xc7, 0xef, 0x00, 0x00, 0x7f, 0xbf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xbf, 0x7f, 0x00, // 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf8, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0xc7, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x3f, 0x7f, 0x00, // 1
0x00, 0x00, 0x02, 0x06, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0xf6, 0xfa, 0xfc, 0x00, 0x00, 0xe0, 0xd0, 0xb8, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x3b, 0x17, 0x0f, 0x00, 0x00, 0x7f, 0xbf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0x80, 0x00, 0x00, // 2
0x00, 0x00, 0x02, 0x06, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0xf6, 0xfa, 0xfc, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xbb, 0xd7, 0xef, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xbf, 0x7f, 0x00, // 3
0x00, 0xfc, 0xf8, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf8, 0xfc, 0x00, 0x00, 0x0f, 0x17, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xbb, 0xd7, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x3f, 0x7f, 0x00, // 4
0x00, 0xfc, 0xfa, 0xf6, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x17, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xb8, 0xd0, 0xe0, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xbf, 0x7f, 0x00, // 5
0x00, 0xfc, 0xfa, 0xf6, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0xef, 0xd7, 0xbb, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xb8, 0xd0, 0xe0, 0x00, 0x00, 0x7f, 0xbf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xbf, 0x7f, 0x00, // 6
0x00, 0x00, 0x02, 0x06, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0xf6, 0xfa, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0xc7, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x3f, 0x7f, 0x00, // 7
0x00, 0xfc, 0xfa, 0xf6, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0xf6, 0xfa, 0xfc, 0x00, 0x00, 0xef, 0xd7, 0xbb, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xbb, 0xd7, 0xef, 0x00, 0x00, 0x7f, 0xbf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xbf, 0x7f, 0x00, // 8
0x00, 0xfc, 0xfa, 0xf6, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0xf6, 0xfa, 0xfc, 0x00, 0x00, 0x0f, 0x17, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0xbb, 0xd7, 0xef, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xbf, 0x7f, 0x00, // 9
};
fontdatatype TinyFont[] PROGMEM =
{
0x04, 0x06, 0x20, 0x5f,
0x00, 0x00, 0x00, 0x03, 0xa0, 0x00, 0xc0, 0x0c, 0x00, 0xf9, 0x4f, 0x80, 0x6b, 0xeb, 0x00, 0x98, 0x8c, 0x80, 0x52, 0xa5, 0x80, 0x03, 0x00, 0x00, // Space, !"#$%&'
0x01, 0xc8, 0x80, 0x89, 0xc0, 0x00, 0x50, 0x85, 0x00, 0x21, 0xc2, 0x00, 0x08, 0x40, 0x00, 0x20, 0x82, 0x00, 0x00, 0x20, 0x00, 0x18, 0x8c, 0x00, // ()*+,-./
0xfa, 0x2f, 0x80, 0x4b, 0xe0, 0x80, 0x5a, 0x66, 0x80, 0x8a, 0xa5, 0x00, 0xe0, 0x8f, 0x80, 0xea, 0xab, 0x00, 0x72, 0xa9, 0x00, 0x9a, 0x8c, 0x00, // 01234567
0xfa, 0xaf, 0x80, 0x4a, 0xa7, 0x00, 0x01, 0x40, 0x00, 0x09, 0x40, 0x00, 0x21, 0x48, 0x80, 0x51, 0x45, 0x00, 0x89, 0x42, 0x00, 0x42, 0x66, 0x00, // 89:;<=>?
0x72, 0xa6, 0x80, 0x7a, 0x87, 0x80, 0xfa, 0xa5, 0x00, 0x72, 0x25, 0x00, 0xfa, 0x27, 0x00, 0xfa, 0xa8, 0x80, 0xfa, 0x88, 0x00, 0x72, 0x2b, 0x00, // @ABCDEFG
0xf8, 0x8f, 0x80, 0x8b, 0xe8, 0x80, 0x8b, 0xe8, 0x00, 0xf8, 0x8d, 0x80, 0xf8, 0x20, 0x80, 0xf9, 0x0f, 0x80, 0xf9, 0xcf, 0x80, 0x72, 0x27, 0x00, // HIJKLMNO
0xfa, 0x84, 0x00, 0x72, 0x27, 0x40, 0xfa, 0x85, 0x80, 0x4a, 0xa9, 0x00, 0x83, 0xe8, 0x00, 0xf0, 0x2f, 0x00, 0xe0, 0x6e, 0x00, 0xf0, 0xef, 0x00, // PQRSTUVW
0xd8, 0x8d, 0x80, 0xc0, 0xec, 0x00, 0x9a, 0xac, 0x80, 0x03, 0xe8, 0x80, 0xc0, 0x81, 0x80, 0x8b, 0xe0, 0x00, 0x42, 0x04, 0x00, 0x08, 0x20, 0x80, // XYZ[\]^_
0x02, 0x04, 0x00, 0x31, 0x23, 0x80, 0xf9, 0x23, 0x00, 0x31, 0x24, 0x80, 0x31, 0x2f, 0x80, 0x31, 0x62, 0x80, 0x23, 0xea, 0x00, 0x25, 0x53, 0x80, // `abcdefg
0xf9, 0x03, 0x80, 0x02, 0xe0, 0x00, 0x06, 0xe0, 0x00, 0xf8, 0x42, 0x80, 0x03, 0xe0, 0x00, 0x79, 0x87, 0x80, 0x39, 0x03, 0x80, 0x31, 0x23, 0x00, // hijklmno
0x7d, 0x23, 0x00, 0x31, 0x27, 0xc0, 0x78, 0x84, 0x00, 0x29, 0x40, 0x00, 0x43, 0xe4, 0x00, 0x70, 0x27, 0x00, 0x60, 0x66, 0x00, 0x70, 0x67, 0x00, // pqrstuvw
0x48, 0xc4, 0x80, 0x74, 0x57, 0x80, 0x59, 0xe6, 0x80, 0x23, 0xe8, 0x80, 0x03, 0x60, 0x00, 0x8b, 0xe2, 0x00, 0x61, 0x0c, 0x00 // zyx{|}~
};
void LCD5110::_convert_float(char *buf, double num, int width, byte prec)
{
dtostrf(num, width, prec, buf);
}
// *** Hardwarespecific defines ***
#define cbi(reg, bitmask) *reg &= ~bitmask
#define sbi(reg, bitmask) *reg |= bitmask
#define pulseClock cbi(P_SCK, B_SCK); asm ("nop"); sbi(P_SCK, B_SCK)
#define resetLCD sbi(P_DC, B_DC); sbi(P_MOSI, B_MOSI); sbi(P_SCK, B_SCK); sbi(P_CS, B_CS); cbi(P_RST, B_RST); delay(10); sbi(P_RST, B_RST)
#define fontbyte(x) pgm_read_byte(&cfont.font[x])
#define bitmapbyte(x) pgm_read_byte(&bitmap[x])
#define regtype volatile uint8_t
#define regsize volatile uint8_t
#define bitmapdatatype uint8_t*
Comments
Please log in or sign up to comment.