Advertisement
Guest User

Untitled

a guest
Aug 22nd, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.91 KB | None | 0 0
  1. /***************************************************************************************
  2. Name : LCD Button Shield Menu
  3. Author : Paul Siewert
  4. Created : June 14, 2016
  5. Last Modified: June 14, 2016
  6. Version : 1.0
  7. Notes : This code is for use with an Arduino Uno and LCD/button shield. The
  8. intent is for anyone to use this program to give them a starting
  9. program with a fully functional menu with minimal modifications
  10. required by the user.
  11. License : This program is free software. You can redistribute it and/or modify
  12. it under the terms of the GNU General Public License as published by
  13. the Free Software Foundation, either version 3 of the License, or
  14. (at your option) any later version.
  15. This program is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. GNU General Public License for more details.
  19. ***************************************************************************************/
  20. /*
  21. This program is designed to get you as close as possible to a finished menu for the standard Arduino Uno LCD/button shield. The only required modifications
  22. are to add as menu items to the master menu (menuItems array) and then modify/adjust the void functions below for each of those selections.
  23. */
  24.  
  25. // You can have up to 10 menu items in the menuItems[] array below without having to change the base programming at all. Name them however you'd like. Beyond 10 items, you will have to add additional "cases" in the switch/case
  26. // section of the operateMainMenu() function below. You will also have to add additional void functions (i.e. menuItem11, menuItem12, etc.) to the program.
  27. String menuItems[] = {"ITEM 1", "ITEM 2", "ITEM 3"};
  28. String subMenuItems[][] = {
  29. {"I1 Sub1", "I1 Sub2"},
  30. {"I2 Sub1", "I2 Sub2"},
  31. {"I3 Sub1", "I3 Sub2"}
  32. };
  33.  
  34. // Navigation button variables
  35. int readKey;
  36. int savedDistance = 0;
  37.  
  38. // Menu control variables
  39. int menuPage = 0;
  40. int maxMenuPages = round(((sizeof(menuItems) / sizeof(String)) / 2) + .5);
  41. int cursorPosition = 0;
  42.  
  43. int subMenuPage = 0;
  44. int maxSubMenuPages(menu) {
  45. return round(((sizeof(subMenuItems[menu]) / sizeof(String)) / 2) + .5);
  46. }
  47. int subCursorPosition = 0;
  48. int subMenu = -1;
  49.  
  50. // Creates 3 custom characters for the menu display
  51. byte downArrow[8] = {
  52. 0b00100, // *
  53. 0b00100, // *
  54. 0b00100, // *
  55. 0b00100, // *
  56. 0b00100, // *
  57. 0b10101, // * * *
  58. 0b01110, // ***
  59. 0b00100 // *
  60. };
  61.  
  62. byte upArrow[8] = {
  63. 0b00100, // *
  64. 0b01110, // ***
  65. 0b10101, // * * *
  66. 0b00100, // *
  67. 0b00100, // *
  68. 0b00100, // *
  69. 0b00100, // *
  70. 0b00100 // *
  71. };
  72.  
  73. byte menuCursor[8] = {
  74. B01000, // *
  75. B00100, // *
  76. B00010, // *
  77. B00001, // *
  78. B00010, // *
  79. B00100, // *
  80. B01000, // *
  81. B00000 //
  82. };
  83.  
  84. #include <Wire.h>
  85. #include <LiquidCrystal.h>
  86.  
  87. // Setting the LCD shields pins
  88. LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
  89.  
  90. void setup() {
  91.  
  92. // Initializes serial communication
  93. Serial.begin(9600);
  94.  
  95. // Initializes and clears the LCD screen
  96. lcd.begin(16, 2);
  97. lcd.clear();
  98.  
  99. // Creates the byte for the 3 custom characters
  100. lcd.createChar(0, menuCursor);
  101. lcd.createChar(1, upArrow);
  102. lcd.createChar(2, downArrow);
  103. }
  104.  
  105. void loop() {
  106. if(subMenu == -1) {
  107. mainMenuDraw();
  108. drawCursor();
  109. operateMainMenu();
  110. } else {
  111. subMenuDraw(subMenu);
  112. drawCursor();
  113. operateSubMenu();
  114. }
  115. }
  116.  
  117. // This function will generate the 2 menu items that can fit on the screen. They will change as you scroll through your menu. Up and down arrows will indicate your current menu position.
  118. void mainMenuDraw() {
  119. Serial.print(menuPage);
  120. lcd.clear();
  121. lcd.setCursor(1, 0);
  122. lcd.print(menuItems[menuPage]);
  123. lcd.setCursor(1, 1);
  124. lcd.print(menuItems[menuPage + 1]);
  125. if (menuPage == 0) {
  126. lcd.setCursor(15, 1);
  127. lcd.write(byte(2));
  128. } else if (menuPage > 0 and menuPage < maxMenuPages) {
  129. lcd.setCursor(15, 1);
  130. lcd.write(byte(2));
  131. lcd.setCursor(15, 0);
  132. lcd.write(byte(1));
  133. } else if (menuPage == maxMenuPages) {
  134. lcd.setCursor(15, 0);
  135. lcd.write(byte(1));
  136. }
  137. }
  138.  
  139. // When called, this function will erase the current cursor and redraw it based on the cursorPosition and menuPage variables.
  140. void drawCursor() {
  141. for (int x = 0; x < 2; x++) { // Erases current cursor
  142. lcd.setCursor(0, x);
  143. lcd.print(" ");
  144. }
  145.  
  146. // The menu is set up to be progressive (menuPage 0 = Item 1 & Item 2, menuPage 1 = Item 2 & Item 3, menuPage 2 = Item 3 & Item 4), so
  147. // in order to determine where the cursor should be you need to see if you are at an odd or even menu page and an odd or even cursor position.
  148. if (menuPage % 2 == 0) {
  149. if (cursorPosition % 2 == 0) { // If the menu page is even and the cursor position is even that means the cursor should be on line 1
  150. lcd.setCursor(0, 0);
  151. lcd.write(byte(0));
  152. }
  153. if (cursorPosition % 2 != 0) { // If the menu page is even and the cursor position is odd that means the cursor should be on line 2
  154. lcd.setCursor(0, 1);
  155. lcd.write(byte(0));
  156. }
  157. }
  158. if (menuPage % 2 != 0) {
  159. if (cursorPosition % 2 == 0) { // If the menu page is odd and the cursor position is even that means the cursor should be on line 2
  160. lcd.setCursor(0, 1);
  161. lcd.write(byte(0));
  162. }
  163. if (cursorPosition % 2 != 0) { // If the menu page is odd and the cursor position is odd that means the cursor should be on line 1
  164. lcd.setCursor(0, 0);
  165. lcd.write(byte(0));
  166. }
  167. }
  168. }
  169.  
  170.  
  171. void operateMainMenu() {
  172. int activeButton = 0;
  173. while (activeButton == 0) {
  174. int button;
  175. readKey = analogRead(0);
  176. if (readKey < 790) {
  177. delay(100);
  178. readKey = analogRead(0);
  179. }
  180. button = evaluateButton(readKey);
  181. switch (button) {
  182. case 0: // When button returns as 0 there is no action taken
  183. break;
  184. case 1: // This case will execute if the "forward" button is pressed
  185. button = 0;
  186. switch (cursorPosition) { // The case that is selected here is dependent on which menu page you are on and where the cursor is.
  187. case 0:
  188. subMenu = 0;
  189. break;
  190. case 1:
  191. subMenu = 1;
  192. break;
  193. case 2:
  194. subMenu = 2;
  195. break;
  196. case 3:
  197. }
  198. activeButton = 1;
  199. mainMenuDraw();
  200. drawCursor();
  201. break;
  202. case 2:
  203. button = 0;
  204. if (menuPage == 0) {
  205. cursorPosition = cursorPosition - 1;
  206. cursorPosition = constrain(cursorPosition, 0, ((sizeof(menuItems) / sizeof(String)) - 1));
  207. }
  208. if (menuPage % 2 == 0 and cursorPosition % 2 == 0) {
  209. menuPage = menuPage - 1;
  210. menuPage = constrain(menuPage, 0, maxMenuPages);
  211. }
  212.  
  213. if (menuPage % 2 != 0 and cursorPosition % 2 != 0) {
  214. menuPage = menuPage - 1;
  215. menuPage = constrain(menuPage, 0, maxMenuPages);
  216. }
  217.  
  218. cursorPosition = cursorPosition - 1;
  219. cursorPosition = constrain(cursorPosition, 0, ((sizeof(menuItems) / sizeof(String)) - 1));
  220.  
  221. mainMenuDraw();
  222. drawCursor();
  223. activeButton = 1;
  224. break;
  225. case 3:
  226. button = 0;
  227. if (menuPage % 2 == 0 and cursorPosition % 2 != 0) {
  228. menuPage = menuPage + 1;
  229. menuPage = constrain(menuPage, 0, maxMenuPages);
  230. }
  231.  
  232. if (menuPage % 2 != 0 and cursorPosition % 2 == 0) {
  233. menuPage = menuPage + 1;
  234. menuPage = constrain(menuPage, 0, maxMenuPages);
  235. }
  236.  
  237. cursorPosition = cursorPosition + 1;
  238. cursorPosition = constrain(cursorPosition, 0, ((sizeof(menuItems) / sizeof(String)) - 1));
  239. mainMenuDraw();
  240. drawCursor();
  241. activeButton = 1;
  242. break;
  243. }
  244. }
  245. }
  246.  
  247. // This function is called whenever a button press is evaluated. The LCD shield works by observing a voltage drop across the buttons all hooked up to A0.
  248. int evaluateButton(int x) {
  249. int result = 0;
  250. if (x < 50) {
  251. result = 1; // right
  252. } else if (x < 195) {
  253. result = 2; // up
  254. } else if (x < 380) {
  255. result = 3; // down
  256. } else if (x < 790) {
  257. result = 4; // left
  258. }
  259. return result;
  260. }
  261.  
  262. // If there are common usage instructions on more than 1 of your menu items you can call this function from the sub
  263. // menus to make things a little more simplified. If you don't have common instructions or verbage on multiple menus
  264. // I would just delete this void. You must also delete the drawInstructions()function calls from your sub menu functions.
  265. void drawInstructions() {
  266. lcd.setCursor(0, 1); // Set cursor to the bottom line
  267. lcd.print("Use ");
  268. lcd.write(byte(1)); // Up arrow
  269. lcd.print("/");
  270. lcd.write(byte(2)); // Down arrow
  271. lcd.print(" buttons");
  272. }
  273.  
  274. void menuItem1() { // Function executes when you select the 2nd item from main menu
  275. int activeButton = 0;
  276.  
  277. lcd.clear();
  278. lcd.setCursor(3, 0);
  279. lcd.print("Sub Menu 2");
  280.  
  281. while (activeButton == 0) {
  282. int button;
  283. readKey = analogRead(0);
  284. if (readKey < 790) {
  285. delay(100);
  286. readKey = analogRead(0);
  287. }
  288. button = evaluateButton(readKey);
  289. switch (button) {
  290. case 4: // This case will execute if the "back" button is pressed
  291. button = 0;
  292. activeButton = 1;
  293. break;
  294. }
  295. }
  296. }
  297.  
  298. void menuItem2() { // Function executes when you select the 2nd item from main menu
  299. int activeButton = 0;
  300.  
  301. lcd.clear();
  302. lcd.setCursor(3, 0);
  303. lcd.print("Sub Menu 2");
  304.  
  305. while (activeButton == 0) {
  306. int button;
  307. readKey = analogRead(0);
  308. if (readKey < 790) {
  309. delay(100);
  310. readKey = analogRead(0);
  311. }
  312. button = evaluateButton(readKey);
  313. switch (button) {
  314. case 4: // This case will execute if the "back" button is pressed
  315. button = 0;
  316. activeButton = 1;
  317. break;
  318. }
  319. }
  320. }
  321.  
  322. void menuItem3() { // Function executes when you select the 3rd item from main menu
  323. int activeButton = 0;
  324.  
  325. lcd.clear();
  326. lcd.setCursor(3, 0);
  327. lcd.print("Sub Menu 3");
  328.  
  329. while (activeButton == 0) {
  330. int button;
  331. readKey = analogRead(0);
  332. if (readKey < 790) {
  333. delay(100);
  334. readKey = analogRead(0);
  335. }
  336. button = evaluateButton(readKey);
  337. switch (button) {
  338. case 4: // This case will execute if the "back" button is pressed
  339. button = 0;
  340. activeButton = 1;
  341. break;
  342. }
  343. }
  344. }
  345.  
  346.  
  347. void subMenuDraw() {
  348. Serial.print(subMenuPage);
  349. lcd.clear();
  350. lcd.setCursor(1, 0);
  351. lcd.print(menuItems[subMenu][subMenuPage]);
  352. lcd.setCursor(1, 1);
  353. lcd.print(menuItems[subMenu][subMenuPage + 1]);
  354. if (subMenuPage == 0) {
  355. lcd.setCursor(15, 1);
  356. lcd.write(byte(2));
  357. } else if (subMenuPage > 0 and subMenuPage < maxSubMenuPages) {
  358. lcd.setCursor(15, 1);
  359. lcd.write(byte(2));
  360. lcd.setCursor(15, 0);
  361. lcd.write(byte(1));
  362. } else if (subMenuPage == maxSubMenuPages) {
  363. lcd.setCursor(15, 0);
  364. lcd.write(byte(1));
  365. }
  366. }
  367.  
  368. // When called, this function will erase the current cursor and redraw it based on the cursorPosition and subMenuPage variables.
  369. void drawCursor() {
  370. for (int x = 0; x < 2; x++) { // Erases current cursor
  371. lcd.setCursor(0, x);
  372. lcd.print(" ");
  373. }
  374.  
  375. // The menu is set up to be progressive (subMenuPage 0 = Item 1 & Item 2, subMenuPage 1 = Item 2 & Item 3, subMenuPage 2 = Item 3 & Item 4), so
  376. // in order to determine where the cursor should be you need to see if you are at an odd or even menu page and an odd or even cursor position.
  377. if (subMenuPage % 2 == 0) {
  378. if (cursorPosition % 2 == 0) { // If the menu page is even and the cursor position is even that means the cursor should be on line 1
  379. lcd.setCursor(0, 0);
  380. lcd.write(byte(0));
  381. }
  382. if (cursorPosition % 2 != 0) { // If the menu page is even and the cursor position is odd that means the cursor should be on line 2
  383. lcd.setCursor(0, 1);
  384. lcd.write(byte(0));
  385. }
  386. }
  387. if (subMenuPage % 2 != 0) {
  388. if (cursorPosition % 2 == 0) { // If the menu page is odd and the cursor position is even that means the cursor should be on line 2
  389. lcd.setCursor(0, 1);
  390. lcd.write(byte(0));
  391. }
  392. if (cursorPosition % 2 != 0) { // If the menu page is odd and the cursor position is odd that means the cursor should be on line 1
  393. lcd.setCursor(0, 0);
  394. lcd.write(byte(0));
  395. }
  396. }
  397. }
  398.  
  399.  
  400. void operateSubMenu() {
  401. int activeButton = 0;
  402. while (activeButton == 0) {
  403. int button;
  404. readKey = analogRead(0);
  405. if (readKey < 790) {
  406. delay(100);
  407. readKey = analogRead(0);
  408. }
  409. button = evaluateButton(readKey);
  410. switch (button) {
  411. case 0: // When button returns as 0 there is no action taken
  412. break;
  413. case 1: // This case will execute if the "forward" button is pressed
  414. button = 0;
  415. switch (cursorPosition) { // The case that is selected here is dependent on which menu page you are on and where the cursor is.
  416. case 0:
  417. menuItem1();
  418. break;
  419. case 1:
  420. menuItem2();
  421. break;
  422. case 2:
  423. menuItem3();
  424. break;
  425. }
  426. activeButton = 1;
  427. mainMenuDraw();
  428. drawCursor();
  429. break;
  430. case 2:
  431. button = 0;
  432. if (subMenuPage == 0) {
  433. cursorPosition = cursorPosition - 1;
  434. cursorPosition = constrain(cursorPosition, 0, ((sizeof(menuItems) / sizeof(String)) - 1));
  435. }
  436. if (subMenuPage % 2 == 0 and cursorPosition % 2 == 0) {
  437. subMenuPage = subMenuPage - 1;
  438. subMenuPage = constrain(subMenuPage, 0, maxSubMenuPages);
  439. }
  440.  
  441. if (subMenuPage % 2 != 0 and cursorPosition % 2 != 0) {
  442. subMenuPage = subMenuPage - 1;
  443. subMenuPage = constrain(subMenuPage, 0, maxSubMenuPages);
  444. }
  445.  
  446. cursorPosition = cursorPosition - 1;
  447. cursorPosition = constrain(cursorPosition, 0, ((sizeof(menuItems) / sizeof(String)) - 1));
  448.  
  449. subMenuDraw();
  450. drawCursor();
  451. activeButton = 1;
  452. break;
  453. case 3:
  454. button = 0;
  455. if (subMenuPage % 2 == 0 and cursorPosition % 2 != 0) {
  456. subMenuPage = subMenuPage + 1;
  457. subMenuPage = constrain(subMenuPage, 0, maxSubMenuPages);
  458. }
  459.  
  460. if (subMenuPage % 2 != 0 and cursorPosition % 2 == 0) {
  461. subMenuPage = subMenuPage + 1;
  462. subMenuPage = constrain(subMenuPage, 0, maxSubMenuPages);
  463. }
  464.  
  465. cursorPosition = cursorPosition + 1;
  466. cursorPosition = constrain(cursorPosition, 0, ((sizeof(menuItems) / sizeof(String)) - 1));
  467. subMenuDraw();
  468. drawCursor();
  469. activeButton = 1;
  470. break;
  471. }
  472. }
  473. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement