Appendix: Code

Download Code /************************************************************************************* * happyzap's Cooking Coach by paras (phs11@cornell.edu) and rudy (rac32@cornell.edu)* *************************************************************************************/ /* to port back to mega103L (backwards to port to 8515) * change include lines X * comment out DDRC X * move portD (appliances to port E) X * move command lines (PORTD) back to port D X * move pushbuttons (portA) back to port F and kill init for port A X * increase table sizes (relative to TEXT_WIDTH) * enable sram X * change TIMSK to 0x11 X * change timer interrupt vector to 13 X */ #include <mega103.h> #include <delay.h> #include <stdio.h> #include <math.h> /************************************************************************************* * Constants * *************************************************************************************/ // Global contants #define NUM_RECIPES 21 // max number of recipes #define NUM_STEPS 450 // max number of steps in all of the recipes collectivly #define TEXT_WIDTH 0x28 // width of screen's text block #define VERTICAL_LINES 25 #define TEXT_MEMORY_ADDR 0x0000 #define GRAPHICS_MEMORY_ADDR 0x03E8 #define MENU_LINE 0xBC // LCD Control line Commands (PORTD) #define LCDreset 0x00 // Reset the Display #define LCDnop 0x47 // No operation #define CmdSetup 0x47 // Set A0 high #define CmdWrite 0x43 // Set WR low #define DataSetup 0x07 // Set A0 low #define DataWrite 0x03 // Set WR low #define StatusRead 0x05 // Set RD low, A0 low #define DataRead 0x45 // Set RD low, A0 high // LCD Commands (PORTB) #define SystemSet 0x40 // Initialize system #define SleepIn 0x53 // Enter standby mode #define DispOFF 0x58 // Display Off #define DispON 0x59 // Display On #define Scroll 0x44 // Initialize Address & Regions #define CSRForm 0x5D // Set cursor type #define CharAddr 0x5C // Set address of character RAM #define CSRRight 0x4C // Cursor direction = right #define CSRLeft 0x4D // Cursor direction = left #define CSRUp 0x4E // Cursor direction = up #define CSRDown 0x4F // Cursor direction = down #define HorzScroll 0x5A // Set horz scroll position #define Overlay 0x5B // Set Display Format #define CSRW 0x46 // Set cursor address #define CSRR 0x47 // Read cursor address #define MWRITE 0x42 // Write to display memory #define MREAD 0x43 // Read from display memory // screen state variables #define num_screen_states 6 #define button_label_length 10 #define _mainmenu 0 #define _optionsmenu 1 #define _selectrecipesforshoppinglist 2 #define _selectrecipe 3 #define _shoppinglist 4 #define _cooking 5 unsigned char lastscreenstate = _cooking; unsigned char screenstate = _mainmenu; // pushbutton variables flash unsigned char _capture = 0; flash unsigned char _wait = 1; unsigned char state = _capture; #define reload 255-117; #define reload2 0;//255-61; #define _scrollup 0 #define _scrolldown 1 #define _selection0 2 #define _selection1 3 #define _selection2 4 #define _selection3 5 #define _panic 6 #define _nothing 7 unsigned char button = _nothing; /************************************************************************************* * Lower Memory Variables * *************************************************************************************/ // lower memory addresses (commonly used variables) unsigned char r_char, i, j, k; unsigned int location; unsigned char line_highlighted = 0; unsigned char topLineDisplayed = 0; unsigned char currentLowestLine = 21; unsigned char timersUpdated = 1; unsigned char startActionOnLine = 22; unsigned char startTimer1OnLine = 22; unsigned char startTimer2OnLine = 22; // database indicies unsigned char r_index_x = 0; unsigned char r_index_y = 0; unsigned char recipe_index = 0; unsigned char t1H, t1M, t1S, t2H, t2M, t2S; // two timers, hours, minutes and seconds /************************************************************************************* * Flash Contants * *************************************************************************************/ // flash tables flash unsigned char happy_zap[11] = {"HAPPY ZAP!"}; flash unsigned char cooking_coach[14] = {"COOKING COACH"}; flash unsigned char choose_one[11] = {"Choose One"}; flash unsigned char main_menu[10] = {"MAIN MENU"}; flash unsigned char options_menu[13] = {"OPTIONS MENU"}; flash unsigned char build_shopping_list[33] = {"SELECT RECIPES FOR SHOPPING LIST"}; flash unsigned char shopping_list[14] = {"SHOPPING LIST"}; flash unsigned char select_recipe[14] = {"SELECT RECIPE"}; flash unsigned char control_oven[15] = {"X Control Oven"}; flash unsigned char control_stove[16] = {"X Control Stove"}; flash unsigned char control_toaster[18] = {"X Control Toaster"}; flash unsigned char control_coffee_maker[23] = {"X Control Coffee Maker"}; flash unsigned char start1[9] = {" Start 1"}; flash unsigned char start2[9] = {" Start 2"}; flash unsigned char timer1[8] = {"timer 1"}; flash unsigned char timer2[8] = {"timer 2"}; flash unsigned char nine_blanks[10] = {" "}; flash unsigned char execute[10] = {" EXECUTE"}; flash unsigned char topBounds[num_screen_states] = {5,3,3,3,3,3}; flash unsigned char botBounds[num_screen_states] = {7,6,21,21,21,21}; flash unsigned char slider[6] = { 0b00000000, 0b00000100, 0b00001100, 0b00011100, 0b00111100, 0b01111100 }; flash unsigned char choices[num_screen_states][4][button_label_length+1] = { { {" ENTER"}, // main menu {" "}, {" "}, {" "} }, { {" MAIN MENU"},// options {" ON"}, {" OFF"}, {" "} }, { {" MAIN MENU"},//select stuff for shopping list {" SELECT"}, {" UNSELECT"}, {" DISPLAY"} }, { {" MAIN MENU"},// select recipes {" SELECT"}, {" REFRESH"}, {" DELETE"} }, { {" MAIN MENU"},// shopping list {" REDO LIST"}, {" CHECK"}, {" UNCHECK"} }, { {" MAIN MENU"},// cooking {" NEW"}, {" "}, {" "} } }; /************************************************************************************* * High Memory Tables * *************************************************************************************/ // large database variables unsigned char pendingTimer1[16]; unsigned char pendingTimer2[16]; unsigned char pendingAction1[5]; unsigned char pendingAction2[5]; unsigned char pendingAction[5]; unsigned char selected[NUM_RECIPES]; unsigned char controls[4] = {1,1,1,1}; unsigned char command[5]; unsigned char recipe_names[NUM_RECIPES][TEXT_WIDTH-8]; // list of recipe names unsigned char recipe_pointers[NUM_RECIPES]; // where to find recipes in the database unsigned char recipes[NUM_STEPS][TEXT_WIDTH-8]; // the database /************************************************************************************* * Prototypes * *************************************************************************************/ // file transfer interrupt[UART_RXC] void uart_rec(void); // button handling void scrollup(void); void scrolldown(void); void PANIC(void); void selection0(void); void selection1(void); void selection2(void); void selection3(void); void captureState(void); void waitState(void); interrupt[TIM0_OVF] void time0_overflow(void); // timing interrupt[13] void t1a_compare_match(void); // init screens void displayMainMenu(void); void displayOptionsMenu(void); void addOptions(unsigned char me); void removeOptions(unsigned char me); void displayListCreator(void); void addSelection(unsigned char me); void removeSelection(unsigned char me); void displayShoppingList(void); void addCheck(unsigned char me); void removeCheck(unsigned char me); void displayRecipeList(void); void showRecipe(void); void readyToStartAction(void); void action(void); void startPendingAction(void); void readyToStartTimer1(void); void readyToStartTimer2(void); void startTimer1(void); void startTimer2(void); void startTimer1PendingAction(void); void startTimer2PendingAction(void); // screen modifications void shiftStuffDown(void); void shiftStuffUp(void); void deleteRecipe(unsigned char deleteMe); // primative LCD functions void printWord(unsigned char flash *word); void printBlankLine(void); void displayButtons(void); void updateTimers(void); void displayTimerLabels(void); void displayBorders(void); void highlight(void); void unHighlight(unsigned char unhighlight); void initLCD(void); void clearLCD(void); void WriteCMD(unsigned char CommandCode); void WriteDATA(unsigned char CommandCode); void DELAY1_2(void); // main void main(void); /************************************************************************************* * File Transfer * *************************************************************************************/ // executes when a character is transfered in over the serial line interrupt[UART_RXC] void uart_rec(void) { r_char = UDR; if (r_char != '\r' && r_char != '\n' && r_char != '\0') recipes[r_index_y][r_index_x++] = r_char; else { recipes[r_index_y][r_index_x++] = '\0'; if (recipes[r_index_y][0] == 'B') // start of a new recipe { for (i=0;i<r_index_x-2;i++) // copy over the recipe name recipe_names[recipe_index][i] = recipes[r_index_y][i+2]; recipe_names[recipe_index][r_index_x-1] = '\0'; recipe_pointers[recipe_index] = r_index_y; recipe_index++; } r_index_y++; // go to next line r_index_x = 0; } } /************************************************************************************* * Timing * *************************************************************************************/ // keeps track of timers 1 and 2 by changing their times on one second ticks and executes timer based actions interrupt[13] void t1a_compare_match(void) { if (t1S != 0 || t1M != 0 || t1H != 0) // if time has hit zero, don't change { t1S--; if (t1S == 0 && t1M == 0 && t1H == 0) // if we just hit zero on this itteration startTimer1PendingAction(); else if (t1S > 59) { t1S = 59; t1M--; if (t1M > 59) { t1M = 59; t1H--; if (t1H > 24) t1H = 0; } } timersUpdated = 1; } if (t2S != 0 || t2M != 0 || t2H != 0) // if time has hit zero, don't change { t2S--; if (t1S == 0 && t1M == 0 && t1H == 0) // if we just hit zero on this itteration startTimer2PendingAction(); else if (t2S > 59) { t2S = 59; t2M--; if (t2M > 59) { t2M = 59; t2H--; if (t2H > 24) t2H = 0; } } timersUpdated = 1; } } /************************************************************************************* * Button Press Handling * *************************************************************************************/ void scrollup(void) { printf("scrolling up"); if (line_highlighted-1 >= topBounds[screenstate]) { unHighlight(line_highlighted--); highlight(); } else if (screenstate == _cooking && topLineDisplayed > 0) shiftStuffDown(); } void scrolldown(void) { printf("scrolling down"); if (line_highlighted+1 <= botBounds[screenstate] && line_highlighted+1 <= currentLowestLine) { unHighlight(line_highlighted++); highlight(); } if (screenstate == _cooking) { //printf("action line %d t1 line %d t2 line %d",startActionOnLine, startTimer1OnLine, startTimer2OnLine); if (line_highlighted == startActionOnLine) readyToStartAction(); else if (line_highlighted == startTimer1OnLine) readyToStartTimer1(); else if (line_highlighted == startTimer2OnLine) readyToStartTimer2(); else if (line_highlighted == 21) shiftStuffUp(); } } void PANIC(void) { printf("PANIC - shutting everything off and killing automatic controls"); UCR = 0x00; PORTE = 0x00; UCR = 0b10011000; controls[0] = 0; controls[1] = 0; controls[2] = 0; controls[3] = 0; } void selection0(void) { printf("sel0"); if (screenstate == _mainmenu) screenstate = line_highlighted - 4; else screenstate = _mainmenu; } void selection1(void) { printf("sel1"); if (screenstate == _selectrecipe) screenstate = _cooking; else if (screenstate == _cooking) screenstate = _selectrecipe; else if (screenstate == _selectrecipesforshoppinglist) addSelection(line_highlighted); else if (screenstate == _shoppinglist) state = _selectrecipesforshoppinglist; else if (screenstate == _optionsmenu) addOptions(line_highlighted); } void selection2(void) { printf("sel2"); if (screenstate == _selectrecipe) displayRecipeList(); else if (screenstate == _selectrecipesforshoppinglist) removeSelection(line_highlighted); else if (screenstate == _shoppinglist) addCheck(line_highlighted); else if (screenstate == _optionsmenu) removeOptions(line_highlighted); else if (screenstate == _cooking) { if (line_highlighted == startActionOnLine) startPendingAction(); else if (line_highlighted == startTimer1OnLine) startTimer1(); else printf("\r\nno longer on action or timer1 line"); } } void selection3(void) { printf("sel3"); if (screenstate == _selectrecipe) { deleteRecipe(line_highlighted - 3); displayRecipeList(); } else if (screenstate == _selectrecipesforshoppinglist) screenstate = _shoppinglist; else if (screenstate == _shoppinglist) removeCheck(line_highlighted); else if (screenstate == _cooking) startTimer2(); } void captureState(void) { state = _wait; if (PINF.0 == 0) button = _scrollup; else if (PINF.1 == 0) button = _scrolldown; else if (PINF.2 == 0) button = _selection0; else if (PINF.3 == 0) button = _selection1; else if (PINF.4 == 0) button = _selection2; else if (PINF.5 == 0) button = _selection3; else if (PINF.6 == 0) button = _panic; else { button = _nothing; state = _capture; } } // waits until no buttons are pushed and goes back to capture state void waitState(void) { if (PINF == 0xff) // if buttons have been released { if (button == _scrollup) scrollup(); else if (button == _scrolldown) scrolldown(); else if (button == _selection0) selection0(); else if (button == _selection1) selection1(); else if (button == _selection2) selection2(); else if (button == _selection3) selection3(); else if (button == _panic) PANIC(); button = _nothing; state = _capture; } } // interrupt jump table... should be envoked every 30mS or so interrupt[TIM0_OVF] void time0_overflow(void) { TCNT0 = reload; if (state == _capture) captureState(); else if (state == _wait) waitState(); } /************************************************************************************* * Screen Initializations * *************************************************************************************/ // shows the mainmenu to the user and lets him/her choose which menu to see next void displayMainMenu(void) { location = TEXT_MEMORY_ADDR; clearLCD(); WriteCMD(CSRW); // print happyzap! WriteDATA(0x0C); WriteDATA(0x00); printWord(happy_zap); location = TEXT_WIDTH; // print main menu WriteCMD(CSRW); WriteDATA(location+0x0C); WriteDATA(0x00); printWord(main_menu); location += TEXT_WIDTH + TEXT_WIDTH; // print choices WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(choose_one); location += TEXT_WIDTH + TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(options_menu); location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(shopping_list); location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(select_recipe); displayBorders(); line_highlighted = topBounds[_mainmenu]; currentLowestLine = botBounds[_mainmenu]; highlight(); displayButtons(); displayTimerLabels(); } // lets the user choose which appliances to have controlled by the cooking coach void displayOptionsMenu(void) { location = TEXT_MEMORY_ADDR + TEXT_WIDTH; clearLCD(); WriteCMD(CSRW); // prints options menu WriteDATA(location+0x0C); WriteDATA(0x00); WriteCMD(MWRITE); printWord(options_menu); location += TEXT_WIDTH<<1; // skip two lines WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); // equip to control printWord(control_oven); location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(control_stove); location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(control_toaster); location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(control_coffee_maker); displayBorders(); displayTimerLabels(); line_highlighted = topBounds[_optionsmenu]; currentLowestLine = botBounds[_optionsmenu]; displayButtons(); highlight(); } // enables control of an appliance and places an X next to it void addOptions(unsigned char me) { controls[me-3] = 0; location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * me); WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA('X'); WriteDATA(' '); } // disables control of an appliance and removes the X next to it void removeOptions(unsigned char me) { controls[me-3] = 0; location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * me); WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA(' '); WriteDATA(' '); } // shows a list of recipes to choose from to generate a shopping list void displayListCreator(void) { location = TEXT_MEMORY_ADDR; clearLCD(); location = TEXT_WIDTH; // prints heading WriteCMD(CSRW); WriteDATA(location+0x05); WriteDATA(0x00); printWord(build_shopping_list); for (i=0;i<NUM_RECIPES;i++) selected[i] = 0; location += TEXT_WIDTH; for (i=0;i<recipe_index;i++) // prints out the recipe index with two spaces inserted before each name { location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); j = 0; WriteCMD(MWRITE); WriteDATA(' '); WriteDATA(' '); while (recipe_names[i][j] != '\0') WriteDATA(recipe_names[i][j++]); } displayBorders(); line_highlighted = topBounds[_selectrecipesforshoppinglist]; currentLowestLine = topBounds[_selectrecipesforshoppinglist] + recipe_index - 1; highlight(); displayButtons(); displayTimerLabels(); } // places and -> to indicate that a recipe will be used in the shopping list void addSelection(unsigned char me) { selected[me-3] = 1; location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * me); WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA('-'); WriteDATA('>'); } // removes the -> to indicate that a recipe will not be included in the shopping list void removeSelection(unsigned char me) { selected[me-3] = 0; location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * me); WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA(' '); WriteDATA(' '); } // parses the recipe file for the recipes included in the shopping list and prints them to screen void displayShoppingList(void) { unsigned char numEs = 0; // number of recipes traversed unsigned char numLines = 0; location = TEXT_MEMORY_ADDR; clearLCD(); WriteCMD(CSRW); // prints title WriteDATA(location+0x0C); WriteDATA(0x00); i = 0; WriteCMD(MWRITE); printWord(shopping_list); location += TEXT_WIDTH<<1; for (i=0;i<r_index_y;i++) { if (recipes[i][0] == 'I' && selected[numEs] == 1) { numLines++; location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); j = 2; WriteCMD(MWRITE); WriteDATA(' '); WriteDATA(' '); while (recipes[i][j] != '\0') { /* if (j == 29 || j == 58 || j == 87) { location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); }*/ WriteDATA(recipes[i][j++]); } } if (recipes[i][0] == 'E') numEs++; } displayBorders(); // unHighlight(line_highlighted-3); line_highlighted = topBounds[_shoppinglist]; currentLowestLine = topBounds[_shoppinglist] + numLines - 1; highlight(); displayButtons(); displayTimerLabels(); } // adds an X next to each ingredient as the user gets them void addCheck(unsigned char me) { location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * me); WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA('X'); WriteDATA(' '); } // lets the user undo a checked off ingredient void removeCheck(unsigned char me) { location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * me); WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA(' '); WriteDATA(' '); } // displays the list of recipes so that the user can choose one to execute void displayRecipeList(void) { location = TEXT_MEMORY_ADDR; clearLCD(); location = TEXT_WIDTH; // prints title WriteCMD(CSRW); WriteDATA(location+0x0C); WriteDATA(0x00); printWord(select_recipe); location += TEXT_WIDTH; for (i=0;i<recipe_index;i++) // write out the name of each recipe { location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); j = 0; WriteCMD(MWRITE); while (recipe_names[i][j] != '\0') WriteDATA(recipe_names[i][j++]); } displayBorders(); line_highlighted = topBounds[_selectrecipe]; currentLowestLine = topBounds[_selectrecipe] + recipe_index - 1; highlight(); displayButtons(); displayTimerLabels(); } // the meat of the project, this displays a choosen recipe, executes the actions as the user hits the // designated line and pushes a button. it also starts timers to drive buzzers and do other actions void showRecipe(void) { unsigned char end; unsigned char numLines = 0; unsigned int locallocation; startActionOnLine = 22; startTimer1OnLine = 22; startTimer2OnLine = 22; end = recipe_pointers[line_highlighted-2]; if (end == 0) end = r_index_y; locallocation = TEXT_MEMORY_ADDR + TEXT_WIDTH; clearLCD(); WriteCMD(CSRW); // show name of the recipe WriteDATA(locallocation+0x0C); WriteDATA(0x00); i = 0; WriteCMD(MWRITE); while (recipe_names[line_highlighted-3][i] != '\0') WriteDATA(recipe_names[line_highlighted-3][i++]); locallocation += TEXT_WIDTH; for (i=recipe_pointers[line_highlighted-3];i<end;i++) // for each line in the recipe { if (recipes[i][0] == 'I' || recipes[i][0] == 'S') // display ingredients or steps { numLines++; locallocation += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(locallocation); WriteDATA(locallocation>>8); j = 2; WriteCMD(MWRITE); while (recipes[i][j] != '\0') { if (j == 29 || j == 58 || j == 87) { locallocation += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(locallocation); WriteDATA(locallocation>>8); WriteCMD(MWRITE); } WriteDATA(recipes[i][j++]); } } else if (recipes[i][0] == 'A' && controls[recipes[i][2]-'0'] == 1) // executes a simple action { startActionOnLine = topBounds[_cooking] + numLines - 1; for (k=0;k<5;k++) pendingAction[k] = recipes[i][k]; readyToStartAction(); } else if (recipes[i][0] == 'T') // prepares to start a timer { if (recipes[i][1] == '1') { startTimer1OnLine = topBounds[_cooking] + numLines - 1; j = 0; while (recipes[i][j] != '\0') { pendingTimer1[j] = recipes[i][j]; j++; } } else if (recipes[i][1] == '2') { startTimer2OnLine = topBounds[_cooking] + numLines - 1; j = 0; while (recipes[i][j] != '\0') { pendingTimer2[j] = recipes[i][j]; j++; } } } } displayBorders(); // unHighlight(line_highlighted-3); line_highlighted = topBounds[_cooking]; currentLowestLine = topBounds[_cooking] + numLines - 1; highlight(); displayButtons(); displayTimerLabels(); } // performs an action (controls an appliance) void action() { UCR = 0x00; if(command[0] == 'A' && controls[command[2]-'0'] == 1) PORTE = slider[command[4]-'0']; UCR = 0b10011000; location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 24) + 20; WriteCMD(CSRW); WriteDATA(location); // removes the button WriteDATA(location>>8); printWord(nine_blanks); } // creates a button to execute an action void readyToStartAction() { location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 24) + 20; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(execute); } // once the user pushes the button, load the action and execute it void startPendingAction(void) { for (k=0;k<5;k++) command[k] = pendingAction[k]; action(); } // creates a button to start timer1 void readyToStartTimer1(void) { location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 24) + 20; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(start1); } // creates a button to start timer2 void readyToStartTimer2(void) { location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 24) + 30; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(start2); } // starts timer1 when the user pushes the appropriate button void startTimer1(void) { if (pendingTimer1[0] == 'T' && pendingTimer1[1] == '1') // makes sure we are looking at a timer thing and not an action { t1H = (pendingTimer1[3]-'0')*10 + (pendingTimer1[4]-'0'); t1M = (pendingTimer1[6]-'0')*10 + (pendingTimer1[7]-'0'); t1S = (pendingTimer1[9]-'0')*10 + (pendingTimer1[10]-'0'); if (pendingTimer1[12] == 'A') for (j=0;j<5;j++) pendingAction1[j] = pendingTimer1[j+12]; } else printf("Bad timer number %d", pendingTimer1[1]); pendingTimer1[1] = '\0'; location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 24) + 20; WriteCMD(CSRW); WriteDATA(location); // removes the button WriteDATA(location>>8); printWord(nine_blanks); } // starts timer2 when the user pushes the appropriate button void startTimer2(void) { if (pendingTimer2[1] == '2') { t2H = (pendingTimer2[3]-'0')*10 + (pendingTimer2[4]-'0'); t2M = (pendingTimer2[6]-'0')*10 + (pendingTimer2[7]-'0'); t2S = (pendingTimer2[9]-'0')*10 + (pendingTimer2[10]-'0'); if (pendingTimer2[12] == 'A') for (j=0;j<5;j++) pendingAction2[j] = pendingTimer2[j+12]; } else printf("Bad timer number %d", pendingTimer2[1]); pendingTimer2[1] = '\0'; location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 24) + 30; WriteCMD(CSRW); // removes the button WriteDATA(location); WriteDATA(location>>8); printWord(nine_blanks); } // start the action which executes when timer1 expires void startTimer1PendingAction() { for (k=0;k<5;k++) command[k] = pendingAction1[k]; action(); } // starts the action which executes when timer2 expires void startTimer2PendingAction() { for (k=0;k<5;k++) command[k] = pendingAction2[k]; action(); } /************************************************************************************* * Screen Modifications * *************************************************************************************/ void shiftStuffDown(void) { } void shiftStuffUp(void) { } // expunges a recipe from the main databse void deleteRecipe(unsigned char deleteMe) { unsigned char deleteFrom, deleteTo, difference; deleteFrom = recipe_pointers[deleteMe]; deleteTo = recipe_pointers[deleteMe+1]; if (deleteTo == 0) deleteTo = r_index_y; difference = deleteTo - deleteFrom; // moves all recipes up for (i=deleteFrom;i<r_index_y;i++) for (j=0;j<TEXT_WIDTH;j++) recipes[i][j] = recipes[i+difference][j]; // moves up each recipe name for (i=deleteMe;i<recipe_index;i++) { for (j=0;j<TEXT_WIDTH-1;j++) recipe_names[i][j] = recipe_names[i+1][j]; recipe_pointers[i] = recipe_pointers[i+1]; } for (j=0;j<TEXT_WIDTH;j++) recipe_names[NUM_RECIPES][j] = 0; recipe_pointers[NUM_RECIPES] = 0; r_index_y -= difference; recipe_index--; } /************************************************************************************* * Primative LCD Functions * *************************************************************************************/ // prints a word to the LCD void printWord(unsigned char flash *word) { unsigned char offset = 0; WriteCMD(MWRITE); while (*(word+offset) != '\0') { WriteDATA(*(word+offset)); offset++; } } // prints a blank line to the LCD void printBlankLine(void) { unsigned char w; WriteCMD(MWRITE); for (w=0;w<TEXT_WIDTH;w++) WriteDATA(' '); } // puts the labels for the timer on the LCD void displayTimerLabels(void) { location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 7) + 32; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(timer1); location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 15) + 32; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); printWord(timer2); } // when the timer ticks we update the timer on the screen void updateTimers(void) { unsigned char bit1; unsigned char bit0; location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 8) + 32; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); bit1 = floor(t1H/10); bit0 = t1H - (bit1*10); WriteDATA(bit1+'0'); WriteDATA(bit0+'0'); WriteDATA(':'); bit1 = floor(t1M/10); bit0 = t1M - (bit1*10); WriteDATA(bit1+'0'); WriteDATA(bit0+'0'); WriteDATA(':'); bit1 = floor(t1S/10); bit0 = t1S - (bit1*10); WriteDATA(bit1+'0'); WriteDATA(bit0+'0'); location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 16) + 32; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); bit1 = floor(t2H/10); bit0 = t2H - (bit1*10); WriteDATA(bit1+'0'); WriteDATA(bit0+'0'); WriteDATA(':'); bit1 = floor(t2M/10); bit0 = t2M - (bit1*10); WriteDATA(bit1+'0'); WriteDATA(bit0+'0'); WriteDATA(':'); bit1 = floor(t2S/10); bit0 = t2S - (bit1*10); WriteDATA(bit1+'0'); WriteDATA(bit0+'0'); } // looks up the appropriate buttons to display for each screen state and puts them on screen void displayButtons(void) { unsigned char r,s; location = TEXT_MEMORY_ADDR + (TEXT_WIDTH * 24); // first clear out current line WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); for (r=0;r<4;r++) { WriteCMD(MWRITE); s = 0; while (choices[screenstate][r][s] != '\0') WriteDATA(choices[screenstate][r][s++]); location += button_label_length; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); } } // displays the lines dividing each window void displayBorders(void) { location = GRAPHICS_MEMORY_ADDR + (TEXT_WIDTH * 16); // horizontal line, 2 spaces down WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); for (i=0;i<(TEXT_WIDTH<<1);i++) WriteDATA(0xFF); location = GRAPHICS_MEMORY_ADDR + (TEXT_WIDTH * MENU_LINE);// horizontal line across bottom WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); for (i=0;i<(TEXT_WIDTH<<1);i++) WriteDATA(0xFF); location = GRAPHICS_MEMORY_ADDR + (TEXT_WIDTH * 18) + 30; for (i=18;i<MENU_LINE-2;i++) { location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA(0x0C); } location = GRAPHICS_MEMORY_ADDR + (TEXT_WIDTH * MENU_LINE); for (i=MENU_LINE;i<201;i++) { WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA(0x0C); location += 10; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA(0x8C); location += 10; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA(0x8C); location += 10; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA(0x8C); location += 10; } location = GRAPHICS_MEMORY_ADDR + (TEXT_WIDTH * 190) + 39; for (i=190;i<201;i++) { location += TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); WriteDATA(0x01); } } // highlights line_highlighted by using an XOR operation between layers void highlight(void) { location = GRAPHICS_MEMORY_ADDR + ( (line_highlighted * TEXT_WIDTH)<<3); location -= TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); for (i=0;i<9;i++) { WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); for (j=0;j<TEXT_WIDTH-10;j++) WriteDATA(0xff); location += TEXT_WIDTH; } } // unhighlights the line unhighlight void unHighlight(unsigned char unhighlight) { location = GRAPHICS_MEMORY_ADDR + ( (unhighlight * TEXT_WIDTH)<<3); location -= TEXT_WIDTH; WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); for (i=0;i<9;i++) { WriteCMD(CSRW); WriteDATA(location); WriteDATA(location>>8); WriteCMD(MWRITE); for (j=0;j<TEXT_WIDTH-10;j++) WriteDATA(0x00); location += TEXT_WIDTH; } } // LCD initialization commands, see datasheet for details void initLCD(void) { //initialize the LCD DDRD = 0xFF; DDRB = 0xFF; PORTD = LCDnop; TCCR0 = 0x02; DELAY1_2(); DELAY1_2(); DELAY1_2(); DELAY1_2(); PORTD = LCDreset; DELAY1_2(); DELAY1_2(); DELAY1_2(); PORTD = LCDnop; DELAY1_2(); DELAY1_2(); DELAY1_2(); DELAY1_2(); WriteCMD(SystemSet); WriteDATA(0x30); WriteDATA(0x87); WriteDATA(0x07); WriteDATA(0x27); WriteDATA(0x2F); WriteDATA(0xC7); WriteDATA(0x28); WriteDATA(0x00); WriteCMD(Overlay); WriteDATA(0x01); WriteCMD(Scroll); WriteDATA(0x00); WriteDATA(0x00); WriteDATA(0xC8); WriteDATA(0xE8); WriteDATA(0x03); WriteDATA(0xC8); WriteCMD(CSRForm); WriteDATA(0x04); WriteDATA(0x86); WriteCMD(CSRRight); WriteCMD(HorzScroll); WriteDATA(0x00); WriteCMD(DispON); WriteDATA(0x14); clearLCD(); WriteCMD(CSRW); WriteDATA(0x0F); WriteDATA(0x00); } void WriteCMD(unsigned char CommandCode) { PORTB = CommandCode; PORTD = CmdSetup; PORTD = CmdWrite; PORTD = CmdSetup; return; } void WriteDATA(unsigned char CommandCode) { PORTB = CommandCode; PORTD = DataSetup; PORTD = DataWrite; PORTD = DataSetup; return; } void clearLCD(void) { unsigned short i; WriteCMD(CSRRight); WriteCMD(CSRW); WriteDATA(0x00); WriteDATA(0x00); WriteCMD(MWRITE); for (i=0; i<1000; i++) WriteDATA(0x20); // write " " to character memory WriteCMD(CSRW); WriteDATA(0xE8); WriteDATA(0x03); WriteCMD(MWRITE); for (i=0; i<8000; i++) WriteDATA(0x00); // erase graphics memory return; } // end clearLCD void DELAY1_2(void) { unsigned char curr; TCNT0 = 0x00; do curr = TCNT0; while(curr < 250); // 250 * 2us = 1/2 ms delay return; } // end DELAY1_2 /************************************************************************************* * Testing * *************************************************************************************/ void testUART(void) { for (i=0;i<r_index_y;i++) { for (j=0;j<TEXT_WIDTH;j++) { if (recipes[i][j] == '\0') break; putchar(recipes[i][j]); } printf("\r\n"); } for (i=0;i<recipe_index;i++) { for (j=0;j<TEXT_WIDTH;j++) { if (recipe_names[i][j] == '\0') break; putchar(recipe_names[i][j]); } printf("\r\n"); printf("%d",recipe_pointers[i]); printf("\r\n"); } printf("\r\n"); } /************************************************************************************* * Main * *************************************************************************************/ void main(void) { MCUCR = 0x80; // enable external ram i = 0; j = 0; t1S = 0; t1M = 0; t1H = 0; t2S = 0; t2M = 0; t2H = 0; // ***** kill when switching to port F DDRE = 0xFF; // UART stuff UCR = 0b10011000; UBRR = 25; printf("\r\nready\r\n"); initLCD(); // setup timer1 to interrupt every second for food timings TCCR1B = 0b00001101; // sets timer1A to prescale /1024 and clear on campare match TCNT1H = 0x00; // clear timer1 TCNT1L = 0x00; OCR1AH = 0x0f; // count up to 3906.25 OCR1AL = 0x42; // setup timer0 to interrupt every 30ms or so to deal with button presses TCCR0 = 0x05; // prescaler = /128 TCNT0 = reload; TIMSK = 0x11; // enable timer1A compare interrupt and timer0 overflow #asm sei #endasm while (1) { if ( screenstate != lastscreenstate ) { //testUART(); lastscreenstate = screenstate; if (screenstate == _mainmenu) displayMainMenu(); else if (screenstate == _optionsmenu) displayOptionsMenu(); else if (screenstate == _selectrecipesforshoppinglist) displayListCreator(); else if (screenstate == _shoppinglist) displayShoppingList(); else if (screenstate == _selectrecipe) displayRecipeList(); else if (screenstate == _cooking) showRecipe(); else printf("Unknown Screen State"); } if (timersUpdated == 1) { timersUpdated = 0; updateTimers(); } } }