My Basket:

Your basket is currently empty.

Click to view the full basket.
cosmetic navigation top arrowview the basket
cosmetic side spacer

AVR LCD Code for STK200 and STK300 in WinAVR C

This LCD code for AVR will work on STK200 and STK300 AVR boards with standard (Hitachi driver) LCD. This code is written for a 16 x 2 character LCD, but can easily be modified for other formats.

Have a look at our BLOG for more microcontroller information


AVR ISP programmer for AVR UART C Code
Now at new reduced price

avrisp more details button

AVR Studio
Create a C project in AVRStudio and make sure the AVR device is the one you want to use. WinAVR C is very fussy about the correct device and although the code will compile, it will not run properly unless the AVR microcontroller type is correct
To change AVR microcontroller, go to Project > Configuration Options and select correct AVR.
Note that only the C Compiler project changes, not main project device type. Also change Optimization to -0s otherwise compiler has problems with delay routines

/* Program to drive LCD on STK200 board normally for Hitachi type 
16 x 2 LCD, but will work on other LCD sizes.  For STK300, RD and 
WR need to be on PORTG - see schematic. 
This program uses Busy Flag on LCD (PORTA.7) instead of delays 
between each instruction.  The current LCD address is read at same 
time but not used in this program. 
Change to correct device in Project - Configuration Options */

//change to match target clock 
//Note: default AVR CLKSEL is 1MHz internal RC
#define F_CPU 8000000UL  

#include <avr/io.h>
#include <util/delay.h>

// used pins on port C and D
#define LCD_E  7    // PORTC.7
#define LCD_RS 6    //PORTC.6
#define LCD_RD 7    // PORTD.7
#define LCD_WR 6    // PORTD.6
// Data and Busy flag are on PORTA
//LCD commands
#define LCD_CLR 0x01  // clear LCD
#define LCD_8BIT 0x38 // 8-bit mode
#define LCD_INC 0x06  //Increment, display freeze
#define LCD_MOV 0x10  //Cursor move, not shift
#define LCD_ALL  0x0F // LCD On, LCD display on, cursor on and blink on
#define LCD_ON           0x08      // turn lcd/cursor on             
#define LCD_ON_DISPLAY   0x04      // turn display on              
#define LCD_ON_CURSOR    0x02      // turn cursor on               
#define LCD_ON_BLINK     0x01      // cursor blink
#define LCD_LINE1  0x80        // cursor Pos on line 1 (or with column)
#define LCD_LINE2  0xC0        // cursor Pos on line 2 (or with column)

//LCD_getaddress reads the address counter and busy flag. For the address only,
//mask off bit7 of the return value.

unsigned char LCD_getaddr(void)
	unsigned char address;	
        PORTC &= ~((1<<LCD_RS)|(1<<LCD_E));  
				//RS low for busy flag read and enable low	
        //RD pin low (for enable circuit)
	PORTD &= ~(1<<LCD_RD);
        // WR connected to read/write pin - high for read
	PORTD |= (1<<LCD_WR);
	//PortA is input
	DDRA = 0;
        PORTC |= (1<<LCD_E);  // enable high
        // short delay
	asm volatile ("nop");  
	asm volatile ("nop");

	//while E is high, get data from LCD
	address = PINA;
	PORTC &= ~(1<<LCD_E);   // E low (for strobe)
	// restore other settings
	PORTD |= (1<<LCD_RD);   // RD pin high (for enable circuit)
	PORTD &= ~(1<<LCD_WR);   // WR read/write goes low for write  
	DDRA = 0xFF; //back to output
	//return address and busy flag
	return address;

//LCD_wait reads the address counter (which contains the busy flag) and loops until
//the busy flag is cleared.

void LCD_wait(void){
	//get address and busy flag
	//and loop until busy flag (bit7) cleared

	while((LCD_getaddr() & 0x80) == 0x80)

/*LCD_putchar writes a character to the LCD at the current address,
usage: LCD_putchar('A'); or LCD_putchar(0x55); */

void LCD_putchar(unsigned char data){
	LCD_wait();  // is it busy?
	//PortA is output
	DDRA = 0xFF;

	//RS high for data and Enable high
	PORTC |= ((1<<LCD_RS)|(1<<LCD_E));
		//put data on bus
	PORTA = data;
	/*the number of nops required varies with your clock frequency, 
	Can be altered */
	asm volatile ("nop");
	asm volatile ("nop");
	asm volatile ("nop");
	asm volatile ("nop");
	// Enable low again
	PORTC &= ~(1<<LCD_E);
	//release port
	DDRA = 0;
/*LCD_command works EXACTLY like LCD_putchar, but takes RS low for 
accessing the command reg */

void LCD_command(unsigned char command){
	LCD_wait();  // is it still busy?
	DDRA = 0xFF;  // data port as output
	PORTC &= ~(1<<LCD_RS);  //RS low for Command
	PORTC |= (1<<LCD_E);    //Enable pin high
	PORTA = command;         // put data on Port
	asm volatile ("nop");
	asm volatile ("nop");
	asm volatile ("nop");
	asm volatile ("nop");    
	PORTC &= ~(1<<LCD_E);   //Enable Pin Low
	DDRA = 0;                // release bus

/*LCD_init initialises the LCD with the following paramters:
8 bit mode, 5*7 font, 2 lines (also for 4 lines)
auto-inc cursor after write and read
cursor and display on, cursor blinking.*/

void LCD_init(void){
	//setup the LCD control signals on PortC  (RS and Enable as output)
	DDRC |= ((1<<LCD_RS)|(1<<LCD_E));
	PORTC &= ~((1<<LCD_RS)|(1<<LCD_E));// set both low
	//setup the LCD control signals on PortD
  DDRD |= ((1<<LCD_RD)|(1<<LCD_WR));// read and write pins (STK300 on PortG)
	PORTD &= ~(1<<LCD_WR); // write pin low
	// data Port A as output
	DDRA = 0xFF;
	/*if called right after power-up, we'll have to wait a bit (fine-tune 
	for faster execution) */
        LCD_command(LCD_CLR);       // clear display
	LCD_command(LCD_8BIT);      // set 8 data bits  
	LCD_command(LCD_INC);       // cursor increments automatically 
	LCD_command(LCD_MOV);       // cursor  set to move
	//LCD_command(LCD_ALL);     // can call all instead of next line
        LCD_command(LCD_LINE1); // set cursor to  row 1, position 0

// function for showing strings on the LCD. It uses the low-level
//functions above. usage example: LCD_write("Hello World!");

void LCD_write(char* dstring){

	//is the character pointed at by dstring a zero? If not, write character to LCD
	// write the character from dstring to the LCD, then post-inc the string pointer.

int main( void )
  LCD_write("Hello World");
  LCD_command(LCD_LINE2 | 5); // move cursor  to row 2, position 5 
  LCD_write("is here");
/*Note: As LCD has a RAM memory, it will display what was written 
until its power is removed hence no loop needed */

If you found this information useful, please give us a mention

STK200 picture

STK200 AVR Training Kit
STK300 picture

STK300 AVR Training Kit (ATmega128)

return to support