Full Version : Butterfly LCD Driver (GCC)
avr >>C PROGRAMMING (AVR) >>Butterfly LCD Driver (GCC)


AVR_Admin- 05-04-2006
Butterfly LCD Driver:

Below is code to control the Butterfly LCD. Rewrote code from Atmel's Butterfly example for size and speed - the resulting code is nice enough with little bloat. The routines are designed for displaying strings out of flash or SRAM only (no direct character writing, etc).

Use LCD_Init(); to initialise the driver (routine stolen from Atmel's code ) and the LCD_puts or LCD_puts_f to show a string. Scrolling is automatic if the string is more than six characters long.

Use as you see fit.

LCD_Driver.c
CODE

/*
  This is a basic driver for the Butterfly LCD. It offers the ability to
  change the contrast and display strings (scrolling or static) from flash
  or SRAM memory only.
   
  This has been completly rewritten from the Atmel code; in this version, as
  much processing as possible is performed by the string display routines
  rather than the interrupt so that the interrupt executes as fast as possible.
*/

#include "LCD_Driver.h"

uint8_t  TextBuffer[LCD_TEXTBUFFER_SIZE + 7];
uint8_t  SegBuffer[LCD_SEGBUFFER_SIZE];
uint8_t  StrStart;
uint8_t  StrEnd;
uint8_t  ScrollMode;
uint8_t  ScrollCount;
uint8_t  UpdateLCD;

uint16_t LCD_SegTable[] PROGMEM =
{
   0xEAA8,     // '*'
   0x2A80,     // '+'
   0x4000,     // ','
   0x0A00,     // '-'
   0x0A51,     // '.' Degree sign
   0x4008,     // '/'
   0x5559,     // '0'
   0x0118,     // '1'
   0x1e11,     // '2
   0x1b11,     // '3
   0x0b50,     // '4
   0x1b41,     // '5
   0x1f41,     // '6
   0x0111,     // '7
   0x1f51,     // '8
   0x1b51,     // '9'
   0x0000,     // ':' (Not defined)
   0x0000,     // ';' (Not defined)
   0x8008,     // '<'
   0x1A00,     // '='
   0x4020,     // '>'
   0x0000,     // '?' (Not defined)
   0x0000,     // '@' (Not defined)
   0x0f51,     // 'A' (+ 'a')
   0x3991,     // 'B' (+ 'b')
   0x1441,     // 'C' (+ 'c')
   0x3191,     // 'D' (+ 'd')
   0x1e41,     // 'E' (+ 'e')
   0x0e41,     // 'F' (+ 'f')
   0x1d41,     // 'G' (+ 'g')
   0x0f50,     // 'H' (+ 'h')
   0x2080,     // 'I' (+ 'i')
   0x1510,     // 'J' (+ 'j')
   0x8648,     // 'K' (+ 'k')
   0x1440,     // 'L' (+ 'l')
   0x0578,     // 'M' (+ 'm')
   0x8570,     // 'N' (+ 'n')
   0x1551,     // 'O' (+ 'o')
   0x0e51,     // 'P' (+ 'p')
   0x9551,     // 'Q' (+ 'q')
   0x8e51,     // 'R' (+ 'r')
   0x9021,     // 'S' (+ 's')
   0x2081,     // 'T' (+ 't')
   0x1550,     // 'U' (+ 'u')
   0x4448,     // 'V' (+ 'v')
   0xc550,     // 'W' (+ 'w')
   0xc028,     // 'X' (+ 'x')
   0x2028,     // 'Y' (+ 'y')
   0x5009,     // 'Z' (+ 'z')
   0x1441,     // '['
   0x8020,     // '\'
   0x1111,     // ']'
   0x0000,     // '^' (Not defined)
   0x1000      // '_'
};


void LCD_Init(void)
{
  LCDCCR = 0x0F;

   // Select asynchronous clock source, enable all COM pins and enable all segment pins.
   LCDCRB  = (1<<LCDCS) | (3<<LCDMUX0) | (7<<LCDPM0);

   // Set LCD prescaler to give a framerate of 32,0 Hz
   LCDFRR  = (0<<LCDPS0) | (7<<LCDCD0);    

  // Enable LCD and set low power waveform
   LCDCRA  = (1<<LCDEN) | (1<<LCDAB);

   //Enable LCD start of frame interrupt
   LCDCRA |= (1<<LCDIE);
}

void LCD_puts_f(const uint8_t *FlashData)
{
  uint8_t StrBuff[LCD_TEXTBUFFER_SIZE];

  strcpy_P(StrBuff, FlashData);
  LCD_puts(StrBuff);
}

void LCD_puts(uint8_t *Data)
{
  uint8_t LoadB;
   
  for (LoadB = 0; LoadB < 20; LoadB++)
  {
     uint8_t CByte = *(Data++);
   
     if ((CByte >= '*') && (CByte <= 'z'))
       TextBuffer[LoadB] = ((CByte == ' ')? 0xFF : (CByte - '*'));
     else if (CByte == 0x00)
       break;
     else
       TextBuffer[LoadB] = 0xFF;      
  }

  ScrollMode  = ((LoadB > 6)? TRUE : FALSE);
  ScrollCount = LCD_DELAYCOUNT_DEFAULT;

  for (uint8_t Nulls = 0; Nulls < 7; Nulls++)
     TextBuffer[LoadB++] = 0xFF;
   
  TextBuffer[LoadB] = 0x00;
  StrStart   = 0;
  StrEnd     = LoadB;    

  UpdateLCD  = TRUE;
}

void LCD_WriteChar(uint8_t Byte, uint8_t Digit)
{
  uint16_t SegData  = 0x00;
  uint8_t  *BuffPtr = (&SegBuffer[0] + (Digit >> 1));

  if (Byte != 0xFF)
    SegData = pgm_read_word(&LCD_SegTable[Byte]);    

  for (uint8_t BNib = 0; BNib < 4; BNib++)
  {
     uint8_t Mask          = 0xF0;
     uint8_t MaskedSegData = (SegData & 0x0000F);
   
     if (Digit & 0x01)
     {
        Mask = 0x0F;
        MaskedSegData <<= 4;
     }
     
     *BuffPtr = ((*BuffPtr & Mask) | MaskedSegData);

     SegData >>= 4;
     BuffPtr  += 5;
  }
}

ISR(LCD_vect)
{
  if (ScrollMode)
  {
     if (!(ScrollCount))
       UpdateLCD = TRUE;
     else
       ScrollCount--;
  }

  if (UpdateLCD)
  {
     for (uint8_t Character = 0; Character < 6; Character++)
     {
        uint8_t Byte = (StrStart + Character);

        if (Byte >= StrEnd)
          Byte = TextBuffer[Byte - StrEnd];
        else
          Byte = TextBuffer[Byte];
         
        LCD_WriteChar(Byte, Character);
     }
     
     if (StrStart++ == StrEnd)
       StrStart = 1;
     
     ScrollCount = LCD_SCROLLCOUNT_DEFAULT;
     UpdateLCD = FALSE;
  }

  for (uint8_t LCDChar = 0; LCDChar < LCD_SEGBUFFER_SIZE; LCDChar++)
    *(pLCDREG + LCDChar) = SegBuffer[LCDChar];
}



LCD_Driver.h
CODE

#ifndef LCDDRIVER_H
#define LCDDRIVER_H

// INCLUDES:
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <string.h>

// DEFINES:
#define pLCDREG ((unsigned char *)(0xEC))

#define LCD_CONTRAST_LEVEL(level) LCDCCR = (0x0F & level)
#define LCD_SCROLLCOUNT_DEFAULT   3
#define LCD_DELAYCOUNT_DEFAULT    10
#define LCD_TEXTBUFFER_SIZE       20
#define LCD_SEGBUFFER_SIZE        20

#define TRUE   1
#define FALSE 0

// PROTOTYPES:
void LCD_puts(uint8_t *Data);
void LCD_puts_f(const uint8_t *FlashData);
void LCD_Init(void);
void LCD_WriteChar(uint8_t Byte, uint8_t Digit);

#endif



Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.