Biblioteka KS0108

    -- Sebastian Pawlak, 2014.


Przedstawiam tu moją bibliotekę obsługującą wyświetlacz KS0108. Zamieściłem także kod krótkiego programu wykorzystującego bibliotekę.





Kod źródłowy pliku "libKS0108.h":

/* libKS0108: KS0108 LCD driver library
 *
 * This library was designed to operate with Atmel AVR ATmega128
 * and 192x64 graphics display
 *
 * CSA=0, CSB=0: left part
 * CSA=0, CSB=1: middle part
 * CSA=1, CSB=0: right part
 *
 * Sebastian Pawlak, 2014, v1.1
 */

#ifndef _KS0108_H_
#define _KS0108_H_


#define F_CPU 16000000       /* set your uC frequency */

#if F_CPU > 16000000
    warning("Please, check if waiting time in delay() is long enough for your "
            "CPU, which is faster than 16MHz.");
#endif


extern uint8_t KS0108_x;
extern uint8_t KS0108_y;


/* display size */
enum {
    KS0108_DISPLAY_WIDTH = 192,    /* width of the display in pixels */
    KS0108_DISPLAY_HEIGHT = 64,    /* height of the display in pixels */

    SET_PIXEL = 1,
    CLEAR_PIXEL = 0,
};


/* set proper ports and pins */
#define KS0108_DATA_OUTPUT_PORT             PORTA
#define KS0108_DATA_DDR_PORT	            DDRA
#define KS0108_DATA_INPUT_PORT              PINA

#define KS0108_CONTROL_EN_OUTPUT_PORT       PORTG
#define KS0108_CONTROL_EN_OUTPUT_PIN        PORTG2
#define KS0108_CONTROL_EN_DDR_PORT          DDRG
#define KS0108_CONTROL_EN_DDR_PIN           DDG2

#define KS0108_CONTROL_RW_OUTPUT_PORT       PORTF
#define KS0108_CONTROL_RW_OUTPUT_PIN        PORTF7
#define KS0108_CONTROL_RW_DDR_PORT          DDRF
#define KS0108_CONTROL_RW_DDR_PIN           DDF7

#define KS0108_CONTROL_RS_OUTPUT_PORT       PORTF
#define KS0108_CONTROL_RS_OUTPUT_PIN        PORTF6
#define KS0108_CONTROL_RS_DDR_PORT          DDRF
#define KS0108_CONTROL_RS_DDR_PIN           DDF6

#define KS0108_CONTROL_CSB_OUTPUT_PORT      PORTF
#define KS0108_CONTROL_CSB_OUTPUT_PIN       PORTF5
#define KS0108_CONTROL_CSB_DDR_PORT         DDRF
#define KS0108_CONTROL_CSB_DDR_PIN          DDF5

#define KS0108_CONTROL_CSA_OUTPUT_PORT      PORTF
#define KS0108_CONTROL_CSA_OUTPUT_PIN       PORTF4
#define KS0108_CONTROL_CSA_DDR_PORT         DDRF
#define KS0108_CONTROL_CSA_DDR_PIN          DDF4

#define KS0108_CONTROL_RST_OUTPUT_PORT      PORTF
#define KS0108_CONTROL_RST_OUTPUT_PIN       PORTF3
#define KS0108_CONTROL_RST_DDR_PORT         DDRF
#define KS0108_CONTROL_RST_DDR_PIN          DDF3


#define  _BV(bit)        (1 << (bit))
#define  cbi(sfr, bit)   (_SFR_BYTE(sfr) &= ~_BV(bit))
#define  sbi(sfr, bit)   (_SFR_BYTE(sfr) |= _BV(bit))


/* display control instructions */
#define KS0108_DISPLAY_TURN_ON_OFF          0x3E
#define KS0108_DISPLAY_SET_ADDRESS          0x40    /* corresponding to X */
#define KS0108_DISPLAY_SET_PAGE             0xB8    /* page number */
#define KS0108_DISPLAY_SET_Z_ADDRESS        0xC0    /* display start line */

#define KS0108_DISPLAY_STATUS_BUSY_FLAG     0x80
#define KS0108_DISPLAY_STATUS_ON_OFF_FLAG   0x20
#define KS0108_DISPLAY_STATUS_RESET_FLAG    0x10


#define KS0108_CONTROL_SBI_EN \
        sbi(KS0108_CONTROL_EN_OUTPUT_PORT, KS0108_CONTROL_EN_OUTPUT_PIN);
#define KS0108_CONTROL_SBI_RW \
        sbi(KS0108_CONTROL_RW_OUTPUT_PORT, KS0108_CONTROL_RW_OUTPUT_PIN);
#define KS0108_CONTROL_SBI_RS \
        sbi(KS0108_CONTROL_RS_OUTPUT_PORT, KS0108_CONTROL_RS_OUTPUT_PIN);
#define KS0108_CONTROL_SBI_CSB \
        sbi(KS0108_CONTROL_CSB_OUTPUT_PORT, KS0108_CONTROL_CSB_OUTPUT_PIN);
#define KS0108_CONTROL_SBI_CSA \
        sbi(KS0108_CONTROL_CSA_OUTPUT_PORT, KS0108_CONTROL_CSA_OUTPUT_PIN);
#define KS0108_CONTROL_SBI_RST \
        sbi(KS0108_CONTROL_RST_OUTPUT_PORT, KS0108_CONTROL_RST_OUTPUT_PIN);

#define KS0108_CONTROL_CBI_EN \
        cbi(KS0108_CONTROL_EN_OUTPUT_PORT, KS0108_CONTROL_EN_OUTPUT_PIN);
#define KS0108_CONTROL_CBI_RW \
        cbi(KS0108_CONTROL_RW_OUTPUT_PORT, KS0108_CONTROL_RW_OUTPUT_PIN);
#define KS0108_CONTROL_CBI_RS \
        cbi(KS0108_CONTROL_RS_OUTPUT_PORT, KS0108_CONTROL_RS_OUTPUT_PIN);
#define KS0108_CONTROL_CBI_CSB \
        cbi(KS0108_CONTROL_CSB_OUTPUT_PORT, KS0108_CONTROL_CSB_OUTPUT_PIN);
#define KS0108_CONTROL_CBI_CSA \
        cbi(KS0108_CONTROL_CSA_OUTPUT_PORT, KS0108_CONTROL_CSA_OUTPUT_PIN);
#define KS0108_CONTROL_CBI_RST \
        cbi(KS0108_CONTROL_RST_OUTPUT_PORT, KS0108_CONTROL_RST_OUTPUT_PIN);

#define KS0108_CONTROL_ONLY_CSB \
        sbi(KS0108_CONTROL_CSB_OUTPUT_PORT, KS0108_CONTROL_CSB_OUTPUT_PIN), \
        cbi(KS0108_CONTROL_CSA_OUTPUT_PORT, KS0108_CONTROL_CSA_OUTPUT_PIN);
#define KS0108_CONTROL_ONLY_CSA \
        sbi(KS0108_CONTROL_CSA_OUTPUT_PORT, KS0108_CONTROL_CSA_OUTPUT_PIN), \
        cbi(KS0108_CONTROL_CSB_OUTPUT_PORT, KS0108_CONTROL_CSB_OUTPUT_PIN);
#define KS0108_CONTROL_NO_CS \
        cbi(KS0108_CONTROL_CSA_OUTPUT_PORT, KS0108_CONTROL_CSA_OUTPUT_PIN), \
        cbi(KS0108_CONTROL_CSB_OUTPUT_PORT, KS0108_CONTROL_CSB_OUTPUT_PIN);


void KS0108_init(void);
void KS0108_displayOn(void);
void KS0108_displayOff(void);
uint8_t KS0108_readStatus();
void inline KS0108_writeCommand(uint8_t cmd);
void inline KS0108_setProperCS(void);
void inline KS0108_writeData(uint8_t data);
void inline KS0108_writeDataNoCS(uint8_t data);
uint8_t inline KS0108_readData(void);
void KS0108_gotoXY(uint8_t x, uint8_t y);
void KS0108_setDisplay(void);
void KS0108_clearDisplay(void);
void inline KS0108_setPixelXY(uint8_t x, uint8_t y);
void inline KS0108_clearPixelXY(uint8_t x, uint8_t y);
void KS0108_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, int8_t c);
void KS0108_drawLineFaster(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2,
                           int8_t c);
void KS0108_drawHorizontalLine(register uint8_t x, uint8_t y,
                               uint8_t width, int8_t c);
void KS0108_drawVerticalLine(uint8_t x, uint8_t y, uint8_t height, int8_t c);
void KS0108_drawRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height,
                          int8_t c);
void KS0108_drawFilledRectangle(uint8_t x, uint8_t y,
                                uint8_t width, uint8_t height, int8_t c);
void KS0108_drawCircle(uint8_t x, uint8_t y, uint8_t r, int8_t c);
void KS0108_drawFilledCircle(uint8_t x, uint8_t y, uint8_t r, int8_t c);
void KS0108_drawBitmap(const uint8_t *bmp, uint8_t x, uint8_t y,
                       uint8_t width, uint8_t height, int8_t c);
void KS0108_drawSprite(const uint8_t *bmp, uint8_t x, uint8_t y,
                       uint8_t width, uint8_t height, int8_t c);
void KS0108_charGotoXY(uint8_t x, uint8_t y);
void inline KS0108_writeChar(uint8_t ch, int8_t c);
void inline KS0108_writeCharUTF8(uint32_t n, int8_t c);
void inline KS0108_writeCharSprite(uint8_t ch, int8_t c);
void inline KS0108_writeCharUTF8Sprite(uint32_t n, int8_t c);
void KS0108_writeString(const uint8_t *s, int8_t c);
void KS0108_writeStringUTF8(const uint8_t *s, int8_t c);
void KS0108_writeStringSprite(const uint8_t *s, int8_t c);
void KS0108_writeStringUTF8Sprite(const uint8_t *s, int8_t c);

#endif

Kod źródłowy pliku "libKS0108.c":

/* libKS0108: KS0108 LCD driver library
 *
 * This library was designed to operate with Atmel AVR ATmega128
 * and 192x64 graphics display
 *
 * CSA=0, CSB=0: left part
 * CSA=0, CSB=1: middle part
 * CSA=1, CSB=0: right part
 *
 * Sebastian Pawlak, 2014, v1.1
 *
 * Changelog:
 * 2014-03-28, v1.1: possible to use control pins on different ports
 */

#include <avr/io.h>
#include <avr/pgmspace.h>
#include "libKS0108.h"
#include "fonts5x8.h"

uint8_t KS0108_x;    /* X position in pixels */
uint8_t KS0108_y;    /* Y position in pixels */


/* KS0108_delay: short KS0108_delay, just to be sure;
 *               it is not probably demanded, if F_CPU == 16MHz
 */
void KS0108_delay(void) {
   asm volatile("nop\n\t"
                "nop\n\t"
                ::);
}


/* KS0108_busyWait: waits until the controller is not busy
 */
void inline KS0108_busyWait(void) {
    KS0108_DATA_DDR_PORT = 0x00;                   /* set pins to input */
    KS0108_CONTROL_CBI_RS KS0108_CONTROL_SBI_RW    /* status read */

    do {
        KS0108_delay();
        KS0108_CONTROL_SBI_EN
        KS0108_delay();
        KS0108_CONTROL_CBI_EN
    } while (KS0108_DATA_INPUT_PORT & KS0108_DISPLAY_STATUS_BUSY_FLAG);

    KS0108_DATA_DDR_PORT = 0xff;        /* set pins to output */
}


/* KS0108_init: port and the display initialization
 */
void KS0108_init(void) {
    KS0108_DATA_DDR_PORT = 0xff;        /* set pins to output */

    KS0108_CONTROL_EN_DDR_PORT |= _BV(KS0108_CONTROL_EN_DDR_PIN);
    KS0108_CONTROL_RW_DDR_PORT |= _BV(KS0108_CONTROL_RW_DDR_PIN);
    KS0108_CONTROL_RS_DDR_PORT |= _BV(KS0108_CONTROL_RS_DDR_PIN);
    KS0108_CONTROL_CSB_DDR_PORT |= _BV(KS0108_CONTROL_CSB_DDR_PIN);
    KS0108_CONTROL_CSA_DDR_PORT |= _BV(KS0108_CONTROL_CSA_DDR_PIN);
    KS0108_CONTROL_RST_DDR_PORT |= _BV(KS0108_CONTROL_RST_DDR_PIN);

    KS0108_CONTROL_SBI_RST     /* it is not demanded to connect RST signal */

    KS0108_displayOn();
}


/* KS0108_displayOn: turn the display on
 */
void KS0108_displayOn(void) {
    KS0108_CONTROL_CBI_RS KS0108_CONTROL_CBI_RW           /* display on/off */

    KS0108_CONTROL_NO_CS                        /* left part of the display */
    KS0108_writeCommand(KS0108_DISPLAY_TURN_ON_OFF | 0x01);
    KS0108_writeCommand(KS0108_DISPLAY_SET_Z_ADDRESS | 0x00);

    KS0108_CONTROL_ONLY_CSA                    /* right part of the display */
    KS0108_writeCommand(KS0108_DISPLAY_TURN_ON_OFF | 0x01);
    KS0108_writeCommand(KS0108_DISPLAY_SET_Z_ADDRESS | 0x00);

    KS0108_CONTROL_ONLY_CSB                   /* middle part of the display */
    KS0108_writeCommand(KS0108_DISPLAY_TURN_ON_OFF | 0x01);
    KS0108_writeCommand(KS0108_DISPLAY_SET_Z_ADDRESS | 0x00);    
}


/* KS0108_displayOff: turn the display off
 */
void KS0108_displayOff(void) {
    KS0108_CONTROL_CBI_RS KS0108_CONTROL_CBI_RW           /* display on/off */

    KS0108_CONTROL_NO_CS                        /* left part of the display */
    KS0108_writeCommand(KS0108_DISPLAY_TURN_ON_OFF | 0x00);
    KS0108_writeCommand(KS0108_DISPLAY_SET_Z_ADDRESS | 0x00);

    KS0108_CONTROL_ONLY_CSA                    /* right part of the display */
    KS0108_writeCommand(KS0108_DISPLAY_TURN_ON_OFF | 0x00);
    KS0108_writeCommand(KS0108_DISPLAY_SET_Z_ADDRESS | 0x00);

    KS0108_CONTROL_ONLY_CSB                   /* middle part of the display */
    KS0108_writeCommand(KS0108_DISPLAY_TURN_ON_OFF | 0x00);
    KS0108_writeCommand(KS0108_DISPLAY_SET_Z_ADDRESS | 0x00);    
}


/* KS0108_readStatus: reads controller status;
 *                    do not forget to set proper CS before calling
 *                    this function
 *                    (only one CS may be active at each call of the function)
 */
uint8_t inline KS0108_readStatus() {
    uint8_t status;

    KS0108_DATA_DDR_PORT = 0x00;                   /* set pins to input */
    KS0108_CONTROL_CBI_RS KS0108_CONTROL_SBI_RW    /* status read */
    KS0108_CONTROL_SBI_EN
    KS0108_delay();
    status = KS0108_DATA_INPUT_PORT;
    KS0108_CONTROL_CBI_EN
    KS0108_DATA_DDR_PORT = 0xff;                   /* set pins to output */

    return status;
}


/* KS0108_writeCommand: writes a command to the controller;
 *                      do not forget to set proper CS before calling
 *                      this function
 *                      (only one CS may be active at each call of the function)
 */
void inline KS0108_writeCommand(uint8_t cmd) {
    KS0108_busyWait();
    KS0108_CONTROL_CBI_RS KS0108_CONTROL_CBI_RW    /* write command */
    KS0108_DATA_OUTPUT_PORT = cmd;
    KS0108_CONTROL_SBI_EN
    KS0108_delay();
    KS0108_CONTROL_CBI_EN
}


/* KS0108_setProperCS: sets proper CS according to actual X
 */
void inline KS0108_setProperCS(void) {
    if (KS0108_x < 64)
        KS0108_CONTROL_NO_CS       /* left part of the display */
    else if (KS0108_x < 128)
        KS0108_CONTROL_ONLY_CSB    /* middle part of the display */
    else
        KS0108_CONTROL_ONLY_CSA    /* right part of the display */
}


/* KS0108_writeData: writes data to the controller
 */
void inline KS0108_writeData(uint8_t data) {
    KS0108_setProperCS();
    KS0108_busyWait();
    KS0108_CONTROL_SBI_RS KS0108_CONTROL_CBI_RW    /* write data */
    KS0108_DATA_OUTPUT_PORT = data;
    KS0108_CONTROL_SBI_EN
    KS0108_delay();
    KS0108_CONTROL_CBI_EN

    if (++KS0108_x >= KS0108_DISPLAY_WIDTH)
        KS0108_x = 0;
}


/* KS0108_writeDataNoCS: writes data to the controller; does not set CS
 */
void inline KS0108_writeDataNoCS(uint8_t data) {
    KS0108_busyWait();
    KS0108_CONTROL_SBI_RS KS0108_CONTROL_CBI_RW    /* write data */
    KS0108_DATA_OUTPUT_PORT = data;
    KS0108_CONTROL_SBI_EN
    KS0108_delay();
    KS0108_CONTROL_CBI_EN

    if (++KS0108_x >= KS0108_DISPLAY_WIDTH)
        KS0108_x = 0;
}


/* KS0108_readData: reads data from the controller
 */
uint8_t inline KS0108_readData(void) {
    uint8_t data;

    KS0108_setProperCS();
    KS0108_busyWait();
    KS0108_DATA_DDR_PORT = 0x00;                   /* set pins to input */
    KS0108_CONTROL_SBI_RS KS0108_CONTROL_SBI_RW    /* read data */
    KS0108_CONTROL_SBI_EN
    KS0108_delay();
    data = KS0108_DATA_INPUT_PORT;
    KS0108_CONTROL_CBI_EN
    KS0108_DATA_DDR_PORT = 0xff;                   /* set pins to output */

    if (++KS0108_x >= KS0108_DISPLAY_WIDTH)
        KS0108_x = 0; 

    return data;   
}


/* KS0108_gotoXY: sets X, Y position
 */
void inline KS0108_gotoXY(uint8_t x, uint8_t y) {
    KS0108_x = x;
    KS0108_y = y;

    if (KS0108_x < 64) {
        KS0108_CONTROL_NO_CS       /* left part of the display */
        KS0108_writeCommand(KS0108_DISPLAY_SET_PAGE | (KS0108_y >> 3));
        KS0108_writeCommand(KS0108_DISPLAY_SET_ADDRESS | KS0108_x);

    } else if (KS0108_x < 128) {
        KS0108_CONTROL_ONLY_CSB    /* middle part of the display */
        KS0108_writeCommand(KS0108_DISPLAY_SET_PAGE | (KS0108_y >> 3));
        KS0108_writeCommand(KS0108_DISPLAY_SET_ADDRESS | (KS0108_x - 64));

    } else {
        KS0108_CONTROL_ONLY_CSA    /* right part of the display */
        KS0108_writeCommand(KS0108_DISPLAY_SET_PAGE | (KS0108_y >> 3));
        KS0108_writeCommand(KS0108_DISPLAY_SET_ADDRESS | (KS0108_x - 128));
    }
}


/* KS0108_setDisplay: sets all pixels of the display
 */
void KS0108_setDisplay(void) {
    register uint8_t x, y, mx;

    for (y = 0; y < 8; y++) {
        for (mx = 0; mx < KS0108_DISPLAY_WIDTH >> 6; mx++) {
            KS0108_gotoXY(mx << 6, y << 3);
            for (x = 0; x < 64; x++)
                KS0108_writeDataNoCS(0xff);
        }
    }
}


/* KS0108_clearDisplay: clears the display
 */
void KS0108_clearDisplay(void) {
    register uint8_t x, y, mx;

    for (y = 0; y < 8; y++) {
        for (mx = 0; mx < KS0108_DISPLAY_WIDTH >> 6; mx++) {
            KS0108_gotoXY(mx << 6, y << 3);
            for (x = 0; x < 64; x++)
                KS0108_writeDataNoCS(0x00);
        }
    }
}


/* KS0108_setPixelXY: sets pixel in X, Y
 */
void inline KS0108_setPixelXY(uint8_t x, uint8_t y) {
    uint8_t tmp;

    KS0108_gotoXY(x, y);
    KS0108_readData();
    KS0108_gotoXY(x, y);      /* it is demanded to do this twice */
    tmp = KS0108_readData();
    KS0108_gotoXY(x, y);
    KS0108_writeData(tmp | (0x01 << (y % 8)));
}


/* KS0108_clearPixelXY: clears pixel in X, Y
 */
void inline KS0108_clearPixelXY(uint8_t x, uint8_t y) {
    uint8_t tmp;

    KS0108_gotoXY(x, y);
    KS0108_readData();
    KS0108_gotoXY(x, y);      /* it is demanded to do this twice */
    tmp = KS0108_readData();
    KS0108_gotoXY(x, y);
    KS0108_writeData(tmp & ~(0x01 << (y % 8)));
}


/* KS0108_drawLine: draws a line
 */
void KS0108_drawLine(uint8_t x1, uint8_t y1,
                     uint8_t x2, uint8_t y2, int8_t c) {
    int16_t dx, sdx, px;
    int16_t dy, sdy, py;
    register int16_t x = 0, y = 0;
    void (*drawPixel)(uint8_t, uint8_t) =
           ((c == SET_PIXEL) ? (&KS0108_setPixelXY) : (&KS0108_clearPixelXY));

    dx = x2 - x1;
    dy = y2 - y1;

    sdx = (dx < 0) ? -1 : 1;
    sdy = (dy < 0) ? -1 : 1;

    dx = sdx * dx + 1;
    dy = sdy * dy + 1;

    px = x1;
    py = y1;

    if (dx >= dy) {
        for (x = 0; x < dx; x++) {
            drawPixel(px, py);
            y += dy;
            if (y >= dx)
                y -= dx, py += sdy;
            px += sdx;
        }
    } else {
        for (y = 0; y < dy; y++) {
            drawPixel(px, py);
            x += dx;
            if (x >= dy)
                x -= dy, px += sdx;
            py += sdy;
        }
    }
}


/* KS0108_drawLineFaster: draws a line; does it faster
 */
void KS0108_drawLineFaster(uint8_t x1, uint8_t y1,
                           uint8_t x2, uint8_t y2, int8_t c) {
    int16_t dx, sdx, px;
    int16_t dy, py, ppy, spy = 0;
    register int16_t x = 0, y = 0;
    void (*drawPixel)(uint8_t, uint8_t) =
           ((c == SET_PIXEL) ? (&KS0108_setPixelXY) : (&KS0108_clearPixelXY));

    if (y2 < y1) {
        uint8_t tmp;
        tmp = y1, y1 = y2, y2 = tmp;
        tmp = x1, x1 = x2, x2 = tmp;
    }

    dx = x2 - x1;
    dy = y2 - y1 + 1;

    sdx = (dx < 0) ? -1 : 1;

    dx = sdx * dx + 1;

    px = x1;
    py = ppy = y1;

    if (dx >= dy) {
        for (x = 0; x < dx; x++) {
            drawPixel(px, py);
            y += dy;
            if (y >= dx)
                y -= dx, py++;
            px += sdx;
        }
    } else {
        for (y = 0; y < dy; y++) {
            spy++;
            x += dx;
            if (x >= dy) {
                KS0108_drawVerticalLine(px, ppy, spy, c);
                ppy = py + 1;
                spy = 0;
                x -= dy, px += sdx;
            }
            py++;
        }
    }
}


/* KS0108_drawHorizontalLine: draws a horizontal line
 */
void KS0108_drawHorizontalLine(register uint8_t x, uint8_t y,
                               uint8_t width, int8_t c) {
    const uint8_t x2 = x + width;
    void (*drawPixel)(uint8_t, uint8_t) =
           ((c == SET_PIXEL) ? (&KS0108_setPixelXY) : (&KS0108_clearPixelXY));

    for ( ; x <= x2; x++)
        drawPixel(x, y);
}


/* setBits: sets proper bits in a byte; for internal use only
 */
inline uint8_t setBits(uint8_t byte, uint8_t bits) {
    return byte | bits;
}


/* clearBits: clears proper bits in a byte; for internal use only
 */
inline uint8_t clearBits(uint8_t byte, uint8_t bits) {
    return byte & (~bits);
}


/* KS0108_drawVerticalLine: draws a vertical line
 */
void KS0108_drawVerticalLine(uint8_t x, uint8_t y,
                             uint8_t height, int8_t c) {
    const uint8_t y2 = y + height;
    uint8_t tmp, yy;
    uint8_t (*doBits)(uint8_t, uint8_t) =
           ((c == SET_PIXEL) ? (&setBits) : (&clearBits));

    /* draw top part of the line */
    if ((y % 8) != 0) {
        KS0108_gotoXY(x, y);
        KS0108_readData();
        KS0108_gotoXY(x, y);    /* it is demanded to do this twice */
        tmp = KS0108_readData();
        KS0108_gotoXY(x, y);
	if ((y2 >> 3 == y >> 3) && (y2 % 8 != 0))
            KS0108_writeData(doBits(tmp, ((0xff << (y % 8)) &
                                          (0xff >> (8 - (y2 % 8))))));
	else
            KS0108_writeData(doBits(tmp, (0xff << (y % 8))));
    }

    /* draw middle part of the line */
    if ((y2 >> 3 != y >> 3) || ((y % 8) == 0)) {
        for (yy = (y >> 3) + ((y % 8) == 0 ? 0 : 1); yy < (y2 >> 3); yy++) {
            KS0108_gotoXY(x, yy << 3);
            KS0108_writeData((c == SET_PIXEL) ? 0xff : 0x00);
        }

        /* draw bottom part of the line */
	if (y2 % 8 != 0) {
            KS0108_gotoXY(x, ((y2 >> 3) << 3));
            KS0108_readData();
            KS0108_gotoXY(x, ((y2 >> 3) << 3)); 
            tmp = KS0108_readData();
            KS0108_gotoXY(x, ((y2 >> 3) << 3));
            KS0108_writeData(doBits(tmp, (0xff >> (8 - (y2 % 8)))));
	}
    }
}


/* KS0108_drawRectangle: draws a rectangle
 */
void KS0108_drawRectangle(uint8_t x, uint8_t y,
                          uint8_t width, uint8_t height, int8_t c) {
    KS0108_drawHorizontalLine(x + 1, y, width - 2, c);
    KS0108_drawHorizontalLine(x + 1, y + height - 1, width - 2, c);

    KS0108_drawVerticalLine(x, y, height, c);
    KS0108_drawVerticalLine(x + width - 1, y, height, c);
}


/* KS0108_drawFilledRectangle: draws a filled rectangle
 *                             (this function need to be optimalized)
 */
void KS0108_drawFilledRectangle(uint8_t x, uint8_t y,
                                uint8_t width, uint8_t height, int8_t c) {
    const uint8_t x2 = x + width;

    for ( ; x < x2; x++)
        KS0108_drawVerticalLine(x, y, height, c);
}


/* KS0108_drawCircle: draws a circle
 */
void KS0108_drawCircle(uint8_t x, uint8_t y, uint8_t r, int8_t c) {
    int16_t xx = r, yy = 0, xc = 1 - (r << 1), yc = 1, re = 0;
    void (*drawPixel)(uint8_t, uint8_t) =
           ((c == SET_PIXEL) ? (&KS0108_setPixelXY) : (&KS0108_clearPixelXY));

    while (xx >= yy) {
        drawPixel(x + xx, y + yy);
        drawPixel(x - xx, y + yy);
        drawPixel(x - xx, y - yy);
        drawPixel(x + xx, y - yy);
        drawPixel(x + yy, y + xx);
        drawPixel(x - yy, y + xx);
        drawPixel(x - yy, y - xx);
        drawPixel(x + yy, y - xx);

        yy++;
        re += yc;
        yc += 2;

        if ((re << 1) + xc > 0) {
            xx--;
            re += xc;
            xc += 2;
        }
    }
}


/* KS0108_drawFilledCircle: draws a filled circle
 */
void KS0108_drawFilledCircle(uint8_t x, uint8_t y, uint8_t r, int8_t c) {
    int16_t xx = r, yy = 0, xc = 1 - (r << 1), yc = 1, re = 0;

    while (xx >= yy) {
        KS0108_drawVerticalLine(x + xx, y - yy, yy << 1, c);
        KS0108_drawVerticalLine(x - xx, y - yy, yy << 1, c);

        KS0108_drawVerticalLine(x + yy, y - xx, xx << 1, c);
        KS0108_drawVerticalLine(x - yy, y - xx, xx << 1, c);

        yy++;
        re += yc;
        yc += 2;

        if ((re << 1) + xc > 0) {
            xx--;
            re += xc;
            xc += 2;
        }
    }
}


/* KS0108__gotoXY: for internal use;
 *                 but you need to use this function instead of KS0108_gotoXY(),
 *                 if you want to write a character or a string and do not
 *                 use KS0108_charGotoXY()
 */
void KS0108__gotoXY(uint8_t x, uint8_t y) {
    KS0108_x = x;
    KS0108_y = y;

    if (KS0108_x < 64) {
        KS0108_CONTROL_ONLY_CSB    /* middle part of the display */
        KS0108_writeCommand(KS0108_DISPLAY_SET_PAGE | (KS0108_y >> 3));
        KS0108_writeCommand(KS0108_DISPLAY_SET_ADDRESS | (0));

        KS0108_CONTROL_ONLY_CSA    /* right part of the display */
        KS0108_writeCommand(KS0108_DISPLAY_SET_PAGE | (KS0108_y >> 3));
        KS0108_writeCommand(KS0108_DISPLAY_SET_ADDRESS | (0));

        KS0108_CONTROL_NO_CS       /* left part of the display */
        KS0108_writeCommand(KS0108_DISPLAY_SET_PAGE | (KS0108_y >> 3));
        KS0108_writeCommand(KS0108_DISPLAY_SET_ADDRESS | KS0108_x);

    } else if (KS0108_x < 128) {
        KS0108_CONTROL_ONLY_CSA    /* right part of the display */
        KS0108_writeCommand(KS0108_DISPLAY_SET_PAGE | (KS0108_y >> 3));
        KS0108_writeCommand(KS0108_DISPLAY_SET_ADDRESS | (0));
    
        KS0108_CONTROL_ONLY_CSB    /* middle part of the display */
        KS0108_writeCommand(KS0108_DISPLAY_SET_PAGE | (KS0108_y >> 3));
        KS0108_writeCommand(KS0108_DISPLAY_SET_ADDRESS | (KS0108_x - 64));

    } else {
        KS0108_CONTROL_ONLY_CSA    /* right part of the display */
        KS0108_writeCommand(KS0108_DISPLAY_SET_PAGE | (KS0108_y >> 3));
        KS0108_writeCommand(KS0108_DISPLAY_SET_ADDRESS | (KS0108_x - 128));
    }    
}


/* KS0108_drawBitmap: draws a bitmap
 *                    "x" and "width" may be any
 *                    "y" % 8 should be 0, "height" % 8 should be 0
 */
void KS0108_drawBitmap(const uint8_t *bmp, uint8_t x, uint8_t y,
                       uint8_t width, uint8_t height, int8_t c) {
    register uint8_t xx;
    uint8_t yy, y2;

    y = (y >> 3) << 3;
    height = (height >> 3) << 3;
    y2 = height + y;

    for (yy = y; yy < y2; yy += 8) {
        KS0108__gotoXY(x, yy);

        if (c == SET_PIXEL)
            for(xx = 0; xx < width; xx++) 
                KS0108_writeData(pgm_read_byte(bmp++));
        else
            for(xx = 0; xx < width; xx++) 
                KS0108_writeData(~pgm_read_byte(bmp++));
    }
}


/* KS0108_drawSprite: draws a sprite
 *                    "x", "y", "width" and "height" may be any
 */
void KS0108_drawSprite(const uint8_t *bmp, uint8_t x, uint8_t y,
                        uint8_t width, uint8_t height, int8_t c) {
    register uint8_t xx;
    uint8_t tmp, yy, yyMul8PlusY;
    uint8_t yyMax, yyMulWidth;
    uint8_t (*doBits)(uint8_t, uint8_t) =
           ((c == SET_PIXEL) ? (&setBits) : (&clearBits));

    yyMax = (height >> 3) + ((height % 8) ? 1 : 0);
    for (yy = 0; yy <= yyMax; yy++) {
        yyMulWidth = yy * width;
        yyMul8PlusY = y + (yy << 3);
        for (xx = 0; xx < width; xx++) {
            KS0108_gotoXY(x + xx, yyMul8PlusY);
            KS0108_readData();
            KS0108_gotoXY(x + xx, yyMul8PlusY);    /* ... to do this twice */
            tmp = KS0108_readData();
            KS0108_gotoXY(x + xx, yyMul8PlusY);

            if (yy == 0)
                KS0108_writeData(doBits(tmp,
                    pgm_read_byte(&bmp[xx]) << (y % 8)));
            else if (yy < yyMax)
                KS0108_writeData(doBits(tmp,
                    (pgm_read_byte(&bmp[yyMulWidth - width + xx]) >>
                                                              (8 - (y % 8))) |
                    (pgm_read_byte(&bmp[yyMulWidth + xx]) << (y % 8))));
            else    /* yy == yyMax */
                KS0108_writeData(doBits(tmp,
                    pgm_read_byte(&bmp[yyMulWidth - width + xx]) >>
                                                              (8 - (y % 8))));
        }
    }
}


/* KS0108_charGotoXY: sets X, Y position for displaying of characters;
 *                    for 192x64 graphics display - x:<0, 31>, y:<0, 7>
 */
void KS0108_charGotoXY(uint8_t x, uint8_t y) {
    KS0108__gotoXY(x * 6, y << 3);
}


/* KS0108_writeChar: writes a single character
 */
void inline KS0108_writeChar(uint8_t ch, int8_t c) {
    uint16_t n = (ch - 32) * 5;

    if (c == SET_PIXEL) {
        KS0108_writeData(pgm_read_byte(fonts5x8 + n++));
        KS0108_writeData(pgm_read_byte(fonts5x8 + n++));
        KS0108_writeData(pgm_read_byte(fonts5x8 + n++));
        KS0108_writeData(pgm_read_byte(fonts5x8 + n++));
        KS0108_writeData(pgm_read_byte(fonts5x8 + n));
        KS0108_writeData(0x00);
    } else {
        KS0108_writeData(~pgm_read_byte(fonts5x8 + n++));
        KS0108_writeData(~pgm_read_byte(fonts5x8 + n++));
        KS0108_writeData(~pgm_read_byte(fonts5x8 + n++));
        KS0108_writeData(~pgm_read_byte(fonts5x8 + n++));
        KS0108_writeData(~pgm_read_byte(fonts5x8 + n));
        KS0108_writeData(0xff);
    }

    if (KS0108_x == 0) {
        KS0108_y += 8;

        KS0108_charGotoXY(0, KS0108_y >> 3);
    }
}


/* KS0108_writeCharUTF8: writes a single character in UTF-8
 */
void inline KS0108_writeCharUTF8(uint32_t n, int8_t c) {
    uint16_t j;
    int16_t min = 0, max = FONTS5X8_UTF8_MAX - 1, mid;

    union {
        struct {
            uint8_t b0;
            uint8_t b1;
            uint16_t b23;
        } s;
        uint32_t w2;
    } ww;

    /* binary search */
    do {
        mid = min + ((max - min) >> 1);
        j = mid << 3;
        ww.s.b23 = pgm_read_byte(fonts5x8_UTF8 + j);
        ww.s.b1 = pgm_read_byte(fonts5x8_UTF8 + j + 1);
        ww.s.b0 = pgm_read_byte(fonts5x8_UTF8 + j + 2);

        if (n > ww.w2)
            min = mid + 1;
        else
            max = mid - 1;
    } while ((ww.w2 != n) && (min <= max));

    if (ww.w2 != n)    /* no such character found */
        j = 0;

    j += 3;

    if (c == SET_PIXEL) {
        KS0108_writeData(pgm_read_byte(fonts5x8_UTF8 + j++));
        KS0108_writeData(pgm_read_byte(fonts5x8_UTF8 + j++));
        KS0108_writeData(pgm_read_byte(fonts5x8_UTF8 + j++));
        KS0108_writeData(pgm_read_byte(fonts5x8_UTF8 + j++));
        KS0108_writeData(pgm_read_byte(fonts5x8_UTF8 + j));
        KS0108_writeData(0x00);
    } else {
        KS0108_writeData(~pgm_read_byte(fonts5x8_UTF8 + j++));
        KS0108_writeData(~pgm_read_byte(fonts5x8_UTF8 + j++));
        KS0108_writeData(~pgm_read_byte(fonts5x8_UTF8 + j++));
        KS0108_writeData(~pgm_read_byte(fonts5x8_UTF8 + j++));
        KS0108_writeData(~pgm_read_byte(fonts5x8_UTF8 + j));
        KS0108_writeData(0xff);
    }

    if (KS0108_x == 0) {
        KS0108_y += 8;

        KS0108_charGotoXY(0, KS0108_y >> 3);
    }
}


/* KS0108_writeCharSprite: writes a single character as a sprite
 */
void inline KS0108_writeCharSprite(uint8_t ch, int8_t c) {
    uint16_t n = (ch - 32) * 5;

    KS0108_drawSprite(fonts5x8 + n, KS0108_x, KS0108_y, 5, 8, c);
}


/* KS0108_writeCharUTF8Sprite: writes a single character in UTF-8 as a sprite
 */
void inline KS0108_writeCharUTF8Sprite(uint32_t n, int8_t c) {
    uint16_t j;
    int16_t min = 0, max = FONTS5X8_UTF8_MAX - 1, mid;

    union {
        struct {
            uint8_t b0;
            uint8_t b1;
            uint16_t b23;
        } s;
        uint32_t w2;
    } ww;

    /* binary search */
    do {
        mid = min + ((max - min) >> 1);
        j = mid << 3;
        ww.s.b23 = pgm_read_byte(fonts5x8_UTF8 + j);
        ww.s.b1 = pgm_read_byte(fonts5x8_UTF8 + j + 1);
        ww.s.b0 = pgm_read_byte(fonts5x8_UTF8 + j + 2);

        if (n > ww.w2)
            min = mid + 1;
        else
            max = mid - 1;
    } while ((ww.w2 != n) && (min <= max));

    if (ww.w2 != n)    /* no such character found */
        j = 0;

    j += 3;

    KS0108_drawSprite(fonts5x8_UTF8 + j, KS0108_x, KS0108_y, 5, 8, c);
}


/* KS0108_writeString: writes a string
 */
void KS0108_writeString(const uint8_t *s, int8_t c) {
    for ( ; *s; s++)
        KS0108_writeChar(*s, c);
}


/* KS0108_writeStringUTF8: writes a string in UTF-8 encoding;
 *                         only two and three bytes UTF-8 supported
 */
void KS0108_writeStringUTF8(const uint8_t *s, int8_t c) {
    for ( ; *s; s++) {
        if ((*s) & 0x80) {    /* UTF8 */
            union {
                struct {
                    uint8_t b0;
                    uint8_t b1;
                    uint16_t b23;
                } s;
                uint32_t w2;
            } ww;

            if (((*s) & 0xe0) == 0xc0) {    /* two bytes UTF8 */
                ww.s.b23 = 0x00;
                ww.s.b1 = *s++;
                ww.s.b0 = *s;
                KS0108_writeCharUTF8(ww.w2, c);
            } else {    /* three bytes and more; max three bytes supported */
                ww.s.b23 = *s++;
                ww.s.b1 = *s++;
                ww.s.b0 = *s;
                KS0108_writeCharUTF8(ww.w2, c);
            }
        } else
            KS0108_writeChar(*s, c);
    }
}


/* KS0108_writeStringSprite: writes a string as a sprite
 */
void KS0108_writeStringSprite(const uint8_t *s, int8_t c) {
    uint8_t x = KS0108_x, y = KS0108_y;

    for ( ; *s; s++) {
        KS0108_writeCharSprite(*s, c);
        x += 6;
        KS0108_x = x;
        KS0108_y = y;
    }
}


/* KS0108_writeStringUTF8Sprite: writes a string in UTF-8 encoding as a sprite;
 *                               only two and three bytes UTF-8 supported
 */
void KS0108_writeStringUTF8Sprite(const uint8_t *s, int8_t c) {
    uint8_t x = KS0108_x, y = KS0108_y;

    for ( ; *s; s++) {
        if ((*s) & 0x80) {    /* UTF8 */
            union {
                struct {
                    uint8_t b0;
                    uint8_t b1;
                    uint16_t b23;
                } s;
                uint32_t w2;
            } ww;
    
            if (((*s) & 0xe0) == 0xc0) {    /* two bytes UTF8 */
                ww.s.b23 = 0x00;
                ww.s.b1 = *s++;
                ww.s.b0 = *s;
                KS0108_writeCharUTF8Sprite(ww.w2, c);
            } else {    /* three bytes and more; max three bytes supported */
                ww.s.b23 = *s++;
                ww.s.b1 = *s++;
                ww.s.b0 = *s;
                KS0108_writeCharUTF8Sprite(ww.w2, c);
            }
        } else
            KS0108_writeCharSprite(*s, c);

        x += 6;
        KS0108_x = x;
        KS0108_y = y;
    }
}


Kod źródłowy pliku "fonts5x8.h":

/* fonts5x8: fonts and national UTF8 fonts
 *
 * Sebastian Pawlak, 2011, v1.0
 */

#include <avr/pgmspace.h>

#ifndef _FONTS_5X8_
#define _FONTS_5X8_


uint8_t fonts5x8[] PROGMEM = {
    0x00, 0x00, 0x00, 0x00, 0x00,    // SP
    0x00, 0x00, 0x5F, 0x00, 0x00,    // !
    0x00, 0x07, 0x00, 0x07, 0x00,    // "
    0x14, 0x7F, 0x14, 0x7F, 0x14,    // #
    0x24, 0x2A, 0x7F, 0x2A, 0x12,    // $
    0x23, 0x13, 0x08, 0x64, 0x62,    // %
    0x36, 0x49, 0x55, 0x22, 0x50,    // &
    0x00, 0x00, 0x07, 0x00, 0x00,    // '
    0x00, 0x1C, 0x22, 0x41, 0x00,    // (
    0x00, 0x41, 0x22, 0x1C, 0x00,    // )
    0x14, 0x08, 0x3e, 0x08, 0x14,    // *
    0x08, 0x08, 0x3E, 0x08, 0x08,    // +
    0x00, 0x50, 0x30, 0x00, 0x00,    // ,
    0x08, 0x08, 0x08, 0x08, 0x08,    // -
    0x00, 0x30, 0x30, 0x00, 0x00,    // .
    0x20, 0x10, 0x08, 0x04, 0x02,    // /
    0x3E, 0x51, 0x49, 0x45, 0x3E,    // 0
    0x00, 0x42, 0x7F, 0x40, 0x00,    // 1
    0x42, 0x61, 0x51, 0x49, 0x46,    // 2
    0x21, 0x41, 0x45, 0x4B, 0x31,    // 3
    0x18, 0x14, 0x12, 0x7F, 0x10,    // 4
    0x27, 0x45, 0x45, 0x45, 0x39,    // 5
    0x3C, 0x4A, 0x49, 0x49, 0x30,    // 6
    0x01, 0x71, 0x09, 0x05, 0x03,    // 7
    0x36, 0x49, 0x49, 0x49, 0x36,    // 8
    0x06, 0x49, 0x49, 0x29, 0x1E,    // 9
    0x00, 0x36, 0x36, 0x00, 0x00,    // :
    0x00, 0x56, 0x36, 0x00, 0x00,    // ;
    0x00, 0x08, 0x14, 0x22, 0x41,    // <
    0x14, 0x14, 0x14, 0x14, 0x14,    // =
    0x41, 0x22, 0x14, 0x08, 0x00,    // >
    0x02, 0x01, 0x51, 0x09, 0x06,    // ?
    0x3e, 0x41, 0x5d, 0x55, 0x0e,    // @
    0x7E, 0x11, 0x11, 0x11, 0x7E,    // A
    0x7F, 0x49, 0x49, 0x49, 0x36,    // B
    0x3E, 0x41, 0x41, 0x41, 0x22,    // C
    0x7F, 0x41, 0x41, 0x22, 0x1C,    // D
    0x7F, 0x49, 0x49, 0x49, 0x41,    // E
    0x7F, 0x09, 0x09, 0x01, 0x01,    // F
    0x3E, 0x41, 0x49, 0x49, 0x3a,    // G
    0x7F, 0x08, 0x08, 0x08, 0x7F,    // H
    0x00, 0x41, 0x7F, 0x41, 0x00,    // I
    0x20, 0x40, 0x41, 0x3F, 0x01,    // J
    0x7F, 0x08, 0x14, 0x22, 0x41,    // K
    0x7F, 0x40, 0x40, 0x40, 0x40,    // L
    0x7F, 0x02, 0x04, 0x02, 0x7F,    // M
    0x7F, 0x04, 0x08, 0x10, 0x7F,    // N
    0x3E, 0x41, 0x41, 0x41, 0x3E,    // O
    0x7F, 0x09, 0x09, 0x09, 0x06,    // P
    0x3E, 0x41, 0x51, 0x21, 0x5E,    // Q
    0x7F, 0x09, 0x19, 0x29, 0x46,    // R
    0x46, 0x49, 0x49, 0x49, 0x31,    // S
    0x01, 0x01, 0x7F, 0x01, 0x01,    // T
    0x3F, 0x40, 0x40, 0x40, 0x3F,    // U
    0x1F, 0x20, 0x40, 0x20, 0x1F,    // V
    0x7F, 0x20, 0x18, 0x20, 0x7F,    // W
    0x63, 0x14, 0x08, 0x14, 0x63,    // X
    0x03, 0x04, 0x78, 0x04, 0x03,    // Y
    0x61, 0x51, 0x49, 0x45, 0x43,    // Z
    0x00, 0x00, 0x7F, 0x41, 0x41,    // [
    0x02, 0x04, 0x08, 0x10, 0x20,    // '\'
    0x41, 0x41, 0x7F, 0x00, 0x00,    // ]
    0x04, 0x02, 0x01, 0x02, 0x04,    // ^
    0x40, 0x40, 0x40, 0x40, 0x40,    // _
    0x00, 0x01, 0x02, 0x04, 0x00,    // `
    0x20, 0x54, 0x54, 0x54, 0x78,    // a
    0x7F, 0x48, 0x44, 0x44, 0x38,    // b
    0x38, 0x44, 0x44, 0x44, 0x28,    // c
    0x38, 0x44, 0x44, 0x48, 0x7F,    // d
    0x38, 0x54, 0x54, 0x54, 0x18,    // e
    0x08, 0x7E, 0x09, 0x01, 0x02,    // f
    0x08, 0x54, 0x54, 0x54, 0x3C,    // g
    0x7F, 0x08, 0x04, 0x04, 0x78,    // h
    0x00, 0x44, 0x7D, 0x40, 0x00,    // i
    0x20, 0x40, 0x44, 0x3D, 0x00,    // j
    0x00, 0x7F, 0x10, 0x28, 0x44,    // k
    0x00, 0x41, 0x7F, 0x40, 0x00,    // l
    0x7C, 0x04, 0x18, 0x04, 0x78,    // m
    0x7C, 0x08, 0x04, 0x04, 0x78,    // n
    0x38, 0x44, 0x44, 0x44, 0x38,    // o
    0x7C, 0x14, 0x14, 0x14, 0x08,    // p
    0x08, 0x14, 0x14, 0x18, 0x7C,    // q
    0x7C, 0x08, 0x04, 0x04, 0x08,    // r
    0x48, 0x54, 0x54, 0x54, 0x24,    // s
    0x04, 0x3F, 0x44, 0x40, 0x20,    // t
    0x3C, 0x40, 0x40, 0x20, 0x7C,    // u
    0x1C, 0x20, 0x40, 0x20, 0x1C,    // v
    0x3C, 0x40, 0x30, 0x40, 0x3C,    // w
    0x44, 0x28, 0x10, 0x28, 0x44,    // x
    0x0C, 0x50, 0x50, 0x50, 0x3C,    // y
    0x44, 0x64, 0x54, 0x4C, 0x44,    // z
    0x00, 0x08, 0x36, 0x41, 0x00,    // {
    0x00, 0x00, 0x7F, 0x00, 0x00,    // |
    0x00, 0x41, 0x36, 0x08, 0x00,    // }
    0x08, 0x04, 0x08, 0x10, 0x08,    // ~
    0x00, 0x00, 0x08, 0x00, 0x00,    // DEL
};


enum {
    FONTS5X8_UTF8_MAX = 30,
};


uint8_t fonts5x8_UTF8[FONTS5X8_UTF8_MAX * 8] PROGMEM = {
/*   UTF8-code    |------- character --------|  */
  0x00,0x00,0x00, 0xff, 0x81, 0x81, 0x81, 0xff, // default character
  0x00,0xc2,0xb0, 0x00, 0x06, 0x09, 0x09, 0x06, // degree sign
  0x00,0xc2,0xb1, 0x24, 0x24, 0x3f, 0x24, 0x24, // plus-minus sign
  0x00,0xc2,0xb2, 0x00, 0x19, 0x15, 0x12, 0x00, // superscript two
  0x00,0xc2,0xb3, 0x00, 0x15, 0x15, 0x0a, 0x00, // superscript three
  0x00,0xc2,0xb5, 0xfc, 0x20, 0x20, 0x20, 0x1c, // micro sign
  0x00,0xc2,0xbc, 0x13, 0x08, 0x64, 0x52, 0xf1, // vulgar fraction one quarter
  0x00,0xc2,0xbd, 0x13, 0x08, 0x04, 0xd2, 0xb1, // vulgar fration one half
  0x00,0xc3,0x93, 0x3c, 0x42, 0x43, 0x42, 0x3c, // capital letter O with acute
  0x00,0xc3,0xb3, 0x38, 0x44, 0x46, 0x45, 0x38, // small letter O with acute
  0x00,0xc4,0x84, 0x7E, 0x11, 0x11, 0x91, 0x7E, // capital letter A with ogonek
  0x00,0xc4,0x85, 0x20, 0x54, 0x54, 0xd4, 0x78, // small letter A with ogonek
  0x00,0xc4,0x86, 0x3c, 0x42, 0x43, 0x42, 0x24, // capital letter C with acute
  0x00,0xc4,0x87, 0x38, 0x44, 0x46, 0x45, 0x28, // small letter C with acute
  0x00,0xc4,0x98, 0x7f, 0x49, 0x49, 0xc9, 0x41, // capital letter E with ogonek
  0x00,0xc4,0x99, 0x38, 0x54, 0x54, 0xd4, 0x18, // small letter E with ogonek
  0x00,0xc5,0x81, 0x7F, 0x48, 0x44, 0x40, 0x40, // capital letter L with stroke
  0x00,0xc5,0x82, 0x00, 0x49, 0x7f, 0x44, 0x00, // small letter L with stroke
  0x00,0xc5,0x83, 0x7e, 0x20, 0x12, 0x09, 0x7e, // capital letter N with acute
  0x00,0xc5,0x84, 0x7c, 0x08, 0x06, 0x05, 0x78, // small letter N with acute
  0x00,0xc5,0x9a, 0x44, 0x4a, 0x4b, 0x4a, 0x32, // capital letter S with acute
  0x00,0xc5,0x9b, 0x48, 0x54, 0x56, 0x55, 0x24, // small letter S with acute
  0x00,0xc5,0xb9, 0x44, 0x64, 0x56, 0x4d, 0x44, // capital letter Z with acute
  0x00,0xc5,0xba, 0x44, 0x64, 0x56, 0x4d, 0x44, // small letter Z with acute
  0x00,0xc5,0xbb, 0x42, 0x62, 0x53, 0x4a, 0x46, // capital Z with dot above
  0x00,0xc5,0xbc, 0x44, 0x64, 0x55, 0x4C, 0x44, // small Z with dot above
  0xe2,0x86,0x90, 0x08, 0x1c, 0x3e, 0x08, 0x08, // leftwards arrow
  0xe2,0x86,0x91, 0x04, 0x06, 0x7f, 0x06, 0x04, // upwards arrow
  0xe2,0x86,0x92, 0x08, 0x08, 0x3e, 0x1c, 0x08, // rightwards arrow
  0xe2,0x86,0x93, 0x10, 0x30, 0x7f, 0x30, 0x10, // downwards arrow
};

#endif

Kod źródłowy pliku "main.c":

/* How to use libKS0108
 *
 * Sebastian Pawlak, 2011
 */

#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "libKS0108.h"


/* E=mc2 */
uint8_t bitmap1[] PROGMEM = {
    0x00, 0x00, 0x18, 0x38, 0x38, 0x38, 0xf8, 0xf8, 0xf8, 0x30, 0x38, 0x38,
    0x3c, 0x1c, 0x3c, 0x38, 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00,
    0x00, 0x00, 0x00, 0x20, 0x38, 0x3c, 0x06, 0x86, 0x86, 0xce, 0xf8, 0x30,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x38, 0x38,
    0x78, 0x7e, 0x3c, 0x00, 0x00, 0x07, 0x87, 0x86, 0x00, 0x98, 0xb8, 0x98,
    0xbc, 0x9c, 0x9c, 0x9c, 0xbc, 0x98, 0x98, 0x00, 0x02, 0x06, 0x7e, 0xfe,
    0xfe, 0x0e, 0x0f, 0x07, 0x2f, 0xfe, 0xfe, 0x1e, 0x07, 0x07, 0xff, 0xff,
    0xd0, 0x00, 0x00, 0xe0, 0xf8, 0xfe, 0x0e, 0x07, 0x07, 0x03, 0x07, 0x3f,
    0x7f, 0x7e, 0x7c, 0x00, 0x10, 0x1e, 0x1f, 0x1b, 0x39, 0x31, 0x10, 0x1c,
    0x0c, 0x00, 0x00, 0x00, 0x60, 0x60, 0xe0, 0xf0, 0xfb, 0xff, 0xff, 0xf0,
    0xe0, 0xe0, 0x70, 0xf0, 0xf0, 0x70, 0x7f, 0x7f, 0x7b, 0x00, 0x01, 0x01,
    0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x60, 0xf2,
    0xff, 0xff, 0x00, 0x00, 0x00, 0x3c, 0x3f, 0x39, 0x00, 0x00, 0x20, 0xfd,
    0xff, 0xef, 0x60, 0x00, 0x03, 0x1f, 0x3d, 0x38, 0x70, 0xe0, 0xf0, 0x60,
    0x20, 0x30, 0x1e, 0x0e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00,
};

/* ! */
uint8_t bitmap2[] PROGMEM = {
    0xe0, 0xf8, 0xfc, 0xfe, 0xfe, 0xff, 0x03, 0x03, 0xff, 0xfe, 0xfe, 0xfc,
    0xf8, 0xe0, 0x01, 0x07, 0x0f, 0x1f, 0x1f, 0x3f, 0x33, 0x33, 0x3f, 0x1f,
    0x1f, 0x0f, 0x07, 0x01,
};


int main(void)
{
    int16_t i;
    volatile int16_t k, l;
    int8_t c = SET_PIXEL;

    KS0108_init();
    KS0108_displayOn();

    srand(1);

    while (1) {

        if (c == SET_PIXEL) {
            KS0108_clearDisplay();
            for (i = 0; i < 192; i += 2)
                KS0108_setPixelXY(i,0), KS0108_setPixelXY(i, 63);
            for (i = 0; i < 64; i += 2)
                KS0108_setPixelXY(0,i), KS0108_setPixelXY(191, i);
        } else {
            KS0108_setDisplay();
            for (i = 0; i < 192; i += 2)
                KS0108_clearPixelXY(i,0), KS0108_clearPixelXY(i, 63);
            for (i = 0; i < 64; i += 2)
                KS0108_clearPixelXY(0,i), KS0108_clearPixelXY(191, i);
        }


        KS0108_drawRectangle(2, 2, 32, 30, c);
        if (c == SET_PIXEL)
            for (i = 0; i < 200; i++)
                KS0108_setPixelXY((rand() % 32) + 2, (rand() % 30) + 2);
        else
            for (i = 0; i < 200; i++)
                KS0108_clearPixelXY((rand() % 32) + 2, (rand() % 30) + 2);

        KS0108_drawFilledRectangle(2, 32, 32, 30, c);
        if (c == SET_PIXEL)
            for (i = 0; i < 200; i++)
                KS0108_clearPixelXY((rand() % 32) + 2, (rand() % 30) + 32);
        else
            for (i = 0; i < 200; i++)
                KS0108_setPixelXY((rand() % 32) + 2, (rand() % 30) + 32);


        for (i = -12; i <= 12; i += 4)
            KS0108_drawLine(35, 15 - i, 67, 15 + i, c);

        for (i = -12; i <= 12; i += 4)
            KS0108_drawLineFaster(51 + i, 29, 51 - i, 61, c);


        KS0108_drawCircle(84, 17, 13, c);

        KS0108_drawFilledCircle(84, 48, 13, c);


        KS0108_charGotoXY(18, 1);
        KS0108_writeString("ABcd", c);

        KS0108_charGotoXY(22, 1);
        KS0108_writeString("12$%",
                           (c == SET_PIXEL) ? CLEAR_PIXEL : SET_PIXEL);


        KS0108_drawHorizontalLine(170, 10, 18, c);

        KS0108_drawVerticalLine(180, 4, 14, c);
        KS0108_drawVerticalLine(182, 8, 14, c);
        KS0108_drawVerticalLine(184, 8, 8, c);
        KS0108_drawVerticalLine(186, 8, 9, c);
        KS0108_drawVerticalLine(188, 8, 16, c);


        KS0108_charGotoXY(18, 2);
        KS0108_writeStringUTF8("G""\xc5\xbc""eg""\xc5\xbc"
                               "\xc3\xb3""\xc5\x82""ka""\xe2\x86\x93", c);
        KS0108_charGotoXY(18, 3);
        KS0108_writeStringUTF8("Gżegżółka↓", c);

        KS0108__gotoXY(174, 13);
        KS0108_writeStringSprite("@", c);

        KS0108__gotoXY(174, 21);
        KS0108_writeStringUTF8Sprite("\xe2\x86\x92", c);


        KS0108_drawBitmap(bitmap1, 110, 32, 73, 24, c);


        KS0108_drawSprite(bitmap2, rand() % (192 - 14), rand() % (64 - 14),
                          14, 14, c);


        if (c == SET_PIXEL)
            c = CLEAR_PIXEL;
        else
            c = SET_PIXEL;

        for (k = 0; k < 1000; k++)
            for (l = 0; l < 2000; l++)
                ;
    }

    return 0;
}
w3cw3c
automatyka przemysłowa