AVR LCD menu routine

Lets have some practice and write simple AVR LCD menu routine. For this we need to write LCD control library. I decided not to use one from AVRLIB. LCD controlling isn't difficult just a few lines of code unless you want to make it more universal.

I want to demonstrate how LCD menu control may look. Of course this isn't the best practice as it uses pretty simple logic, but may do the job.

To make it interesting I am going to have 4 buttons: 2 for menu scrolling up and down and two for changing submenu parameters. As output I am going to use three LED diodes that will light according to parameters selected in menu. Button states are going to be read using timer0 overflow interrupts. Code is written for WinAVR compiler.

First of all construct a circuit:


I have excluded power circuit, just left main parts: LCD, LED's and buttons connected. This circuit works well with Proteus simulator as it is. Proteus circuit is attached to project archive.

My idea is to store menu strings in Flash memory without occupying MCU RAM. This way menu items are limited only by Flash memory, not by RAM.

As you can see in code menu structure is pretty simple and there is many ways to optimize. Feel free to do so. Firs of all decide how many Menu items we are going to have. According to my example there are 4 menu items:


//Menu Strings in flash

//menu 1

const uint8_t MN100[] PROGMEM="<<One Led>>\0";

//menu 2

const uint8_t MN200[] PROGMEM="<<All ON/OFF>>\0";

//menu 3

const uint8_t MN300[] PROGMEM="<<Auto scroll>>\0";

//menu 4

const uint8_t MN400[] PROGMEM="<<Blink All>>\0";


Then we have to describe submenus:


//SubMenu Strings in flash

//menu 1 submenus

const uint8_t MN101[] PROGMEM="R ON\0";

const uint8_t MN102[] PROGMEM="G ON\0";

const uint8_t MN103[] PROGMEM="B ON\0";

//Submenus of menu 2

const uint8_t MN201[] PROGMEM="All ON\0";

const uint8_t MN202[] PROGMEM="All OFF\0";

//Submenus of menu 3

const uint8_t MN301[] PROGMEM="Left\0";

const uint8_t MN302[] PROGMEM="Right\0";

//submenus of menu 4

const uint8_t MN401[] PROGMEM="Blink Fast\0";

const uint8_t MN402[] PROGMEM="Blink Slow\0";


Then we have to create array pointers to menu strings stored in flash:


const uint8_t *MENU[] ={

MN100, //menu 1 string

MN200, //menu 2 string

MN300, //menu 3 string

MN400 //menu 4 string

//add more if more menu items are used


const uint8_t *SUBMENU[] ={

MN101, MN102, MN103, //submenus of menu 1

MN201, MN202, //submenus of menu 2

MN301, MN302, //submenus of menu 3

MN401, MN402 //submenus of menu 4

//continue with other menu submenu strings



These pointers are used to call proper menu string when menu/submenu item is changed. There could be different logic used, but this time I've chosen this one :)

Then wee need to describe menu structure with number constants indicating how many menus and submenu items there are:


const uint8_t MSTR2[] PROGMEM ={

4, //number of menu items

3, //Number of submenu items of menu item 1

2, //of menu item 2

2, //of menu item 3

2 //of menu item 4

//enter further submenu items



This array is stored in Flash memory.

Last thing is functions. I used pointer to function. As functions are similar:


//Functions for each menu item

void func101(void);

void func102(void);

void func103(void);

void func201(void);

void func202(void);

void func301(void);

void func302(void);

void func401(void);

void func402(void);

//...add more functions if more menu items are used


It is ease to use function pointer, that can be changed during menu item change. To make things easier to manage I have created Array of function pointers in Flash


const FuncPtr FuncPtrTable[] PROGMEM=

{ func101, func102, func103, //functions for submenus of menu 1

func201, func202, //functions for submenus of menu 2

func301, func302, //functions for submenus of menu 3

func401, func402 //functions for submenus of menu 4

//further functions...



Using this function array I can easily point to required function with single code line:


FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.menuNo, MN.subMenuNo)]);


Where MFIndex(MN.menuNo, MN.subMenuNo) function returns array index according to menu and submenu number.




Dear Administrator,I have directly used your given code for ATmega16. First modified ISR required for 1MHz, then as is used for 1 MHz in both cased the sequence does not follow the menu design but performs its own sequence. Is it possible to guide what else we have to take care of.avr_1950

Did you try to run this code with simulator? I should recheck this code - as it may have some glitches.

Dear Administrator,Thanks for your prompt reply. No, I do not have a simulator. Also as a timer is involved, most simulators have problem with timers involved. Please may I humbly request if you could indicate where some tweaking may be required to make the program run properly. Many thanks in advance

I have updated LCD library and recompiled program. Seems to be running ok on Proteus simulator for mega8. It should also work on ATmega16 if ported correctly. If not I will try to recompile and run for mega16 on simulator.

hi, great examples thank you,I want to use this software on atmega 168, is simulating fine in vmlab for the atmega 8, I changed the software so theTCC and TIMSK dont give errors,TCCR0B|=(1