/* ** LCD Routines with bargraph display, heavily modified from Pascal Stang's avrlib ** Original LCD routines heavily modified from examples posted on Pololu user forum ** sjames_remington /at/ yahoo.com */ //#define F_CPU 8000000UL #include #include #include /* custom characters for bargraph display The original code had rails on the top and bottom of the bar use the following for "no rails" display, bar is 6 pixels high with spacers top and bottom */ unsigned char __attribute__ ((progmem)) LcdCustomChar[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0. 0/5 full progress block 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, // 1. 1/5 full progress block 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, // 2. 2/5 full progress block 0x00, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x00, // 3. 3/5 full progress block 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, // 4. 4/5 full progress block 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00 // 5. 5/5 full progress block }; /* The required delays included here are generously in accord with the LCD data sheet, and should be independent of the clock speed as long as F_CPU is set correctly (>= 1 MHz) Jim Remington, sjames_remington at yahoo dot com */ //Function prototypes void LCDInit(void); void LCDSendData(unsigned char); void LCDSendCommand(unsigned char command); void LCDPrintString(const unsigned char *string); void LCDGotoXY(unsigned char x,unsigned char y); void LCDBar(unsigned int value, unsigned int maxval, unsigned char charlen); void LCDLoadCustomChar(unsigned char* lcdCustomCharArray, unsigned char romCharNum, unsigned char lcdCharNum); // useful defines (LCD commands) #define LCD_Clear 0x01 #define LCD_Line1 0x80 #define LCD_Line2 0xC0 #define LCD_CGRAM 6 // set CG RAM address #define LCD_DDRAM 7 // set DD RAM address /* Send lower 4 bits of data byte to display */ void LCDSendNibble( unsigned char data ) { data &= 0x0F; //lower 4 bits of data data <<= 3; PORTB &= ~0x38; //clear LCD bus bits 456 PORTB |= (data & 0x38); //or in data data <<= 1; PORTD &= ~0x80; //same for top bit on PORTD.7 PORTD |= (data & 0x80); _delay_us(1); PORTD |= (1<<4); //E = 1 _delay_us(2); //required minimum 1 us delay PORTD &= ~(1<<4); //E = 0 _delay_us(1); } /* Send a character to the LCD display */ void LCDSendData( unsigned char data ) { PORTD &= ~(1<<3); //R/W =0 PORTD |= (1<<2); //RS = 1; LCDSendNibble( data >> 4 ); LCDSendNibble( data ); _delay_us(100); //38 us typically needed to complete this action } /* Send a command to display. Required delay time depends on the command and the LCD controller clock frequency -- here assumed to be the minimum 190 kHz */ void LCDSendCommand( unsigned char command ) { PORTD &= ~(3<<2); // R/W=0, RS = 0; LCDSendNibble(command>> 4 ); LCDSendNibble(command); _delay_ms(3); //maximum required is 2.1 ms for "clear display" } // print a string constant void LCDPrintString( const unsigned char *str ) { while (*str != 0) LCDSendData( *str++ ); } // set print position to (x,y) where y=line number (0 or 1), x = character position 0, 1, etc. void LCDGotoXY(unsigned char x, unsigned char y) { volatile unsigned char ddram_addr; ddram_addr=0x80; //initialize data ram address to 0 (default) if (y==1) ddram_addr=0xC0; //start print at line 2, DDRAM address 0x40 LCDSendCommand(ddram_addr+ (x&0x7F) ); } /* Initialize the LCD Display, timing requirements taken from datasheet Set PORTB.3,4,5 to DB 4,5,6 Set PORTD.2,3,4,7 to RS, R/W, E and DB7 Send required start-up sequence to set 4 bit interface, 2 lines, 5x8 characters and clear display */ void LCDInit( void ) { DDRB |= (7<<3); DDRD |= (1<<7) | (7<<2); PORTD &= ~(7<<2); // E=0,R/W=0, RS = 0; _delay_ms(20); //required startup sequence from power-on (see datasheet) LCDSendNibble(0x03); //set interface=8 bits _delay_ms(10); //wait at least 5 ms LCDSendNibble(0x03); //set interface=8 bits _delay_ms(1); //wait at least 100 us LCDSendNibble(0x03); //set interface=8 bits _delay_ms(1); //wait at least 100 us LCDSendNibble(0x02); //set interface=4 bits _delay_ms(1); //delays after this are built into SendCommand LCDSendCommand(0x28); //set interface=4 bits, 2 lines, 5x8 characters LCDSendCommand(0x08); //display off, cursor off, blink off LCDSendCommand(0x01); //clear display LCDSendCommand(0x06); //entry mode set, cursor shifts right after character rcvd. LCDSendCommand(0x0D); //0b01DCB D=1:Display on, C=1:cursor on, B=1:Blink on // load 6 custom characters for bargraph display LCDLoadCustomChar((unsigned char*)LcdCustomChar,0,0); LCDLoadCustomChar((unsigned char*)LcdCustomChar,1,1); LCDLoadCustomChar((unsigned char*)LcdCustomChar,2,2); LCDLoadCustomChar((unsigned char*)LcdCustomChar,3,3); LCDLoadCustomChar((unsigned char*)LcdCustomChar,4,4); LCDLoadCustomChar((unsigned char*)LcdCustomChar,5,5); // the above commands move cursor due to autoinc. So clear display again: LCDSendCommand( LCD_Clear ); } void LCDLoadCustomChar(unsigned char* lcdCustomCharArray, unsigned char romCharNum, unsigned char lcdCharNum) { register unsigned char i; // multiply the character index by 8 lcdCharNum = (lcdCharNum<<3); // each character occupies 8 bytes romCharNum = (romCharNum<<3); // each character occupies 8 bytes // copy the 8 bytes into CG (character generator) RAM for(i=0; i<8; i++) { // set CG RAM address LCDSendCommand((1< pixelprogress ) { // this is a partial or empty block if( ((i*(int)PROGRESSPIXELS_PER_CHAR)) > pixelprogress ) { // this is an empty block c = 0; } else { // this is a partial block c = pixelprogress % PROGRESSPIXELS_PER_CHAR; } } else { // this is a full block c = 5; } // write character to display LCDSendData(c); } }