395 lines
10 KiB
C
395 lines
10 KiB
C
/*
|
|
* lc7981.c
|
|
*
|
|
* Version 0.7 beta
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS"
|
|
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing rights and limitations
|
|
* under the License.
|
|
*
|
|
* The Original Code is Sebastians AVR Library for lc7981.
|
|
*
|
|
* The Initial Developer of the Original Code is Sebastian Schumb (webmaster@sebastians-site.de).
|
|
*
|
|
* Contributor(s): None so far.
|
|
*
|
|
* Any version below 0.6 is still licensed under GPL.
|
|
* The GPLed versions will neither be supported, nor developed any further.
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
#include "lc7981.h"
|
|
|
|
uint8_t lcd_mode, //!< Currently used mode, can be text or graphic.
|
|
lcd_curline; //!< Current line. Used for scrolling in text mode.
|
|
|
|
/**
|
|
* lcd_init set the to default values.
|
|
*
|
|
* @param mode LCD_TEXT for text mode and LCD_GRAPHIC for graphic mode
|
|
*/
|
|
void lcd_init(uint8_t mode) {
|
|
|
|
LCD_DATA_DDR = 0xFF;
|
|
LCD_DATA = 0;
|
|
LCD_CRTL_DDR |= (1 << LCD_RS) | (1 << LCD_RW) | (1 << LCD_EN);
|
|
LCD_CTRL = 0;
|
|
|
|
|
|
lcd_en_low();
|
|
lcd_rs_low();
|
|
lcd_rw_low();
|
|
|
|
if(mode == LCD_TEXT) {
|
|
|
|
lcd_mode = LCD_TEXT;
|
|
|
|
lcd_write_command(0x00,0x3C);
|
|
lcd_write_command(0x01,0x75);
|
|
lcd_write_command(0x02,LCD_TEXT_COLUMNS - 1);
|
|
lcd_write_command(0x03,0x4F);
|
|
lcd_write_command(0x04,0x07);
|
|
lcd_write_command(0x08,0x00);
|
|
lcd_write_command(0x09,0x00);
|
|
lcd_write_command(0x0A,0x00);
|
|
lcd_write_command(0x0B,0x00);
|
|
|
|
}
|
|
else {
|
|
|
|
lcd_mode = LCD_GRAPHIC;
|
|
|
|
lcd_write_command(0x00,0x32);
|
|
lcd_write_command(0x01,0x07);
|
|
lcd_write_command(0x02,(LCD_GRAPHIC_WIDTH / 8)-1);
|
|
lcd_write_command(0x03,0x4F);
|
|
lcd_write_command(0x08,0x00);
|
|
lcd_write_command(0x09,0x00);
|
|
lcd_write_command(0x0A,0x00);
|
|
lcd_write_command(0x0B,0x00);
|
|
}
|
|
|
|
lcd_clear();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Clears the display by setting the whole memory to 0.
|
|
*/
|
|
void lcd_clear() {
|
|
uint16_t i;
|
|
|
|
if(lcd_mode == LCD_TEXT) {
|
|
|
|
lcd_write_command(0x0A,0x00);
|
|
lcd_write_command(0x0B,0x00);
|
|
|
|
for(i = 1; i <= LCD_TEXT_LINES * LCD_TEXT_COLUMNS; i++)
|
|
lcd_write_command(0x0C,' ');
|
|
|
|
lcd_write_command(0x0A,0x00);
|
|
lcd_write_command(0x0B,0x00);
|
|
|
|
lcd_curline = 0;
|
|
}
|
|
else {
|
|
|
|
lcd_write_command(0x0A,0x00);
|
|
lcd_write_command(0x0B,0x00);
|
|
|
|
for(i = 0; i < ((LCD_GRAPHIC_WIDTH * LCD_GRAPHIC_HEIGHT)/8); i++)
|
|
lcd_write_command(0x0C,0x00);
|
|
|
|
lcd_write_command(0x0A,0x00);
|
|
lcd_write_command(0x0B,0x00);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Outputs text in at the current cursor position.
|
|
* If a \\n occurs in the last line of the display,
|
|
* all the other line will be 'scrolled' up.
|
|
* This function is textmode only.
|
|
* The the second line becomes the first, the third the second and so on ...
|
|
* @param txt the text
|
|
*/
|
|
void lcd_write_text(char *txt) {
|
|
uint8_t c,tmp,x,y;
|
|
uint16_t pos;
|
|
|
|
|
|
if(lcd_mode == LCD_TEXT) {
|
|
c = 0; //variable to count the chars in the current line
|
|
while(!(*txt == 0)) { //loop through the string
|
|
|
|
if(*txt == '\n' || c == LCD_TEXT_COLUMNS) { //linebreak if //n or if a line is too long
|
|
if(lcd_curline < LCD_TEXT_LINES - 1) { //next line
|
|
lcd_curline++;
|
|
c = 0;
|
|
lcd_gotoxy(0,lcd_curline);
|
|
}
|
|
else { //scroll up
|
|
for(y = 1; y < LCD_TEXT_LINES; y++ ) {
|
|
for(x = 0; x < LCD_TEXT_COLUMNS; x++) {
|
|
pos = (y * LCD_TEXT_COLUMNS) + x;
|
|
tmp = lcd_read_byte(pos);
|
|
lcd_gotoxy(x,y-1);
|
|
lcd_write_command(0x0C,tmp);
|
|
}
|
|
}
|
|
for(x = 0; x < LCD_TEXT_COLUMNS; x++) { //free the last line
|
|
lcd_write_command(0x0C,' ');
|
|
}
|
|
lcd_gotoxy(0,LCD_TEXT_LINES-1);
|
|
c = 0;
|
|
}
|
|
}
|
|
|
|
if(*txt != '\n') { //write the character
|
|
lcd_write_command(0x0C,*txt);
|
|
c++;
|
|
}
|
|
txt++;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the display cursor to a specific location.
|
|
* Right now this does only work in text mode,
|
|
* since there's no need for it now in graphics mode. \n
|
|
* If the x and y values are to big, the function does nothing.
|
|
*
|
|
* @param x the horizontal cursorposition (starts at 0)
|
|
* @param y the vertical cursorposition (starts at 0)
|
|
*
|
|
*/
|
|
void lcd_gotoxy(uint8_t x, uint8_t y) {
|
|
uint16_t pos;
|
|
|
|
if(lcd_mode == LCD_TEXT) {
|
|
if((x <= LCD_TEXT_COLUMNS - 1) && (y <= LCD_TEXT_LINES - 1)) {
|
|
pos = (y * LCD_TEXT_COLUMNS) + x;
|
|
|
|
lcd_write_command(0x0A,(uint8_t) pos );
|
|
lcd_write_command(0x0B,(uint8_t) (pos >> 8));
|
|
lcd_curline = y;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* set or unset a pixel at the specified location
|
|
*
|
|
* @param x horizontal position of the pixel (starts at 0)
|
|
* @param y horizontal position of the pixel (starts at 0)
|
|
* @param set can be PIXEL_ON or PIXEL_OFF
|
|
*/
|
|
void lcd_plot_pixel(uint8_t x, uint8_t y, uint8_t set) {
|
|
uint16_t pos;
|
|
uint8_t xr;
|
|
|
|
if((x <= LCD_GRAPHIC_WIDTH - 1) && (y <= LCD_GRAPHIC_HEIGHT - 1)) {
|
|
pos = y * (LCD_GRAPHIC_WIDTH / 8) + x / 8;
|
|
xr = x % 8;
|
|
lcd_write_command(0x0A,(uint8_t) pos );
|
|
lcd_write_command(0x0B,(uint8_t) (pos >> 8));
|
|
|
|
if(set == PIXEL_ON) {
|
|
lcd_write_command(0x0F,xr);
|
|
}
|
|
else {
|
|
lcd_write_command(0x0E,xr);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function will plot a bitmap with the upper left corner to the given coordinates.\n
|
|
* If the bitmap doesn't fit on the display at this location, nothing is drawn at all.\n
|
|
* Unset pixels are treated as transparent \n
|
|
* This function is by far the most tricky piece of code in this project,\n
|
|
* don't worry if you don't understand it at first sight. \n
|
|
* Actually it just loops bitwise through the bitmap and uses some \n
|
|
* nice bit shifting magic to get it anywhere you want.
|
|
*
|
|
* @param x horizontal position of the bitmap
|
|
* @param y vertical position of the bitmap
|
|
* @param bitmap pointer to the bitmap in pgmspace
|
|
* @param w width of the bitmap
|
|
* @param h height of the bitmap
|
|
*
|
|
* This function is dedicated to Greta, one of the most important persons in my life so far.\n
|
|
*
|
|
*/
|
|
|
|
void lcd_plot_bitmap(uint8_t x, uint8_t y, PGM_P bitmap, uint8_t w, uint8_t h) {
|
|
//curent x position in bytes, current y position in bytes, the width of the bitmap in bytes
|
|
uint8_t cx,cy,wb;
|
|
//source and destination position in bytes in the memory
|
|
uint16_t dpos,spos;
|
|
// x offest used if the x coordinate is in the middle of a byte
|
|
uint8_t xoff;
|
|
// various places to store a byte
|
|
uint8_t fbyte,nbyte,byte;
|
|
|
|
// check whether the bitmap fits on the display
|
|
if((x <= LCD_GRAPHIC_WIDTH - 1) && (y <= LCD_GRAPHIC_HEIGHT - 1)
|
|
&& (x + w <= LCD_GRAPHIC_WIDTH - 1) && (y + h <= LCD_GRAPHIC_HEIGHT - 1)) {
|
|
|
|
// Calculate the width in byte (1-8 pixel one byte, 9-16 pixel two bytes ..)
|
|
if (w % 8 != 0) {
|
|
wb = w / 8 + 1;
|
|
}
|
|
else {
|
|
wb = w / 8;
|
|
}
|
|
|
|
// Loop bytewise through the bitmap
|
|
for(cy = 0; cy < h; cy++) {
|
|
for(cx = 0; cx < wb; cx++) {
|
|
//source and destination positions
|
|
spos = cx + cy * wb;
|
|
dpos = (x + y * LCD_GRAPHIC_WIDTH) / 8 + (cx + cy * LCD_GRAPHIC_WIDTH / 8);
|
|
|
|
//Crop the Bitmap if it doesn't use all the bits in the last byte
|
|
if((w % 8 != 0) & (cx == wb -1)) {
|
|
byte = pgm_read_byte(bitmap+spos);
|
|
byte = (byte & ~(0xFF << (w % 8)));
|
|
}
|
|
else {
|
|
byte = pgm_read_byte(bitmap+spos);
|
|
}
|
|
|
|
//Coordinate is the first bit of a display memory byte
|
|
if(x % 8 == 0) {
|
|
byte = lcd_read_byte(dpos) | byte;
|
|
lcd_write_byte(dpos,byte);
|
|
}
|
|
else { // Coordinate is somewhere in the byte, let's do some shifting
|
|
xoff = x % 8;
|
|
|
|
fbyte = byte & ~(0xFF << (8 - xoff));
|
|
nbyte = byte & (0xFF << (8 - xoff));
|
|
|
|
byte = lcd_read_byte(dpos) | (fbyte << xoff);
|
|
lcd_write_byte(dpos, byte);
|
|
|
|
byte = lcd_read_byte(dpos+1) | (nbyte >> (8 - xoff));
|
|
lcd_write_byte(dpos+1, byte);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Plots a single character in graphicmode.
|
|
* Each character of the font is stored linewise. \n
|
|
* This means for a 8x8 Pixel font the 8 bytes are needed. \n
|
|
* The first byte is the first line and the last byte is the last line. \n
|
|
* The next 8byte are the next character.\n
|
|
* \n
|
|
* If the position is too close to the display edge so it can't be displayed completely,\n
|
|
* It won't be displayed at all.
|
|
*
|
|
* @param x_off horizontal position of the character
|
|
* @param y_off vertical position of the character
|
|
* @param c the character or it's ascii code
|
|
* @param fw width of the font (we start counting from 0, so a 10px width font will have fw = 9)
|
|
* @param fh height of the font (we start counting from 0, so a 10px height font will have fh = 9)
|
|
* @param font pointer to the flash area where the font is stored
|
|
*
|
|
*/
|
|
void lcd_plot_char(uint8_t x_off, uint8_t y_off, uint8_t c, uint8_t fw, uint8_t fh, PGM_P font) {
|
|
PGM_P letter;
|
|
uint8_t fsize,fwb;
|
|
|
|
if (fw % 8 != 0) {
|
|
fwb = fw / 8 + 1;
|
|
}
|
|
else {
|
|
fwb = fw / 8;
|
|
}
|
|
|
|
fsize = fh * fwb;
|
|
letter = font + c * fsize;
|
|
|
|
lcd_plot_bitmap(x_off,y_off,letter,fw,fh);
|
|
|
|
}
|
|
|
|
/**
|
|
* Plots a text using lcd_plot_char.
|
|
* @param x_off horizontal position of the character
|
|
* @param y_off vertical position of the character
|
|
* @param text the text that is plotted
|
|
* @param fw width of the font (we start counting from 0, so a 10px width font will have fw = 9)
|
|
* @param fh height of the font (we start counting from 0, so a 10px height font will have fh = 9)
|
|
* @param font pointer to the flash area where the font is stored
|
|
*
|
|
*
|
|
*
|
|
* @see lcd_plot_char
|
|
*/
|
|
void lcd_plot_text(uint8_t x_off, uint8_t y_off, const char *text, uint8_t fw, uint8_t fh, PGM_P font) {
|
|
|
|
while(*text) {
|
|
lcd_plot_char(x_off,y_off,(uint8_t) *text,fw,fh,font);
|
|
x_off += fw;
|
|
text++;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* Plots a text using lcd_plot_char.
|
|
* @param x_off horizontal position of the character
|
|
* @param y_off vertical position of the character
|
|
* @param text flash area where the text is stored
|
|
* @param fw width of the font (we start counting from 0, so a 10px width font will have fw = 9)
|
|
* @param fh height of the font (we start counting from 0, so a 10px height font will have fh = 9)
|
|
* @param font pointer to the flash area where the font is stored
|
|
*
|
|
*
|
|
*
|
|
* @see lcd_plot_char
|
|
* @see lcd_plot_text
|
|
*/
|
|
void lcd_plot_pgmtext(uint8_t x_off, uint8_t y_off, PGM_P text, uint8_t fw, uint8_t fh, PGM_P font) {
|
|
uint8_t c;
|
|
|
|
c = pgm_read_byte (text);
|
|
while (c != 0)
|
|
{
|
|
lcd_plot_char(x_off,y_off,c,fw,fh,font);
|
|
x_off += fw;
|
|
text++;
|
|
c = pgm_read_byte (text);
|
|
}
|
|
}
|
|
|
|
|
|
|