light text library for 5110 nokia lcd * easy to modify * proportional font, bold / inverse modes * easy to add / change fonts * fixed rows for fast update

Library finished! :-) If you use 5110 and need fast menus - try this library. No overhead - small and robust, optimized for this display type only, fast update. Nice looking font. Power management. Displays from 5110 and 3110 are cheap as dirt :-)

medvdv5110.cpp

Committer:
medvdv
Date:
2014-01-31
Revision:
6:cd44333c061b
Parent:
5:c37e5454bdb2

File content as of revision 6:cd44333c061b:

//
// 5110 LCD Driver
// (c) 2012 @medvdv - Alexander Medvedev
//

#include "mbed.h"
#include "medvdv5110.h"

// Nice proportional font with 8px height
 
const char lcd_font8p_widths[] = {
    2, 1, 3, 5, 5, 5, 5, 1, 2, 2, 5, 5, 4,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 6, 5, 6, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 3,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4,
    1, 3, 4, 1, 5, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 4, 4, 4, 2, 4, 5, 4
};

const char* lcd_font8p[] = {
    (const char[]){ 0x00, 0x00 },
    (const char[]){ 0x2F },
    (const char[]){ 0x03, 0x00, 0x03 },
    (const char[]){ 0x14, 0x3E, 0x14, 0x3E, 0x14 },
    (const char[]){ 0x24, 0x6A, 0x3E, 0x2B, 0x12 },
    (const char[]){ 0x22, 0x10, 0x08, 0x04, 0x22 },
    (const char[]){ 0x14, 0x2A, 0x2A, 0x14, 0x20 },
    (const char[]){ 0x03 },
    (const char[]){ 0x1E, 0x21 },
    (const char[]){ 0x21, 0x1E },
    (const char[]){ 0x14, 0x08, 0x3E, 0x08, 0x14 },
    (const char[]){ 0x08, 0x08, 0x3E, 0x08, 0x08 },
    (const char[]){ 0x00, 0x80, 0x70, 0x30 },
    (const char[]){ 0x08, 0x08, 0x08, 0x08, 0x08 },
    (const char[]){ 0x00, 0x00, 0x30, 0x30, 0x00 },
    (const char[]){ 0x20, 0x10, 0x08, 0x04, 0x02 },
    (const char[]){ 0x1E, 0x31, 0x2D, 0x23, 0x1E },
    (const char[]){ 0x00, 0x00, 0x02, 0x3F, 0x00 },
    (const char[]){ 0x22, 0x31, 0x29, 0x25, 0x22 },
    (const char[]){ 0x12, 0x21, 0x25, 0x25, 0x1A },
    (const char[]){ 0x18, 0x14, 0x12, 0x3F, 0x10 },
    (const char[]){ 0x17, 0x25, 0x25, 0x25, 0x19 },
    (const char[]){ 0x1E, 0x25, 0x25, 0x25, 0x18 },
    (const char[]){ 0x01, 0x01, 0x39, 0x05, 0x03 },
    (const char[]){ 0x1A, 0x25, 0x25, 0x25, 0x1A },
    (const char[]){ 0x06, 0x29, 0x29, 0x29, 0x1E },
    (const char[]){ 0x00, 0x00, 0x36, 0x36 },
    (const char[]){ 0x00, 0x80, 0x76, 0x36 },
    (const char[]){ 0x08, 0x08, 0x14, 0x14, 0x22, 0x22 },
    (const char[]){ 0x14, 0x14, 0x14, 0x14, 0x14 },
    (const char[]){ 0x22, 0x22, 0x14, 0x14, 0x08, 0x08 },
    (const char[]){ 0x02, 0x01, 0x29, 0x05, 0x02 },
    (const char[]){ 0x3E, 0x41, 0x5D, 0x55, 0x5E, 0x20 },
    (const char[]){ 0x3E, 0x09, 0x09, 0x09, 0x3E },
    (const char[]){ 0x3F, 0x25, 0x25, 0x25, 0x1A },
    (const char[]){ 0x1E, 0x21, 0x21, 0x21, 0x12 },
    (const char[]){ 0x3F, 0x21, 0x21, 0x22, 0x1C },
    (const char[]){ 0x3F, 0x25, 0x25, 0x25, 0x21 },
    (const char[]){ 0x3F, 0x05, 0x05, 0x05, 0x01 },
    (const char[]){ 0x1E, 0x21, 0x21, 0x29, 0x1A },
    (const char[]){ 0x3F, 0x04, 0x04, 0x04, 0x3F },
    (const char[]){ 0x21, 0x3F, 0x21 },
    (const char[]){ 0x18, 0x20, 0x21, 0x1F, 0x01 },
    (const char[]){ 0x3F, 0x04, 0x04, 0x0A, 0x31 },
    (const char[]){ 0x3F, 0x20, 0x20, 0x20, 0x20 },
    (const char[]){ 0x3F, 0x02, 0x04, 0x02, 0x3F },
    (const char[]){ 0x3F, 0x02, 0x04, 0x08, 0x3F },
    (const char[]){ 0x1E, 0x21, 0x21, 0x21, 0x1E },
    (const char[]){ 0x3F, 0x09, 0x09, 0x09, 0x06 },
    (const char[]){ 0x1E, 0x21, 0x29, 0x31, 0x3E },
    (const char[]){ 0x3F, 0x09, 0x09, 0x19, 0x26 },
    (const char[]){ 0x12, 0x25, 0x25, 0x25, 0x1A },
    (const char[]){ 0x01, 0x01, 0x3F, 0x01, 0x01 },
    (const char[]){ 0x1F, 0x20, 0x20, 0x20, 0x1F },
    (const char[]){ 0x03, 0x0C, 0x30, 0x0C, 0x03 },
    (const char[]){ 0x1F, 0x20, 0x18, 0x20, 0x1F },
    (const char[]){ 0x21, 0x12, 0x0C, 0x12, 0x21 },
    (const char[]){ 0x03, 0x04, 0x38, 0x04, 0x03 },
    (const char[]){ 0x31, 0x29, 0x25, 0x23, 0x21 },
    (const char[]){ 0x00, 0x3F, 0x21, 0x21 },
    (const char[]){ 0x02, 0x04, 0x08, 0x10, 0x20 },
    (const char[]){ 0x00, 0x00, 0x21, 0x21, 0x3F },
    (const char[]){ 0x04, 0x02, 0x01, 0x02, 0x04 },
    (const char[]){ 0x20, 0x20, 0x20, 0x20, 0x20 },
    (const char[]){ 0x00, 0x01, 0x03, 0x04 },
    (const char[]){ 0x10, 0x2A, 0x2A, 0x3C },
    (const char[]){ 0x3F, 0x24, 0x22, 0x1C },
    (const char[]){ 0x1C, 0x22, 0x22, 0x14 },
    (const char[]){ 0x1C, 0x22, 0x24, 0x3F },
    (const char[]){ 0x1C, 0x2A, 0x2A, 0x2C },
    (const char[]){ 0x3E, 0x09, 0x01, 0x02 },
    (const char[]){ 0x0C, 0x52, 0x4A, 0x3C },
    (const char[]){ 0x3F, 0x04, 0x02, 0x3C },
    (const char[]){ 0x3D },
    (const char[]){ 0x40, 0x40, 0x3D },
    (const char[]){ 0x3F, 0x08, 0x0C, 0x32 },
    (const char[]){ 0x3F },
    (const char[]){ 0x3C, 0x02, 0x3C, 0x02, 0x3C },
    (const char[]){ 0x3C, 0x02, 0x02, 0x3C },
    (const char[]){ 0x1C, 0x22, 0x22, 0x1C },
    (const char[]){ 0x7E, 0x22, 0x22, 0x1C },
    (const char[]){ 0x1C, 0x22, 0x22, 0x7E },
    (const char[]){ 0x02, 0x3C, 0x02, 0x02 },
    (const char[]){ 0x24, 0x2A, 0x2A, 0x12 },
    (const char[]){ 0x02, 0x1F, 0x22, 0x22 },
    (const char[]){ 0x1E, 0x20, 0x20, 0x3E },
    (const char[]){ 0x06, 0x18, 0x20, 0x3C, 0x02 },
    (const char[]){ 0x1E, 0x20, 0x1C, 0x20, 0x1E },
    (const char[]){ 0x22, 0x14, 0x08, 0x14, 0x22 },
    (const char[]){ 0x0E, 0x50, 0x50, 0x3E },
    (const char[]){ 0x22, 0x32, 0x2A, 0x26 },
    (const char[]){ 0x00, 0x08, 0x36, 0x41 },
    (const char[]){ 0x00, 0x7F },
    (const char[]){ 0x00, 0x41, 0x36, 0x08 },
    (const char[]){ 0x08, 0x04, 0x08, 0x10, 0x08 },
    (const char[]){ 0x2A, 0x55, 0x2A, 0x55 }
};

// lcd5110 - Internals

// Generic SPI writer
void lcd5110::write(char data, bool cmd)
{
    sce -> write(0);
    dc -> write(cmd ? 0:1);
    spi -> write(data);
    sce -> write(1);
}

// lcd5110 - Public

// Supply LCD pin's here
lcd5110::lcd5110(PinName mosi, PinName sclk, PinName dc, PinName sce, PinName rst)
{
    spi = new SPI(mosi, NC, sclk);

    spi -> format(8, 1);
    spi -> frequency(4000000);

    this -> rst = new DigitalOut(rst);
    this -> sce = new DigitalOut(sce);
    this -> dc  = new DigitalOut(dc);

    // Setup default font
    font.first_code = 32;
    font.glyphs_total = 128 - 32;
    font.widths = lcd_font8p_widths;
    font.glyphs = lcd_font8p;

    invert = false;
    bold = false;
    
    contrast = DEFAULT_CONTRAST;
}

// Start inverting chars
void lcd5110::Invert(bool invert)
{
    this -> invert = invert;
}

// Start bold mode (repeat twice wide)
void lcd5110::Bold(bool bold)
{
    this -> bold = bold;
}

// Reset LCD, configure defaults and contrast
void lcd5110::Reset()
{
    rst -> write(0);
    wait_ms(100);
    rst -> write(1);
    write(0x21, true);
    write(0x80 + contrast, true);
    write(0x04, true);
    write(0x14, true);
    write(0x20, true);
    write(0x0C, true);
    XY();
}

// Change contrast
void lcd5110::Contrast(char contrast)
{
    this -> contrast = contrast;
    write(0x21, true);
    write(0x80 + contrast, true);
    write(0x20, true);
}

// LCD power off
void lcd5110::Power(bool power)
{
    if(!power) write(0x24, true);
          else write(0x20, true);
}

void lcd5110::InverseMode(bool invert)
{
    if(invert) write(0x0d, true);
          else write(0x08, true);
}

// Clear - fill all by 8bit line 'pattern'
void lcd5110::Clear(char pattern)
{
    Write(pattern,504);
    XY();
}

// Change current output position
// X in pixels [0..83]
// Y in rows   [0..5]
void lcd5110::XY(int x, int y)
{
    if (x<0)  x=0;
    if (x>83) x=83;
    if (y<0)  y=0;
    if (y>5)  y=5;

    X = x;
    Y = y;

    write( 0x80 | (x & 0x3f), true);
    write( 0x40 | (y & 0x3f), true);
}

// Write one 8bit row 
// with inversion and XY update
void lcd5110::Write(char byte)
{
    write(invert?(~byte):byte, false);
    if (++X > 83) {
        X=0;
        if (++Y > 5) Y=0;
    }
}

// Write array of 8bit rows
void lcd5110::Write(char* data, int size)
{
    for(int i=0; i<size; i++) Write(data[i]);
}

// Write array of 8bit rows, twice each
void lcd5110::Write2(char* data, int size)
{
    for(int i=0; i<size; i++) {
        Write(data[i]);
        Write(data[i]);
    }
}

// Write 8bit row 'count' times
void lcd5110::Write(char byte, int count)
{
    for(int i=0; i<count; i++) Write(byte);
}

// Draw one proportional font character
// Jump to next line if empty space is not enought
void lcd5110::Character(char chr)
{
    if( chr < font.first_code ) return;
    if( chr > font.first_code + font.glyphs_total - 1 ) return;

    chr -= font.first_code;

    int width = font.widths[chr];

    if (bold) width*=2;

    if ((X + width) > 83) {
        if (++Y > 5) Y = 0;
        XY(0,Y);
    }

    if (bold) {
        Write2( (char*) font.glyphs[chr], (int) font.widths[chr] );
        if (X != 0) {
            Write( 0 );
            Write( 0 );
        }
    } else {
        Write( (char*) font.glyphs[chr], (int) font.widths[chr] );
        if (X != 0) Write( 0 );
    }
}

// Calculate width of concrete character 
// takes into account bold setting 
int lcd5110::CharacterWidth(char chr)
{
    if( chr < font.first_code ) return 0;
    if( chr > font.first_code + font.glyphs_total - 1 ) return 0;

    chr -= font.first_code;

    if (bold)
        return 2 * (font.widths[chr] + 1);
    else
        return font.widths[chr] + 1;
}

// Write string
void lcd5110::String(char* str)
{
    while(*str) Character(*str++);
}

// Predict string width
int lcd5110::StringWidth(char* str)
{
    int width = 0;

    while(*str) width += CharacterWidth(*str++);

    return width;
}

// Clear one line, 
// then write string from it's begin 
void lcd5110::Row(int Y, char* str)
{
    XY(0, Y);
    Write((char) 0, 84);
    XY(0, Y);
    String(str);
}

// Remove pin objects's
lcd5110::~lcd5110()
{
    delete spi;

    delete rst;
    delete sce;
    delete dc;
}