├── m328p_example.m4v ├── m328p_example.png ├── m328p_example ├── Readme.md ├── digital.h ├── serial_lib │ ├── xitoa.h │ └── xitoa.S ├── pcd8544.h ├── Makefile ├── main.c └── pcd8544.c ├── README.md ├── lcdMenu.h └── lcdMenu.c /m328p_example.m4v: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kehribar/lcdMenu/HEAD/m328p_example.m4v -------------------------------------------------------------------------------- /m328p_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kehribar/lcdMenu/HEAD/m328p_example.png -------------------------------------------------------------------------------- /m328p_example/Readme.md: -------------------------------------------------------------------------------- 1 | ![image](../m328p_example.png) 2 | 3 | #m328p_example 4 | 5 | This example is written to demonstrate the lcdMenu library. PCD8544 based GLCD is used as a LCD in this example. Code works perfectly on an Arduino board. But be careful with the voltage level shifting. PCD8544 requires 3v3 supply and control signals. 6 | 7 | ##Wiring 8 | 9 | ###Buttons 10 | 11 | Select button -> PC0 -> Analog 0 12 | Up button -> PC1 -> Analog 1 13 | Back button -> PC2 -> Analog 2 14 | Down button -> PC3 -> Analog 3 15 | 16 | **Note:** Atmega328p's internal pullups are used for the buttons. 17 | 18 | ##PCD8544 LCD 19 | 20 | GND -> GND 21 | VCC -> 3v3 22 | CE -> GND 23 | RST -> PB0 -> Digital 8 24 | DC -> PB1 -> Digital 9 25 | DIN -> PB2 -> Digital 10 26 | CLK -> PB3 -> Digital 11 27 | 28 | ##Memory Usage 29 | 30 | AVR Memory Usage 31 | ---------------- 32 | Device: atmega328p 33 | 34 | Program: 2678 bytes (8.2% Full) 35 | (.text + .data + .bootloader) 36 | 37 | Data: 225 bytes (11.0% Full) 38 | (.data + .bss + .noinit) 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![image](./m328p_example.png) 2 | 3 | #lcdMenu - v0.1 4 | 5 | Portable text based lcd menu library written in C. You can see the library in action in this [video](https://github.com/kehribar/lcdMenu/blob/master/m328p_example.m4v?raw=true). 6 | 7 | ##Porting 8 | 9 | You have to submit 4 functions to this library. 10 | 11 | #####`void lcdMenu_goNextLine();` 12 | Moves the text cursor of the LCD to begining of the next line. 13 | 14 | #####`void lcdMenu_clearScreen();` 15 | Clears the screen and moves the cursor to the (0,0) location of the LCD. 16 | 17 | #####`void lcdMenu_printNormal(const char* message);` 18 | Prints a line of text to LCD's current line. 19 | 20 | #####`void lcdMenu_printSpecial(const char* message);` 21 | Prints a line of text to LCD's current line with a special format. For example, text color could be inverted or a prefix like `> ` can be added to the text. 22 | 23 | ##Usage 24 | 25 | After you assign your platform spesific functions to the lcdMenu library, you should also add some kind of button - action mechanism on your main code as well. 26 | 27 | Moreover, you should also define your menu and item elements and their structural relationship on your code. 28 | 29 | `m328p_example` can be used as a reference. 30 | 31 | ##TODO 32 | 33 | The library currently uses standard SRAM based variable definitions for menu informations. This can be a bit problematic in small RAM based devices. In order to solve this problem, I'll be creating an AVR spesific PROGMEM based version of this library when I needed. 34 | -------------------------------------------------------------------------------- /lcdMenu.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------- 2 | / “THE COFFEEWARE LICENSE” (Revision 1): 3 | / wrote this file. As long as you retain this notice you 4 | / can do whatever you want with this stuff. If we meet some day, and you think 5 | / this stuff is worth it, you can buy me a coffee in return. 6 | /----------------------------------------------------------------------------*/ 7 | #include 8 | #include 9 | /*---------------------------------------------------------------------------*/ 10 | #define lcdMenu_callFunction(fp) ((*fp)()) 11 | /*---------------------------------------------------------------------------*/ 12 | typedef struct menustate 13 | { 14 | uint8_t top; 15 | uint8_t MAX_ROWS; 16 | uint8_t last_top; 17 | uint8_t currentItem; 18 | uint8_t last_currentItem; 19 | struct menu* currentMenu; 20 | }; 21 | /*---------------------------------------------------------------------------*/ 22 | typedef struct menuitem 23 | { 24 | const char* name; 25 | void (*handlerFunc)(); 26 | struct menu* child; 27 | }; 28 | /*---------------------------------------------------------------------------*/ 29 | typedef struct menu 30 | { 31 | uint8_t length; 32 | struct menu* parent; 33 | struct menuitem** menuArray; 34 | }; 35 | /*---------------------------------------------------------------------------*/ 36 | void lcdMenu_goUp(struct menustate* ms); 37 | /*---------------------------------------------------------------------------*/ 38 | void lcdMenu_goBack(struct menustate* ms); 39 | /*---------------------------------------------------------------------------*/ 40 | void lcdMenu_select(struct menustate* ms); 41 | /*---------------------------------------------------------------------------*/ 42 | void lcdMenu_goDown(struct menustate* ms); 43 | /*---------------------------------------------------------------------------*/ 44 | void lcdMenu_drawMenu(struct menustate* ms); 45 | /*---------------------------------------------------------------------------*/ 46 | extern void lcdMenu_goNextLine(); 47 | /*---------------------------------------------------------------------------*/ 48 | extern void lcdMenu_clearScreen(); 49 | /*---------------------------------------------------------------------------*/ 50 | extern void lcdMenu_printNormal(const char* message); 51 | /*---------------------------------------------------------------------------*/ 52 | extern void lcdMenu_printSpecial(const char* message); 53 | /*---------------------------------------------------------------------------*/ 54 | -------------------------------------------------------------------------------- /lcdMenu.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------- 2 | / “THE COFFEEWARE LICENSE” (Revision 1): 3 | / wrote this file. As long as you retain this notice you 4 | / can do whatever you want with this stuff. If we meet some day, and you think 5 | / this stuff is worth it, you can buy me a coffee in return. 6 | /----------------------------------------------------------------------------*/ 7 | #include "lcdMenu.h" 8 | /*---------------------------------------------------------------------------*/ 9 | void lcdMenu_goBack(struct menustate* ms) 10 | { 11 | if(ms->currentMenu->parent != NULL) 12 | { 13 | ms->currentMenu = ms->currentMenu->parent; 14 | ms->top = ms->last_top; 15 | ms->currentItem = ms->last_currentItem; 16 | } 17 | } 18 | /*---------------------------------------------------------------------------*/ 19 | void lcdMenu_select(struct menustate* ms) 20 | { 21 | if(ms->currentMenu->menuArray[ms->currentItem]->child != NULL) 22 | { 23 | ms->currentMenu = ms->currentMenu->menuArray[ms->currentItem]->child; 24 | ms->last_top = ms->top; 25 | ms->last_currentItem = ms->currentItem; 26 | ms->top = 0; 27 | ms->currentItem = 0; 28 | } 29 | else if(ms->currentMenu->menuArray[ms->currentItem]->handlerFunc != NULL) 30 | { 31 | lcdMenu_callFunction(ms->currentMenu->menuArray[ms->currentItem]->handlerFunc); 32 | } 33 | } 34 | /*---------------------------------------------------------------------------*/ 35 | void lcdMenu_goDown(struct menustate* ms) 36 | { 37 | if(ms->top != ms->currentMenu->length) 38 | { 39 | if(ms->currentItem != (ms->currentMenu->length-1)) 40 | { 41 | ms->currentItem += 1; 42 | if(((ms->currentItem)-(ms->top))==ms->MAX_ROWS) 43 | { 44 | ms->top += 1; 45 | } 46 | } 47 | } 48 | } 49 | /*---------------------------------------------------------------------------*/ 50 | void lcdMenu_goUp(struct menustate* ms) 51 | { 52 | if(!((ms->top==0)&(ms->currentItem==0))) 53 | { 54 | ms->currentItem = ms->currentItem - 1; 55 | if((ms->top > ms->currentItem)) 56 | { 57 | ms->top = ms->top -1; 58 | } 59 | } 60 | } 61 | /*---------------------------------------------------------------------------*/ 62 | void lcdMenu_drawMenu(struct menustate* ms) 63 | { 64 | uint8_t i; 65 | 66 | lcdMenu_clearScreen(); 67 | 68 | for (i = ms->top; i < ms->top+ms->MAX_ROWS; ++i) 69 | { 70 | if(icurrentMenu->length) 71 | { 72 | if (ms->currentItem==i) 73 | { 74 | lcdMenu_printSpecial(ms->currentMenu->menuArray[i]->name); 75 | lcdMenu_goNextLine(); 76 | } 77 | else 78 | { 79 | lcdMenu_printNormal(ms->currentMenu->menuArray[i]->name); 80 | lcdMenu_goNextLine(); 81 | } 82 | } 83 | else 84 | { 85 | lcdMenu_goNextLine(); 86 | } 87 | } 88 | } 89 | /*---------------------------------------------------------------------------*/ -------------------------------------------------------------------------------- /m328p_example/digital.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * “THE COFFEEWARE LICENSE” (Revision 1): 4 | * wrote this file. As long as you retain this notice you 5 | * can do whatever you want with this stuff. If we meet some day, and you think 6 | * this stuff is worth it, you can buy me a coffee in return. 7 | * ----------------------------------------------------------------------------- 8 | */ 9 | 10 | #ifndef DIGITAL 11 | #define DIGITAL 12 | 13 | #include 14 | 15 | /****************************************************************************** 16 | / Useful symbolic definitions. 17 | /*****************************************************************************/ 18 | #define HIGH 1 19 | #define LOW 0 20 | #define OUTPUT 1 21 | #define INPUT 0 22 | #define ENABLE 1 23 | #define DISABLE 0 24 | 25 | /****************************************************************************** 26 | / Definition: Writes high/low to a digital output pin. 27 | / Example: 28 | / 29 | / digitalWrite(A,6,LOW); 30 | / digitalWrite(A,7,HIGH); 31 | /*****************************************************************************/ 32 | #define digitalWrite(port,pin,state) state ? (PORT ## port |= (1< 10 | #include 11 | 12 | extern void (*xfunc_out)(uint8_t); 13 | 14 | /* This is a pointer to user defined output function. It must be initialized 15 | before using this modle. 16 | */ 17 | 18 | void xputc(char chr); 19 | 20 | /* This is a stub function to forward outputs to user defined output function. 21 | All outputs from this module are output via this function. 22 | */ 23 | 24 | 25 | /*-----------------------------------------------------------------------------*/ 26 | void xputs(const prog_char *string); 27 | 28 | /* The string placed in the ROM is forwarded to xputc() directly. 29 | */ 30 | 31 | 32 | /*-----------------------------------------------------------------------------*/ 33 | void xitoa(long value, char radix, char width); 34 | 35 | /* Extended itoa(). 36 | 37 | value radix width output 38 | 100 10 6 " 100" 39 | 100 10 -6 "000100" 40 | 100 10 0 "100" 41 | 4294967295 10 0 "4294967295" 42 | 4294967295 -10 0 "-1" 43 | 655360 16 -8 "000A0000" 44 | 1024 16 0 "400" 45 | 0x55 2 -8 "01010101" 46 | */ 47 | 48 | 49 | /*-----------------------------------------------------------------------------*/ 50 | void xprintf(const prog_char *format, ...); 51 | 52 | /* Format string is placed in the ROM. The format flags is similar to printf(). 53 | 54 | %[flag][width][size]type 55 | 56 | flag 57 | A '0' means filled with '0' when output is shorter than width. 58 | ' ' is used in default. This is effective only numeral type. 59 | width 60 | Minimum width in decimal number. This is effective only numeral type. 61 | Default width is zero. 62 | size 63 | A 'l' means the argument is long(32bit). Default is short(16bit). 64 | This is effective only numeral type. 65 | type 66 | 'c' : Character, argument is the value 67 | 's' : String placed on the RAM, argument is the pointer 68 | 'S' : String placed on the ROM, argument is the pointer 69 | 'd' : Signed decimal, argument is the value 70 | 'u' : Unsigned decimal, argument is the value 71 | 'X' : Hex decimal, argument is the value 72 | 'b' : Binary, argument is the value 73 | '%' : '%' 74 | 75 | */ 76 | 77 | 78 | /*-----------------------------------------------------------------------------*/ 79 | char xatoi(char **str, long *ret); 80 | 81 | /* Get value of the numeral string. 82 | 83 | str 84 | Pointer to pointer to source string 85 | 86 | "0b11001010" binary 87 | "0377" octal 88 | "0xff800" hexdecimal 89 | "1250000" decimal 90 | "-25000" decimal 91 | 92 | ret 93 | Pointer to return value 94 | */ 95 | 96 | #endif /* XITOA */ 97 | 98 | -------------------------------------------------------------------------------- /m328p_example/pcd8544.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | / Pure C based pcd8544 library. 3 | /------------------------------------------------------------------------------ 4 | / This library is derived from C++ based Arduino/Maple library for pcd8544 5 | / lcd controller. https://github.com/snigelen/pcd8544 6 | /----------------------------------------------------------------------------*/ 7 | #include 8 | #include 9 | #include 10 | #include "digital.h" 11 | #include 12 | /*---------------------------------------------------------------------------*/ 13 | #define PCD8544_FUNCTION_SET (1<<5) 14 | #define PCD8544_FUNCTION_PD (1<<2) 15 | #define PCD8544_FUNCTION_V (1<<1) 16 | #define PCD8544_FUNCTION_H (1<<0) 17 | /*---------------------------------------------------------------------------*/ 18 | #define PCD8544_DISPLAY_CONTROL (1<<3) 19 | #define PCD8544_DISPLAY_CONTROL_D (1<<2) 20 | #define PCD8544_DISPLAY_CONTROL_E (1<<0) 21 | #define PCD8544_DISPLAY_CONTROL_BLANK 0 22 | #define PCD8544_DISPLAY_CONTROL_NORMAL_MODE PCD8544_DISPLAY_CONTROL_D 23 | #define PCD8544_DISPLAY_CONTROL_ALL_ON PCD8544_DISPLAY_CONTROL_E 24 | #define PCD8544_DISPLAY_CONTROL_INVERSE (PCD8544_DISPLAY_CONTROL_D|PCD8544_DISPLAY_CONTROL_E) 25 | /*---------------------------------------------------------------------------*/ 26 | #define PCD8544_SET_Y_ADDRESS (1<<6) 27 | #define PCD8544_Y_ADRESS_MASK 0b111 28 | #define PCD8544_SET_X_ADDRESS (1<<7) 29 | #define PCD8544_X_ADRESS_MASK 0b01111111 30 | /*---------------------------------------------------------------------------*/ 31 | #define PCD8544_TEMP_CONTROL (1<<2) 32 | #define PCD8544_TEMP_TC1 (1<<1) 33 | #define PCD8544_TEMP_TC0 (1<<0) 34 | /*---------------------------------------------------------------------------*/ 35 | #define PCD8544_BIAS (1<<4) 36 | #define PCD8544_BIAS_BS2 (1<<2) 37 | #define PCD8544_BIAS_BS1 (1<<1) 38 | #define PCD8544_BIAS_BS0 (1<<0) 39 | /*---------------------------------------------------------------------------*/ 40 | #define PCD8544_VOP (1<<7) 41 | /*---------------------------------------------------------------------------*/ 42 | #define PCD8544_LINES 6 43 | #define PCD8544_COLS 14 44 | #define PCD8544_WIDTH 84 45 | #define PCD8544_HEIGHT 48 46 | /*---------------------------------------------------------------------------*/ 47 | uint8_t current_row, current_column; 48 | /*---------------------------------------------------------------------------*/ 49 | void pcd8544_begin(uint8_t contrast); 50 | /*---------------------------------------------------------------------------*/ 51 | void pcd8544_clear(void); 52 | /*---------------------------------------------------------------------------*/ 53 | void pcd8544_setCursor(uint8_t column, uint8_t row); 54 | /*---------------------------------------------------------------------------*/ 55 | void pcd8544_gotoRc(uint8_t row, uint8_t pixel_column); 56 | /*---------------------------------------------------------------------------*/ 57 | void pcd8544_data(uint8_t data); 58 | /*---------------------------------------------------------------------------*/ 59 | void pcd8544_smallNum(uint8_t num, uint8_t shift); 60 | /*---------------------------------------------------------------------------*/ 61 | void pcd8544_clearRestOfLine(void); 62 | /*---------------------------------------------------------------------------*/ 63 | void pcd8544_bitmap(uint8_t *data, uint8_t rows, uint8_t columns); 64 | /*---------------------------------------------------------------------------*/ 65 | void pcd8544_send(uint8_t dc, uint8_t data); 66 | /*---------------------------------------------------------------------------*/ 67 | void pcd8544_command(uint8_t data); 68 | /*---------------------------------------------------------------------------*/ 69 | void pcd8544_write(uint8_t ch); 70 | /*---------------------------------------------------------------------------*/ 71 | void pcd8544_inc_row_column(void); 72 | /*---------------------------------------------------------------------------*/ 73 | void pcd8544_print(const char* message); 74 | /*---------------------------------------------------------------------------*/ 75 | -------------------------------------------------------------------------------- /m328p_example/Makefile: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # Example makefile 4 | # 5 | ############################################################################### 6 | 7 | ### Project name (also used for output file name) 8 | PROJECT = main 9 | 10 | ### Source files and search directory 11 | CSRC = main.c pcd8544.c ../lcdMenu.c 12 | ASRC = xitoa.S 13 | VPATH = ./serial_lib 14 | DEVICE = atmega328p 15 | F_OSC = 16000000 16 | PORT = /dev/tty.usbserial-A900cbrd 17 | AVRDUDE = avrdude -c arduino -P $(PORT) -p ${DEVICE} -U flash:w:$(PROJECT).hex 18 | RESET = avrdude -c arduino -P $(PORT) -p ${DEVICE} 19 | CONSOLE = screen $(PORT) 19200 20 | 21 | ############################################################################### 22 | # 23 | # Don't change anything below 24 | # 25 | ############################################################################### 26 | 27 | ### Include dirs, library dirs and definitions 28 | LIBS = 29 | LIBDIRS = 30 | INCDIRS = 31 | DEFS = F_CPU=$(F_OSC) 32 | ADEFS = F_CPU=$(F_OSC) 33 | 34 | ### Optimization level (0, 1, 2, 3, 4 or s) 35 | OPTIMIZE = s 36 | 37 | ### C Standard level (c89, gnu89, c99 or gnu99) 38 | CSTD = gnu99 39 | 40 | ### Warning contorls 41 | WARNINGS = all extra 42 | 43 | ### Output directory 44 | OBJDIR = obj 45 | 46 | ### Output file format (ihex, bin or both) and debugger type 47 | OUTPUT = ihex 48 | DEBUG = # dwarf-2 49 | 50 | ### Programs to build porject 51 | CC = avr-gcc 52 | OBJCOPY = avr-objcopy 53 | OBJDUMP = avr-objdump 54 | SIZE = avr-size 55 | NM = avr-nm 56 | 57 | # Define all object files 58 | COBJ = $(CSRC:.c=.o) 59 | AOBJ = $(ASRC:.S=.o) 60 | COBJ := $(addprefix $(OBJDIR)/,$(COBJ)) 61 | AOBJ := $(addprefix $(OBJDIR)/,$(AOBJ)) 62 | PROJECT := $(OBJDIR)/$(PROJECT) 63 | 64 | # Flags for C files 65 | CFLAGS += -Wno-deprecated-declarations -D__PROG_TYPES_COMPAT__ 66 | CFLAGS += -fdata-sections -ffunction-sections 67 | CFLAGS += -Wl,--gc-sections 68 | CFLAGS += -std=$(CSTD) 69 | CFLAGS += -g$(DEBUG) 70 | CFLAGS += -mmcu=$(DEVICE) 71 | CFLAGS += -O$(OPTIMIZE) -mcall-prologues 72 | CFLAGS += $(addprefix -W,$(WARNINGS)) 73 | CFLAGS += $(addprefix -I,$(INCDIRS)) 74 | CFLAGS += $(addprefix -D,$(DEFS)) 75 | CFLAGS += -Wp,-M,-MP,-MT,$(OBJDIR)/$(*F).o,-MF,$(OBJDIR)/$(*F).d 76 | 77 | # Assembler flags 78 | ASFLAGS += $(addprefix -D,$(ADEFS)) -Wa,-gstabs,-g$(DEBUG) 79 | ALL_ASFLAGS = -mmcu=$(DEVICE) -I. -x assembler-with-cpp $(ASFLAGS) -fdata-sections -ffunction-sections 80 | 81 | # Linker flags 82 | LDFLAGS += -Wl,-lm -Wl,--gc-sections,-Map,$(PROJECT).map 83 | 84 | # Default target. 85 | all: version build size 86 | 87 | ifeq ($(OUTPUT),ihex) 88 | build: elf hex lst sym 89 | hex: $(PROJECT).hex 90 | else 91 | ifeq ($(OUTPUT),binary) 92 | build: elf bin lst sym 93 | bin: $(PROJECT).bin 94 | else 95 | ifeq ($(OUTPUT),both) 96 | build: elf hex bin lst sym 97 | hex: $(PROJECT).hex 98 | bin: $(PROJECT).bin 99 | else 100 | $(error "Invalid format: $(OUTPUT)") 101 | endif 102 | endif 103 | endif 104 | 105 | elf: $(PROJECT).elf 106 | lst: $(PROJECT).lst 107 | sym: $(PROJECT).sym 108 | 109 | 110 | # Display compiler version information. 111 | version : 112 | @$(CC) --version 113 | 114 | # Create final output file (.hex or .bin) from ELF output file. 115 | %.hex: %.elf 116 | @echo 117 | $(OBJCOPY) -O ihex $< $@ 118 | 119 | %.bin: %.elf 120 | @echo 121 | $(OBJCOPY) -O binary $< $@ 122 | 123 | # Create extended listing file from ELF output file. 124 | %.lst: %.elf 125 | @echo 126 | $(OBJDUMP) -h -S -C $< > $@ 127 | 128 | # Create a symbol table from ELF output file. 129 | %.sym: %.elf 130 | @echo 131 | $(NM) -n $< > $@ 132 | 133 | # Display size of file. 134 | size: 135 | @echo 136 | $(SIZE) -C --mcu=$(DEVICE) $(PROJECT).elf 137 | 138 | # Link: create ELF output file from object files. 139 | %.elf: $(AOBJ) $(COBJ) 140 | @echo 141 | @echo Linking... 142 | $(CC) $(CFLAGS) $(AOBJ) $(COBJ) --output $@ 143 | 144 | # Compile: create object files from C source files. ARM or Thumb(-2) 145 | $(COBJ) : $(OBJDIR)/%.o : %.c 146 | @echo 147 | @echo $< : 148 | $(CC) -c $(CFLAGS) $< -o $@ 149 | 150 | # Assemble: create object files from assembler source files. ARM or Thumb(-2) 151 | $(AOBJ) : $(OBJDIR)/%.o : %.S 152 | @echo 153 | @echo $< : 154 | $(CC) -c $(ALL_ASFLAGS) $< -o $@ 155 | 156 | # Target: clean project. 157 | clean: 158 | @echo 159 | rm -f -r $(OBJDIR) | exit 0 160 | 161 | # Include the dependency files. 162 | -include $(shell mkdir $(OBJDIR) 2>/dev/null) $(wildcard $(OBJDIR)/*.d) 163 | 164 | upload: 165 | @echo 166 | $(AVRDUDE) 167 | 168 | reset: 169 | @echo 170 | $(RESET) 171 | 172 | console: 173 | @echo 174 | $(CONSOLE) -------------------------------------------------------------------------------- /m328p_example/main.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | / 3 | / 4 | / 5 | / 6 | / 7 | / 8 | / 9 | / 10 | /----------------------------------------------------------------------------*/ 11 | #include 12 | #include 13 | #include 14 | /*---------------------------------------------------------------------------*/ 15 | #include "./digital.h" 16 | #include "./pcd8544.h" 17 | #include "../lcdMenu.h" 18 | #include "./serial_lib/xitoa.h" 19 | /*---------------------------------------------------------------------------*/ 20 | #define BUTTON_DEBUG 1 21 | /*---------------------------------------------------------------------------*/ 22 | void init_serial(); 23 | void send_char(char c); 24 | /*---------------------------------------------------------------------------*/ 25 | void initButtons(); 26 | uint8_t handleButtons(); 27 | uint8_t upButton_clicked(); 28 | uint8_t downButton_clicked(); 29 | uint8_t backButton_clicked(); 30 | uint8_t selectButton_clicked(); 31 | /*---------------------------------------------------------------------------*/ 32 | void callback() 33 | { 34 | xprintf(PSTR("callback from mainmenu!\r\n")); 35 | } 36 | /*---------------------------------------------------------------------------*/ 37 | void scallback() 38 | { 39 | xprintf(PSTR("callback from submenu!\r\n")); 40 | } 41 | /*---------------------------------------------------------------------------*/ 42 | struct menu subMenu; 43 | /*---------------------------------------------------------------------------*/ 44 | struct menuitem node1 = {"menu1",callback,NULL}; 45 | struct menuitem node2 = {"menu2",NULL,&subMenu}; 46 | struct menuitem node3 = {"menu3",NULL,&subMenu}; 47 | struct menuitem node4 = {"menu4",NULL,&subMenu}; 48 | struct menuitem node5 = {"menu5",NULL,&subMenu}; 49 | struct menuitem node6 = {"menu6",NULL,&subMenu}; 50 | struct menuitem node7 = {"menu7",NULL,&subMenu}; 51 | struct menuitem node8 = {"menu8",NULL,&subMenu}; 52 | struct menuitem* mainElements[] = {&node1,&node2,&node3,&node4,&node5,&node6,&node7,&node8}; 53 | /*---------------------------------------------------------------------------*/ 54 | struct menuitem snode1 = {"submenu1",scallback,NULL}; 55 | struct menuitem snode2 = {"submenu2",scallback,NULL}; 56 | struct menuitem snode3 = {"submenu3",scallback,NULL}; 57 | struct menuitem snode4 = {"submenu4",scallback,NULL}; 58 | struct menuitem snode5 = {"submenu5",scallback,NULL}; 59 | struct menuitem* subElements[] = {&snode1,&snode2,&snode3,&snode4,&snode5}; 60 | /*---------------------------------------------------------------------------*/ 61 | struct menu mainMenu = {8,NULL,mainElements}; 62 | struct menu subMenu = {5,&mainMenu,subElements}; 63 | /*---------------------------------------------------------------------------*/ 64 | struct menustate myMenuState; 65 | /*---------------------------------------------------------------------------*/ 66 | int main() 67 | { 68 | init_serial(); 69 | initButtons(); 70 | pcd8544_begin(0x29); 71 | 72 | myMenuState.top = 0; 73 | myMenuState.MAX_ROWS = 6; 74 | myMenuState.last_top = 0; 75 | myMenuState.currentItem = 0; 76 | myMenuState.last_currentItem = 0; 77 | myMenuState.currentMenu = &mainMenu; 78 | 79 | lcdMenu_drawMenu(&myMenuState); 80 | 81 | while(1) 82 | { 83 | if(handleButtons(&myMenuState)) 84 | { 85 | lcdMenu_drawMenu(&myMenuState); 86 | } 87 | } 88 | } 89 | /*---------------------------------------------------------------------------*/ 90 | void init_serial() 91 | { 92 | /* 19200 baud rate with 16 MHz Xtal ... */ 93 | const uint8_t ubrr = 51; 94 | 95 | pinMode(D,0,INPUT); 96 | pinMode(D,1,OUTPUT); 97 | 98 | /* Set baud rate */ 99 | UBRR0H = (unsigned char)(ubrr>>8); 100 | UBRR0L = (unsigned char)ubrr; 101 | 102 | /* Enable receiver and transmitter and Receive interupt */ 103 | UCSR0B = (1< Back!\r\n")); 201 | #endif 202 | } 203 | else if(selectButton_clicked()) 204 | { 205 | while(selectButton_clicked()); 206 | activity = 1; 207 | lcdMenu_select(ms); 208 | #if BUTTON_DEBUG 209 | xprintf(PSTR("> Select!\r\n")); 210 | #endif 211 | } 212 | else if(downButton_clicked()) 213 | { 214 | while(downButton_clicked()); 215 | activity = 1; 216 | lcdMenu_goDown(ms); 217 | #if BUTTON_DEBUG 218 | xprintf(PSTR("> Down!\r\n")); 219 | #endif 220 | } 221 | else if(upButton_clicked()) 222 | { 223 | while(upButton_clicked()); 224 | activity = 1; 225 | lcdMenu_goUp(ms); 226 | #if BUTTON_DEBUG 227 | xprintf(PSTR("> Up!\r\n")); 228 | #endif 229 | } 230 | return activity; 231 | } 232 | /*---------------------------------------------------------------------------*/ 233 | void lcdMenu_clearScreen() 234 | { 235 | pcd8544_clear(); 236 | pcd8544_gotoRc(0,0); 237 | } 238 | /*---------------------------------------------------------------------------*/ 239 | void lcdMenu_printNormal(const char* message) 240 | { 241 | pcd8544_print(" "); 242 | pcd8544_print(message); 243 | } 244 | /*---------------------------------------------------------------------------*/ 245 | void lcdMenu_printSpecial(const char* message) 246 | { 247 | pcd8544_print(">"); 248 | pcd8544_print(message); 249 | } 250 | /*---------------------------------------------------------------------------*/ 251 | void lcdMenu_goNextLine() 252 | { 253 | pcd8544_print("\r\n"); 254 | } 255 | /*---------------------------------------------------------------------------*/ -------------------------------------------------------------------------------- /m328p_example/serial_lib/xitoa.S: -------------------------------------------------------------------------------- 1 | ;---------------------------------------------------------------------------; 2 | ; Extended itoa, puts, printf and atoi (C)ChaN, 2006 3 | ; 4 | ; Module size: 277/261 words (max) 5 | ; 6 | 7 | #define USE_XPUTS 8 | #define USE_XITOA 9 | #define USE_XPRINTF 10 | ;#define CR_CRLF 11 | ;#define USE_XATOI 12 | 13 | 14 | 15 | .nolist 16 | #include // Include device specific definitions. 17 | .list 18 | 19 | #ifdef SPM_PAGESIZE // Recent devices have "lpm Rd,Z+" and "movw". 20 | .macro _LPMI reg 21 | lpm \reg, Z+ 22 | .endm 23 | .macro _MOVW dh,dl, sh,sl 24 | movw \dl, \sl 25 | .endm 26 | #else // Earlier devices do not have "lpm Rd,Z+" nor "movw". 27 | .macro _LPMI reg 28 | lpm 29 | mov \reg, r0 30 | adiw ZL, 1 31 | .endm 32 | .macro _MOVW dh,dl, sh,sl 33 | mov \dl, \sl 34 | mov \dh, \sh 35 | .endm 36 | #endif 37 | 38 | 39 | 40 | ;--------------------------------------------------------------------------- 41 | ; Stub function to forward to user output function 42 | ; 43 | ;Prototype: void xputc (char chr // a character to be output 44 | ; ); 45 | ;Size: 17/17 words 46 | 47 | .section .bss 48 | 49 | .global xfunc_out ; xfunc_out must be initialized before using this module. 50 | xfunc_out: .ds.w 1 51 | 52 | .section .text 53 | 54 | 55 | .global xputc 56 | .func xputc 57 | xputc: 58 | #ifdef CR_CRLF 59 | cpi r24, 10 ;LF --> CRLF 60 | brne 1f ; 61 | ldi r24, 13 ; 62 | rcall 1f ; 63 | ldi r24, 10 ;/ 64 | 1: 65 | #endif 66 | push ZH 67 | push ZL 68 | lds ZL, xfunc_out+0 ;Pointer to the registered output function. 69 | lds ZH, xfunc_out+1 ;/ 70 | sbiw ZL, 0 71 | breq 2f 72 | icall 73 | 2: pop ZL 74 | pop ZH 75 | ret 76 | .endfunc 77 | 78 | 79 | 80 | ;--------------------------------------------------------------------------- 81 | ; Direct ROM string output 82 | ; 83 | ;Prototype: void xputs (const prog_char *str // rom string to be output 84 | ; ); 85 | ;Size: 10/7 words 86 | 87 | #ifdef USE_XPUTS 88 | .global xputs 89 | .func xputs 90 | xputs: 91 | _MOVW ZH,ZL, r25,r24 ; Z = pointer to rom string 92 | 1: _LPMI r24 93 | cpi r24, 0 94 | breq 2f 95 | rcall xputc 96 | rjmp 1b 97 | 2: ret 98 | .endfunc 99 | #endif 100 | 101 | 102 | ;--------------------------------------------------------------------------- 103 | ; Extended direct numeral string output (32bit version) 104 | ; 105 | ;Prototype: void xitoa (long value, // value to be output 106 | ; char radix, // radix 107 | ; char width); // minimum width 108 | ;Size: 59/59 words 109 | ; 110 | 111 | #ifdef USE_XITOA 112 | .global xitoa 113 | .func xitoa 114 | xitoa: 115 | ;r25:r22 = value, r20 = base, r18 = digits 116 | clr r31 ;r31 = stack level 117 | ldi r30, ' ' ;r30 = sign 118 | ldi r19, ' ' ;r19 = filler 119 | sbrs r20, 7 ;When base indicates signd format and the value 120 | rjmp 0f ;is minus, add a '-'. 121 | neg r20 ; 122 | sbrs r25, 7 ; 123 | rjmp 0f ; 124 | ldi r30, '-' ; 125 | com r22 ; 126 | com r23 ; 127 | com r24 ; 128 | com r25 ; 129 | adc r22, r1 ; 130 | adc r23, r1 ; 131 | adc r24, r1 ; 132 | adc r25, r1 ;/ 133 | 0: sbrs r18, 7 ;When digits indicates zero filled, 134 | rjmp 1f ;filler is '0'. 135 | neg r18 ; 136 | ldi r19, '0' ;/ 137 | ;----- string conversion loop 138 | 1: ldi r21, 32 ;r26 = r25:r22 % r20 139 | clr r26 ;r25:r22 /= r20 140 | 2: lsl r22 ; 141 | rol r23 ; 142 | rol r24 ; 143 | rol r25 ; 144 | rol r26 ; 145 | cp r26, r20 ; 146 | brcs 3f ; 147 | sub r26, r20 ; 148 | inc r22 ; 149 | 3: dec r21 ; 150 | brne 2b ;/ 151 | cpi r26, 10 ;r26 is a numeral digit '0'-'F' 152 | brcs 4f ; 153 | subi r26, -7 ; 154 | 4: subi r26, -'0' ;/ 155 | push r26 ;Stack it 156 | inc r31 ;/ 157 | cp r22, r1 ;Repeat until r25:r22 gets zero 158 | cpc r23, r1 ; 159 | cpc r24, r1 ; 160 | cpc r25, r1 ; 161 | brne 1b ;/ 162 | 163 | cpi r30, '-' ;Minus sign if needed 164 | brne 5f ; 165 | push r30 ; 166 | inc r31 ;/ 167 | 5: cp r31, r18 ;Filler 168 | brcc 6f ; 169 | push r19 ; 170 | inc r31 ; 171 | rjmp 5b ;/ 172 | 173 | 6: pop r24 ;Flush stacked digits and exit 174 | rcall xputc ; 175 | dec r31 ; 176 | brne 6b ;/ 177 | 178 | ret 179 | .endfunc 180 | #endif 181 | 182 | 183 | 184 | ;---------------------------------------------------------------------------; 185 | ; Formatted string output (16/32bit version) 186 | ; 187 | ;Prototype: 188 | ; void xprintf (const prog_char *format, ...); 189 | ;Size: 104/94 words 190 | ; 191 | 192 | #ifdef USE_XPRINTF 193 | .global xprintf 194 | .func xprintf 195 | xprintf: 196 | push YH 197 | push YL 198 | in YL, _SFR_IO_ADDR(SPL) 199 | #ifdef SPH 200 | in YH, _SFR_IO_ADDR(SPH) 201 | #else 202 | clr YH 203 | #endif 204 | #if FLASHEND > 0x1FFFF 205 | adiw YL, 6 ;Y = pointer to arguments 206 | #else 207 | adiw YL, 5 ;Y = pointer to arguments 208 | #endif 209 | ld ZL, Y+ ;Z = pointer to format string 210 | ld ZH, Y+ ;/ 211 | 212 | 0: _LPMI r24 ;Get a format char 213 | cpi r24, 0 ;End of format string? 214 | breq 90f ;/ 215 | cpi r24, '%' ;Is format? 216 | breq 20f ;/ 217 | 1: rcall xputc ;Put a normal character 218 | rjmp 0b ;/ 219 | 90: pop YL 220 | pop YH 221 | ret 222 | 223 | 20: ldi r18, 0 ;r18: digits 224 | clt ;T: filler 225 | _LPMI r21 ;Get flags 226 | cpi r21, '%' ;Is a %? 227 | breq 1b ;/ 228 | cpi r21, '0' ;Zero filled? 229 | brne 23f ; 230 | set ;/ 231 | 22: _LPMI r21 ;Get width 232 | 23: cpi r21, '9'+1 ; 233 | brcc 24f ; 234 | subi r21, '0' ; 235 | brcs 90b ; 236 | lsl r18 ; 237 | mov r0, r18 ; 238 | lsl r18 ; 239 | lsl r18 ; 240 | add r18, r0 ; 241 | add r18, r21 ; 242 | rjmp 22b ;/ 243 | 244 | 24: brtc 25f ;get value (low word) 245 | neg r18 ; 246 | 25: ld r24, Y+ ; 247 | ld r25, Y+ ;/ 248 | cpi r21, 'c' ;Is type character? 249 | breq 1b ;/ 250 | cpi r21, 's' ;Is type RAM string? 251 | breq 50f ;/ 252 | cpi r21, 'S' ;Is type ROM string? 253 | breq 60f ;/ 254 | _MOVW r23,r22,r25,r24 ;r25:r22 = value 255 | clr r24 ; 256 | clr r25 ; 257 | clt ;/ 258 | cpi r21, 'l' ;Is long int? 259 | brne 26f ; 260 | ld r24, Y+ ;get value (high word) 261 | ld r25, Y+ ; 262 | set ; 263 | _LPMI r21 ;/ 264 | 26: cpi r21, 'd' ;Is type signed decimal? 265 | brne 27f ;/ 266 | ldi r20, -10 ; 267 | brts 40f ; 268 | sbrs r23, 7 ; 269 | rjmp 40f ; 270 | ldi r24, -1 ; 271 | ldi r25, -1 ; 272 | rjmp 40f ;/ 273 | 27: cpi r21, 'u' ;Is type unsigned decimal? 274 | ldi r20, 10 ; 275 | breq 40f ;/ 276 | cpi r21, 'X' ;Is type hexdecimal? 277 | ldi r20, 16 ; 278 | breq 40f ;/ 279 | cpi r21, 'b' ;Is type binary? 280 | ldi r20, 2 ; 281 | breq 40f ;/ 282 | rjmp 90b ;abort 283 | 40: push ZH ;Output the value 284 | push ZL ; 285 | rcall xitoa ; 286 | 42: pop ZL ; 287 | pop ZH ; 288 | rjmp 0b ;/ 289 | 290 | 50: push ZH ;Put a string on the RAM 291 | push ZL 292 | _MOVW ZH,ZL, r25,r24 293 | 51: ld r24, Z+ 294 | cpi r24, 0 295 | breq 42b 296 | rcall xputc 297 | rjmp 51b 298 | 299 | 60: push ZH ;Put a string on the ROM 300 | push ZL 301 | rcall xputs 302 | rjmp 42b 303 | 304 | .endfunc 305 | #endif 306 | 307 | 308 | 309 | ;--------------------------------------------------------------------------- 310 | ; Extended numeral string input 311 | ; 312 | ;Prototype: 313 | ; char xatoi ( /* 1: Successful, 0: Failed */ 314 | ; const char **str, /* pointer to pointer to source string */ 315 | ; long *res /* result */ 316 | ; ); 317 | ;Size: 94/91 words 318 | ; 319 | 320 | #ifdef USE_XATOI 321 | .global xatoi 322 | .func xatoi 323 | xatoi: 324 | _MOVW r1, r0, r23, r22 325 | _MOVW XH, XL, r25, r24 326 | ld ZL, X+ 327 | ld ZH, X+ 328 | clr r18 ;r21:r18 = 0; 329 | clr r19 ; 330 | clr r20 ; 331 | clr r21 ;/ 332 | clt ;T = 0; 333 | 334 | ldi r25, 10 ;r25 = 10; 335 | rjmp 41f ;/ 336 | 40: adiw ZL, 1 ;Z++; 337 | 41: ld r22, Z ;r22 = *Z; 338 | cpi r22, ' ' ;if(r22 == ' ') continue 339 | breq 40b ;/ 340 | brcs 70f ;if(r22 < ' ') error; 341 | cpi r22, '-' ;if(r22 == '-') { 342 | brne 42f ; T = 1; 343 | set ; continue; 344 | rjmp 40b ;} 345 | 42: cpi r22, '9'+1 ;if(r22 > '9') error; 346 | brcc 70f ;/ 347 | cpi r22, '0' ;if(r22 < '0') error; 348 | brcs 70f ;/ 349 | brne 51f ;if(r22 > '0') cv_start; 350 | ldi r25, 8 ;r25 = 8; 351 | adiw ZL, 1 ;r22 = *(++Z); 352 | ld r22, Z ;/ 353 | cpi r22, ' '+1 ;if(r22 <= ' ') exit; 354 | brcs 80f ;/ 355 | cpi r22, 'b' ;if(r22 == 'b') { 356 | brne 43f ; r25 = 2; 357 | ldi r25, 2 ; cv_start; 358 | rjmp 50f ;} 359 | 43: cpi r22, 'x' ;if(r22 != 'x') error; 360 | brne 51f ;/ 361 | ldi r25, 16 ;r25 = 16; 362 | 363 | 50: adiw ZL, 1 ;Z++; 364 | ld r22, Z ;r22 = *Z; 365 | 51: cpi r22, ' '+1 ;if(r22 <= ' ') break; 366 | brcs 80f ;/ 367 | cpi r22, 'a' ;if(r22 >= 'a') r22 =- 0x20; 368 | brcs 52f ; 369 | subi r22, 0x20 ;/ 370 | 52: subi r22, '0' ;if((r22 -= '0') < 0) error; 371 | brcs 70f ;/ 372 | cpi r22, 10 ;if(r22 >= 10) { 373 | brcs 53f ; r22 -= 7; 374 | subi r22, 7 ; if(r22 < 10) 375 | cpi r22, 10 ; 376 | brcs 70f ;} 377 | 53: cp r22, r25 ;if(r22 >= r25) error; 378 | brcc 70f ;/ 379 | 60: ldi r24, 33 ;r21:r18 *= r25; 380 | sub r23, r23 ; 381 | 61: brcc 62f ; 382 | add r23, r25 ; 383 | 62: lsr r23 ; 384 | ror r21 ; 385 | ror r20 ; 386 | ror r19 ; 387 | ror r18 ; 388 | dec r24 ; 389 | brne 61b ;/ 390 | add r18, r22 ;r21:r18 += r22; 391 | adc r19, r24 ; 392 | adc r20, r24 ; 393 | adc r21, r24 ;/ 394 | rjmp 50b ;repeat 395 | 396 | 70: ldi r24, 0 397 | rjmp 81f 398 | 80: ldi r24, 1 399 | 81: brtc 82f 400 | clr r22 401 | com r18 402 | com r19 403 | com r20 404 | com r21 405 | adc r18, r22 406 | adc r19, r22 407 | adc r20, r22 408 | adc r21, r22 409 | 82: st -X, ZH 410 | st -X, ZL 411 | _MOVW XH, XL, r1, r0 412 | st X+, r18 413 | st X+, r19 414 | st X+, r20 415 | st X+, r21 416 | clr r1 417 | ret 418 | .endfunc 419 | #endif 420 | 421 | 422 | -------------------------------------------------------------------------------- /m328p_example/pcd8544.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | / Pure C based pcd8544 library. 3 | /------------------------------------------------------------------------------ 4 | / This library is derived from C++ based Arduino/Maple library for pcd8544 5 | / lcd controller. https://github.com/snigelen/pcd8544 6 | /----------------------------------------------------------------------------*/ 7 | #include "pcd8544.h" 8 | /*---------------------------------------------------------------------------*/ 9 | const unsigned char PROGMEM small_num[][4] = { 10 | {0x0e,0x15,0x0e,0x00}, // 48, zero 11 | {0x12,0x1f,0x10,0x00}, // 49, one 12 | {0x12,0x19,0x16,0x00}, // 50, two 13 | {0x11,0x15,0x0b,0x00}, // 51, three 14 | {0x07,0x04,0x1f,0x00}, // 52, four 15 | {0x17,0x15,0x09,0x00}, // 53, five 16 | {0x0e,0x15,0x09,0x00}, // 54, six 17 | {0x19,0x05,0x03,0x00}, // 55, seven 18 | {0x1a,0x15,0x0b,0x00}, // 56, eight 19 | {0x12,0x15,0x0e,0x00}, // 57, nine 20 | {0x00,0x10,0x00,0x00}, // 46, period 21 | }; 22 | /*---------------------------------------------------------------------------*/ 23 | const unsigned char PROGMEM font6x8 [][5] = { 24 | {0x00,0x00,0x00,0x00,0x00,}, // ' ' 32 25 | {0x00,0x00,0x5F,0x00,0x00,}, // '!' 33 26 | {0x00,0x07,0x00,0x07,0x00,}, // '"' 34 27 | {0x14,0x7F,0x14,0x7F,0x14,}, // '#' 35 28 | {0x24,0x2A,0x7F,0x2A,0x12,}, // '$' 36 29 | {0x23,0x13,0x08,0x64,0x62,}, // '%' 37 30 | {0x36,0x49,0x55,0x22,0x50,}, // '&' 38 31 | {0x00,0x05,0x03,0x00,0x00,}, // ''' 39 32 | {0x00,0x1C,0x22,0x41,0x00,}, // '(' 40 33 | {0x00,0x41,0x22,0x1C,0x00,}, // ')' 41 34 | {0x14,0x08,0x3E,0x08,0x14,}, // '*' 42 35 | {0x08,0x08,0x3E,0x08,0x08,}, // '+' 43 36 | {0x00,0x50,0x30,0x00,0x00,}, // ',' 44 37 | {0x08,0x08,0x08,0x08,0x08,}, // '-' 45 38 | {0x00,0x60,0x60,0x00,0x00,}, // '.' 46 39 | {0x20,0x10,0x08,0x04,0x02,}, // '/' 47 40 | {0x3E,0x51,0x49,0x45,0x3E,}, // '0' 48 41 | {0x00,0x42,0x7F,0x40,0x00,}, // '1' 49 42 | {0x42,0x61,0x51,0x49,0x46,}, // '2' 50 43 | {0x21,0x41,0x45,0x4B,0x31,}, // '3' 51 44 | {0x18,0x14,0x12,0x7F,0x10,}, // '4' 52 45 | {0x27,0x45,0x45,0x45,0x39,}, // '5' 53 46 | {0x3C,0x4A,0x49,0x49,0x30,}, // '6' 54 47 | {0x03,0x01,0x71,0x09,0x07,}, // '7' 55 48 | {0x36,0x49,0x49,0x49,0x36,}, // '8' 56 49 | {0x06,0x49,0x49,0x29,0x16,}, // '9' 57 50 | {0x00,0x36,0x36,0x00,0x00,}, // ':' 58 51 | {0x00,0x56,0x36,0x00,0x00,}, // ';' 59 52 | {0x08,0x14,0x22,0x41,0x00,}, // '<' 60 53 | {0x14,0x14,0x14,0x14,0x14,}, // '=' 61 54 | {0x00,0x41,0x22,0x14,0x08,}, // '>' 62 55 | {0x02,0x01,0x51,0x09,0x06,}, // '?' 63 56 | {0x32,0x49,0x79,0x41,0x3E,}, // '@' 64 57 | {0x7E,0x11,0x11,0x11,0x7E,}, // 'A' 65 58 | {0x7F,0x49,0x49,0x49,0x36,}, // 'B' 66 59 | {0x3E,0x41,0x41,0x41,0x22,}, // 'C' 67 60 | {0x7F,0x41,0x41,0x22,0x1C,}, // 'D' 68 61 | {0x7F,0x49,0x49,0x49,0x41,}, // 'E' 69 62 | {0x7F,0x09,0x09,0x01,0x01,}, // 'F' 70 63 | {0x3E,0x41,0x49,0x49,0x3A,}, // 'G' 71 64 | {0x7F,0x08,0x08,0x08,0x7F,}, // 'H' 72 65 | {0x00,0x41,0x7F,0x41,0x00,}, // 'I' 73 66 | {0x20,0x41,0x41,0x3F,0x01,}, // 'J' 74 67 | {0x7F,0x08,0x14,0x22,0x41,}, // 'K' 75 68 | {0x7F,0x40,0x40,0x40,0x40,}, // 'L' 76 69 | {0x7F,0x02,0x0C,0x02,0x7F,}, // 'M' 77 70 | {0x7F,0x04,0x08,0x10,0x7F,}, // 'N' 78 71 | {0x3E,0x41,0x41,0x41,0x3E,}, // 'O' 79 72 | {0x7F,0x09,0x09,0x09,0x06,}, // 'P' 80 73 | {0x3E,0x41,0x51,0x21,0x5E,}, // 'Q' 81 74 | {0x7F,0x09,0x19,0x29,0x46,}, // 'R' 82 75 | {0x26,0x49,0x49,0x49,0x32,}, // 'S' 83 76 | {0x01,0x01,0x7F,0x01,0x01,}, // 'T' 84 77 | {0x3F,0x40,0x40,0x40,0x3F,}, // 'U' 85 78 | {0x1F,0x20,0x40,0x20,0x1F,}, // 'V' 86 79 | {0x3F,0x40,0x38,0x40,0x3F,}, // 'W' 87 80 | {0x63,0x14,0x08,0x14,0x63,}, // 'X' 88 81 | {0x07,0x08,0x70,0x08,0x07,}, // 'Y' 89 82 | {0x61,0x51,0x49,0x45,0x43,}, // 'Z' 90 83 | {0x00,0x7F,0x41,0x41,0x00,}, // '[' 91 84 | {0x02,0x04,0x08,0x10,0x20,}, // '\' 92 85 | {0x00,0x41,0x41,0x7F,0x00,}, // ']' 93 86 | {0x04,0x02,0x01,0x02,0x04,}, // '^' 94 87 | {0x40,0x40,0x40,0x40,0x40,}, // '_' 95 88 | {0x00,0x01,0x02,0x04,0x00,}, // '`' 96 89 | {0x20,0x54,0x54,0x54,0x78,}, // 'a' 97 90 | {0x7F,0x48,0x44,0x44,0x38,}, // 'b' 98 91 | {0x38,0x44,0x44,0x44,0x20,}, // 'c' 99 92 | {0x38,0x44,0x44,0x48,0x3F,}, // 'd' 100 93 | {0x38,0x54,0x54,0x54,0x18,}, // 'e' 101 94 | {0x08,0x7E,0x09,0x01,0x02,}, // 'f' 102 95 | {0x0C,0x52,0x52,0x52,0x3E,}, // 'g' 103 96 | {0x7F,0x08,0x04,0x04,0x78,}, // 'h' 104 97 | {0x00,0x44,0x7D,0x40,0x00,}, // 'i' 105 98 | {0x20,0x40,0x45,0x3C,0x00,}, // 'j' 106 99 | {0x7F,0x10,0x28,0x44,0x00,}, // 'k' 107 100 | {0x00,0x41,0x7F,0x40,0x00,}, // 'l' 108 101 | {0x7C,0x04,0x18,0x04,0x78,}, // 'm' 109 102 | {0x7C,0x08,0x04,0x04,0x78,}, // 'n' 110 103 | {0x38,0x44,0x44,0x44,0x38,}, // 'o' 111 104 | {0x7C,0x14,0x14,0x14,0x08,}, // 'p' 112 105 | {0x08,0x14,0x14,0x18,0x7C,}, // 'q' 113 106 | {0x7C,0x08,0x04,0x04,0x08,}, // 'r' 114 107 | {0x48,0x54,0x54,0x54,0x20,}, // 's' 115 108 | {0x04,0x3F,0x44,0x40,0x20,}, // 't' 116 109 | {0x3C,0x40,0x40,0x20,0x7C,}, // 'u' 117 110 | {0x1C,0x20,0x40,0x20,0x1C,}, // 'v' 118 111 | {0x3C,0x40,0x30,0x40,0x3C,}, // 'w' 119 112 | {0x44,0x28,0x10,0x28,0x44,}, // 'x' 120 113 | {0x0C,0x50,0x50,0x50,0x3C,}, // 'y' 121 114 | {0x44,0x64,0x54,0x4C,0x44,}, // 'z' 122 115 | {0x00,0x08,0x36,0x41,0x00,}, // '{' 123 116 | {0x00,0x00,0x7F,0x00,0x00,}, // '|' 124 117 | {0x00,0x41,0x36,0x08,0x00,}, // '}' 125 118 | {0x10,0x08,0x08,0x10,0x08,}, // '~' 126 119 | {0x08,0x1C,0x2A,0x08,0x08,} // <- 127 120 | }; 121 | /*---------------------------------------------------------------------------*/ 122 | void pcd8544_begin(uint8_t contrast) 123 | { 124 | // cs pin 125 | // pinMode(cs,OUTPUT); 126 | 127 | // reset pin 128 | pinMode(B,0,OUTPUT); 129 | 130 | // DC pin 131 | pinMode(B,1,OUTPUT); 132 | 133 | // DATA pin 134 | pinMode(B,2,OUTPUT); 135 | 136 | // CLK pin 137 | pinMode(B,3,OUTPUT); 138 | 139 | // set reset low 140 | digitalWrite(B,0,LOW); 141 | // wait a little amount of time 142 | _delay_ms(1); 143 | // set reset high 144 | digitalWrite(B,0,HIGH); 145 | 146 | // Extenden instructions and !powerdown 147 | // and horizontal adressing (autoincrement of x-adress) 148 | pcd8544_command(PCD8544_FUNCTION_SET | PCD8544_FUNCTION_H); 149 | // Set Vop to 0x3F 150 | pcd8544_command(PCD8544_VOP | contrast); 151 | // Vlcd temp. coeff. 0 152 | pcd8544_command(PCD8544_TEMP_CONTROL); 153 | // Bias system 4, 1:48 154 | pcd8544_command(PCD8544_BIAS | PCD8544_BIAS_BS1 | PCD8544_BIAS_BS0); 155 | // Set H = 0 for normal instructions 156 | pcd8544_command(PCD8544_FUNCTION_SET); 157 | // Normal mode 158 | pcd8544_command(PCD8544_DISPLAY_CONTROL | PCD8544_DISPLAY_CONTROL_NORMAL_MODE); 159 | } 160 | /*---------------------------------------------------------------------------*/ 161 | void pcd8544_clear(void) 162 | { 163 | int i; 164 | for (i = 0; i < PCD8544_WIDTH*PCD8544_LINES; i++) 165 | { 166 | pcd8544_data(0); 167 | } 168 | } 169 | /*---------------------------------------------------------------------------*/ 170 | void pcd8544_write(uint8_t ch) 171 | { 172 | uint8_t i; 173 | 174 | if (ch == '\r') 175 | { 176 | pcd8544_gotoRc(current_row, 0); 177 | } 178 | if (ch == '\n') 179 | { 180 | pcd8544_gotoRc(current_row+1, current_column); 181 | } 182 | if (ch >= ' ' && ch <= 127) 183 | { 184 | for (i = 0; i < 5; i++) 185 | { 186 | pcd8544_data(pgm_read_byte(&font6x8[ch-' '][i]) <<1); 187 | } 188 | pcd8544_data(0); 189 | } 190 | } 191 | /*---------------------------------------------------------------------------*/ 192 | void pcd8544_data(uint8_t data) 193 | { 194 | pcd8544_send(1, data); 195 | } 196 | /*---------------------------------------------------------------------------*/ 197 | void pcd8544_command(uint8_t data) 198 | { 199 | pcd8544_send(0, data); 200 | } 201 | /*---------------------------------------------------------------------------*/ 202 | void pcd8544_send(uint8_t data_or_command, uint8_t data) 203 | { 204 | uint8_t i = 0; 205 | 206 | // dc pin 207 | digitalWrite(B,1,data_or_command); 208 | 209 | // digitalWrite(cs, LOW); 210 | 211 | // sck low 212 | digitalWrite(B,3,LOW); 213 | 214 | for(i=0;i<8;i++) 215 | { 216 | 217 | if(data & (1<<(7-i))) 218 | { 219 | // din high 220 | digitalWrite(B,2,HIGH); 221 | } 222 | else 223 | { 224 | // din low 225 | digitalWrite(B,2,LOW); 226 | } 227 | 228 | // sck high 229 | digitalWrite(B,3,HIGH); 230 | 231 | // sck low 232 | digitalWrite(B,3,LOW); 233 | } 234 | 235 | // digitalWrite(cs, HIGH); 236 | 237 | if(data_or_command) 238 | { 239 | pcd8544_inc_row_column(); 240 | } 241 | } 242 | /*---------------------------------------------------------------------------*/ 243 | void pcd8544_setCursor(uint8_t column, uint8_t row) 244 | { 245 | pcd8544_gotoRc(row, 6*column); 246 | } 247 | /*---------------------------------------------------------------------------*/ 248 | void pcd8544_gotoRc(uint8_t row, uint8_t column) 249 | { 250 | if (row >= PCD8544_LINES) 251 | { 252 | row %= PCD8544_LINES; 253 | } 254 | if (column >= PCD8544_WIDTH) 255 | { 256 | row %= PCD8544_WIDTH; 257 | } 258 | pcd8544_command(PCD8544_SET_X_ADDRESS | column); 259 | pcd8544_command(PCD8544_SET_Y_ADDRESS | row); 260 | current_row = row; 261 | current_column = column; 262 | } 263 | /*---------------------------------------------------------------------------*/ 264 | void pcd8544_inc_row_column(void) 265 | { 266 | if (++current_column >= PCD8544_WIDTH) 267 | { 268 | current_column = 0; 269 | if (++current_row >= PCD8544_LINES) 270 | { 271 | current_row = 0; 272 | } 273 | } 274 | } 275 | /*---------------------------------------------------------------------------*/ 276 | void pcd8544_smallNum(uint8_t num, uint8_t shift) 277 | { 278 | uint8_t i; 279 | for (i = 0; i < 4; i++) 280 | { 281 | pcd8544_data(pgm_read_byte(&small_num[num][i])<