Display SSD1306 for ESP32
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

808 lines
28 KiB

  1. #include <SPI.h>
  2. #include <Wire.h>
  3. #include <Adafruit_GFX.h>
  4. #include <Adafruit_SSD1306.h>
  5. #define __DEBUG__
  6. //The following constants are used to configure the behaviour of the interface
  7. // MAX_OPTIONS defines the maximum number of options a menu can hold
  8. // MAX_MENUS declares the maximum number of menu screens in the interface
  9. // MAX_GRAPHS is the maximum number of graphs to create
  10. // DISP_WIDTH and DISP_HEIGHT are hardware specific (SSD1306)
  11. // REFRESH: is the time in miliseconds the interface will take in refreshing (this time affects the loop, keep that in mind)
  12. #define MAX_OPTIONS 10 //Maximum number of options for each menu
  13. #define MAX_MENUS 3
  14. #define MAX_GRAPHS 3
  15. #define MAX_MODIFIERS 3
  16. #define DISP_WIDTH 128 // OLED display width
  17. #define DISP_HEIGHT 64 // OLED display height
  18. #define REFRESH 10 //Refresh time in ms
  19. #define ADDRESS 0x3C //I2C address of the display
  20. Adafruit_SSD1306 display(DISP_WIDTH, DISP_HEIGHT, &Wire, -1);
  21. class Option{
  22. private:
  23. int sizex; //Defines the size it will occupy in the x axis (width), this value is gotten from the menu
  24. int sizey; //Defines the height of the option (this value is gotten from the menu it belongs to)
  25. String content; //Text of the option
  26. int pos; //Defines the position it has in the menu
  27. int textSpacing; //According to the height, defines the space for the text, so that it's vertically centered
  28. bool fill = false; //In case an option is not selected this should be false
  29. bool disp = false; //In case an option is not configured, it should be false and, thus hidden
  30. int destinationType; //Defines what the option leads to (another menu, graph, something else)
  31. int destinationIndex; //Defines where the option leads to (index of the destination)
  32. public:
  33. //Option(){}
  34. //Method to configure an option, all attributes are assigned, and disp is true, so the option can be displayed
  35. void configure(String content, int sizex, int sizey, int pos, int destinationType, int destinationIndex){
  36. this->sizex = sizex;
  37. this->sizey = sizey;
  38. this->content = content;
  39. this->pos = pos;
  40. this->destinationType = destinationType;
  41. this->destinationIndex = destinationIndex;
  42. this->disp = true;
  43. this->textSpacing = ((sizey - 7)/2) + 7;
  44. }
  45. int getDestinationType(){
  46. int destinationType = this->destinationType;
  47. return destinationType;
  48. }
  49. int getDestinationIndex(){
  50. int destinationIndex = this->destinationIndex;
  51. return destinationIndex;
  52. }
  53. //This method draws each option
  54. void drawopt(int page, int pos, int optPPage){
  55. if(this->disp){ //Checks if the option was configured and, as a result, is displayable
  56. if(this->pos == pos){ //If the position of the option corresponds to the position passed to the function, then it should be selected
  57. display.fillRect(0, (this->sizey)*(this->pos) + 1 - (page*optPPage*this->sizey), this->sizex, this->sizey, WHITE);
  58. display.setTextColor(SSD1306_BLACK);
  59. display.setCursor(5, (this->sizey)*(this->pos + 1) - (page*optPPage*this->sizey) - this->textSpacing);
  60. display.print(this->content);
  61. display.setTextColor(SSD1306_WHITE);
  62. }
  63. else{ //If the option is not selected, the rectangle containing it shouldn't be filled
  64. display.drawRect(0, (this->sizey)*(this->pos) + 1 - (page*optPPage*this->sizey), this->sizex, this->sizey, WHITE);
  65. display.setCursor(5, (this->sizey)*(this->pos + 1) - (page*optPPage*this->sizey) - this->textSpacing);
  66. display.print(this->content);
  67. }
  68. }
  69. }
  70. };
  71. class Menu{ //ContentType (0)
  72. private:
  73. int sizex; //X size for each option in the menu
  74. int sizey; //Y size of each option in the menu
  75. int options = 0; //This indicates the number of options created
  76. int pos = 0; //This indicates the position of the cursor
  77. int page = 0; //If the menu is too long, this indicates the page that is being displayed
  78. Option opt[MAX_OPTIONS];
  79. int optPPage;
  80. int previousScreen = 0;
  81. int previousContentType = 0;
  82. public:
  83. void configure(int sizex, int sizey){ //This method configures the menu created from Screen
  84. this->sizex = sizex;
  85. this->sizey = sizey;
  86. this->optPPage = DISP_HEIGHT / this->sizey;
  87. }
  88. //The following method is used to created an option for the menu
  89. void createOption(String content, int destinationType, int destinationIndex){
  90. //The option takes the place in the array defined by the options number variable (options), which is later increased.
  91. this->opt[this->options].configure(content, this->sizex, this->sizey, this->options++, destinationType, destinationIndex);
  92. }
  93. int extractDestinationType(){
  94. int destinationType = this->opt[this->pos].getDestinationType();
  95. return destinationType;
  96. }
  97. int extractDestinationIndex(){
  98. int destinationIndex = this->opt[this->pos].getDestinationIndex();
  99. return destinationIndex;
  100. }
  101. //The following method draws the whole menu by drawing every option configured within it
  102. void drawMenu(){
  103. display.clearDisplay();
  104. this->page = pos/this->optPPage; //The current page is obtained by dividing the position by the number of options per page (only integer)
  105. for(int i = 0; i < options; i++){
  106. this->opt[i].drawopt(this->page, this->pos, this->optPPage);
  107. }
  108. display.display();
  109. }
  110. //Methods used by Screen
  111. int extractPos(){ //Gets the current position of the cursor
  112. return(this->pos);
  113. }
  114. int extractOptNumber(){ //Gets the number of options in the menu
  115. return(this->options);
  116. }
  117. void increasePos(){ //Increases the position of the cursor
  118. this->pos++;
  119. }
  120. void decreasePos(){ //Decreases the position of the cursor
  121. this->pos--;
  122. }
  123. //Both of the following methods store the values of the previous screen passed as parameters by Screen
  124. void setPreviousScreen(int prev){
  125. this->previousScreen = prev;
  126. }
  127. void setPreviousContentType(int prev){
  128. this->previousContentType = prev;
  129. }
  130. //Both of the following methods retrieve the values of the screen previous to the menu containing these data.
  131. int getPreviousScreen(){
  132. int prev = this->previousScreen;
  133. return prev;
  134. }
  135. int getPreviousContentType(){
  136. int prev = this->previousContentType;
  137. return prev;
  138. }
  139. };
  140. class Graph{ //ContentType (1)
  141. private:
  142. String title;
  143. char graphType; //'a' Vertical Bar, 'b' Horizontal Bar, 'c' Cartesian Graph
  144. //Assign whatever value in "configure(..." if a parameter is not required for the specified graphType
  145. double value; //For: Vertical Bar Horizontal Bar Cartesian
  146. double xpos; //For: Vertical Bar Horizontal Bar Cartesian
  147. double ypos; //For: Vertical Bar Horizontal Bar Cartesian
  148. double height; //For: Vertical Bar Horizontal Bar Cartesian
  149. double width; //For: Vertical Bar Horizontal Bar Cartesian
  150. double yminimum; //For: Vertical Bar Cartesian
  151. double ymaximum; //For: Vertical Bar Cartesian
  152. double xminimum; //For: Horizontal Bar Cartesian
  153. double xmaximum; //For: Horizontal Bar Cartesian
  154. double yStepSize; //For: Vertical Bar Cartesian
  155. double xStepSize; //For: Horizontal Bar Cartesian
  156. int digit; //For: Vertical Bar Horizontal Bar Cartesian
  157. double x;
  158. double yrange;
  159. double xrange;
  160. double ox;
  161. double oy;
  162. double count;
  163. double graphScale;
  164. bool redraw = true;
  165. int previousScreen = 0;
  166. int previousContentType = 0;
  167. public:
  168. //This method configures the graph created, defines its parameters according the type of graph selected.
  169. void configure(String title, char graphType, double xpos, double ypos, double width, double height,
  170. double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, int digit){
  171. this->title = title;
  172. this->graphType = graphType;
  173. this->yminimum = yminimum;
  174. this->ymaximum = ymaximum;
  175. this->xminimum = xminimum;
  176. this->count = xminimum;
  177. this->xmaximum = xmaximum;
  178. this->height = height;
  179. this->width = width;
  180. this->yStepSize = yStepSize;
  181. this->xStepSize = xStepSize;
  182. this->digit = digit;
  183. this->xpos = xpos;
  184. this->ypos = ypos;
  185. switch(graphType){
  186. case 'a':
  187. this->yrange = ymaximum - yminimum;
  188. this->graphScale = (yStepSize) * (height / this->yrange) - .001; //Adjusts the scale of the graph, according to the range and the size of the step
  189. break;
  190. case 'b':
  191. this->xrange = xmaximum - xminimum;
  192. this->graphScale = (xStepSize) * (width / this->xrange) - .001; //Adjusts the scale of the graph, according to the range and the size of the step
  193. break;
  194. case 'c':
  195. this->yrange = ymaximum - yminimum;
  196. this->xrange = xmaximum - xminimum;
  197. break;
  198. }
  199. }
  200. void drawGraph(){
  201. double level, data, i;
  202. switch(graphType){
  203. case 'a':
  204. double my;
  205. if (this->redraw) { //Prints the labels
  206. display.clearDisplay();
  207. this->redraw = false;
  208. display.fillRect(0, 0, 127 , 14, SSD1306_WHITE);
  209. display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
  210. display.setTextSize(1);
  211. display.setCursor(2, 4);
  212. display.println(this->title);
  213. for (i = 0; i <= this->height; i += this->graphScale) {
  214. my = this->ypos - this->height + i;
  215. display.drawFastHLine(this->xpos + this->width + 1, my, 5, SSD1306_WHITE);
  216. // draw lables
  217. display.setTextSize(1);
  218. display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
  219. display.setCursor(this->xpos + this->width + 12, my - 3 );
  220. data = this->ymaximum - ( i * (this->yStepSize / this->graphScale));
  221. display.print(data, this->digit);
  222. }
  223. }
  224. // compute level of bar graph that is scaled to the height and the hi and low vals
  225. // this is needed to accompdate for +/- range
  226. level = (this->height * (((this->value - this->yminimum) / (this->yrange))));
  227. // draw the bar graph
  228. // write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update
  229. display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE);
  230. display.fillRect(this->xpos, this->ypos - this->height, this->width, this->height - level, SSD1306_BLACK);
  231. display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE);
  232. display.fillRect(this->xpos, this->ypos - level, this->width, level, SSD1306_WHITE);
  233. // up until now print sends data to a video buffer NOT the screen
  234. // this call sends the data to the screen
  235. display.display();
  236. break;
  237. case 'b':
  238. if (this->redraw) {
  239. display.clearDisplay();
  240. this->redraw = false;
  241. display.fillRect(0, 0, 127 , 16, SSD1306_WHITE);
  242. display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
  243. display.setTextSize(1);
  244. display.setCursor(2, 4);
  245. display.println(this->title);
  246. // draw the text
  247. for (i = 0; i <= this->width; i += this->graphScale) {
  248. display.drawFastVLine(i + this->xpos , this->ypos , 5, SSD1306_WHITE);
  249. // draw lables
  250. display.setTextSize(1);
  251. display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
  252. display.setCursor(i + this->xpos , this->ypos + 10);
  253. // addling a small value to eliminate round off errors
  254. // this val may need to be adjusted
  255. data = ( i * (this->xStepSize / this->graphScale)) + this->xminimum + 0.00001;
  256. display.print(data, this->digit);
  257. }
  258. }
  259. // compute level of bar graph that is scaled to the width and the hi and low vals
  260. // this is needed to accompdate for +/- range capability
  261. // draw the bar graph
  262. // write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update
  263. level = (this->width * (((this->value - this->xminimum) / (this->xmaximum - this->xminimum))));
  264. display.fillRect(this->xpos + level, this->ypos - this->height, this->width - level, this->height, SSD1306_BLACK);
  265. display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE);
  266. display.fillRect(this->xpos, this->ypos - this->height, level, this->height, SSD1306_WHITE);
  267. // up until now print sends data to a video buffer NOT the screen
  268. // this call sends the data to the screen
  269. display.display();
  270. break;
  271. case 'c':
  272. double temp;
  273. if (this->redraw == true) {
  274. this->redraw = false;
  275. display.clearDisplay();
  276. display.fillRect(0, 0, 127 , 16, SSD1306_WHITE);
  277. display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
  278. display.setTextSize(1);
  279. display.setCursor(2, 4);
  280. display.println(title);
  281. this->ox = (this->count - this->xminimum) * (this->width) / (this->xrange) + this->xpos;
  282. this->oy = (this->value - this->yminimum) * (- this->height) / (this->yrange) + this->ypos;
  283. // draw y scale
  284. display.setTextSize(1);
  285. display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
  286. for ( i = this->yminimum; i <= this->ymaximum; i += this->yStepSize) {
  287. // compute the transform
  288. // note my transform funcition is the same as the map function, except the map uses long and we need doubles
  289. temp = (i - this->yminimum) * (- this->height) / (this->ymaximum - this->yminimum) + this->ypos;
  290. if (i == 0) {
  291. display.drawFastHLine(this->xpos - 3, temp, this->width + 3, SSD1306_WHITE);
  292. }
  293. else {
  294. display.drawFastHLine(this->xpos - 3, temp, 3, SSD1306_WHITE);
  295. }
  296. display.setCursor(this->xpos - 27, temp - 3);
  297. display.println(i, this->digit);
  298. }
  299. // draw x scale
  300. for (i = this->xminimum; i <= this->xmaximum; i += this->xStepSize) {
  301. // compute the transform
  302. display.setTextSize(1);
  303. display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
  304. temp = (i - this->xminimum) * (this->width) / (this->xrange) + this->xpos;
  305. if (i == 0) {
  306. display.drawFastVLine(temp, this->ypos - this->height, this->height + 3, SSD1306_WHITE);
  307. }
  308. else {
  309. display.drawFastVLine(temp, this->ypos, 3, SSD1306_WHITE);
  310. }
  311. display.setCursor(temp, this->ypos + 6);
  312. display.println(i, this->digit);
  313. }
  314. }
  315. // graph drawn now plot the data
  316. // the entire plotting code are these few lines...
  317. this->x = (this->count - this->xminimum) * (this->width) / (this->xrange) + this->xpos;
  318. this->value = (this->value - this->yminimum) * (- this->height) / (this->yrange) + this->ypos;
  319. display.drawLine(this->ox, this->oy, this->x, this->value, SSD1306_WHITE);
  320. display.drawLine(this->ox, this->oy - 1, this->x, this->value - 1, SSD1306_WHITE);
  321. this->ox = this->x;
  322. this->oy = this->value;
  323. // up until now print sends data to a video buffer NOT the screen
  324. // this call sends the data to the screen
  325. display.display();
  326. this->count += 1;
  327. if(this->ox >= (this->xpos + this->width)){
  328. this->redraw = true;
  329. this->count = xminimum;
  330. }
  331. }
  332. }
  333. void redrawFlag(){ // Activates the redraw bool to get the graph printed correctly
  334. this->redraw = true;
  335. }
  336. void setPreviousScreen(int prev){
  337. this->previousScreen = prev;
  338. }
  339. void setPreviousContentType(int prev){
  340. this->previousContentType = prev;
  341. }
  342. int getPreviousScreen(){
  343. int prev = this->previousScreen;
  344. return prev;
  345. }
  346. int getPreviousContentType(){
  347. int prev = this->previousContentType;
  348. return prev;
  349. }
  350. void assignValue(double value){
  351. this->value = value;
  352. }
  353. void reset(){
  354. this->x = 0;
  355. }
  356. };
  357. class Modifier{ //ContentType (2)
  358. private:
  359. String title;
  360. int *value;
  361. int max;
  362. int min;
  363. int step;
  364. int previousScreen = 0;
  365. int previousContentType = 0;
  366. public:
  367. void configure(String title, int *value, int max, int min, int step){
  368. this->title = title;
  369. this->value = value;
  370. this->max = max;
  371. this->min = min;
  372. this->step = step;
  373. }
  374. void drawModifier(){
  375. display.clearDisplay();
  376. display.fillRect(0, 0, 127 , 16, SSD1306_WHITE);
  377. display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
  378. display.setTextSize(1);
  379. display.setCursor(2, 4);
  380. display.println(this->title);
  381. display.setTextColor(SSD1306_WHITE);
  382. display.setTextSize(3);
  383. display.setCursor(2, ((DISP_HEIGHT - 16 - 15)/2) + 16);
  384. display.println(*this->value);
  385. display.display();
  386. display.setTextSize(1);
  387. }
  388. void increaseValue(){
  389. if((*this->value + this->step) <= this->max){
  390. *this->value += this->step;
  391. }
  392. }
  393. void decreaseValue(){
  394. if((*this->value - this->step) >= this->min){
  395. *this->value -= this->step;
  396. }
  397. }
  398. void setPreviousScreen(int prev){
  399. this->previousScreen = prev;
  400. }
  401. void setPreviousContentType(int prev){
  402. this->previousContentType = prev;
  403. }
  404. int getPreviousScreen(){
  405. int prev = this->previousScreen;
  406. return prev;
  407. }
  408. int getPreviousContentType(){
  409. int prev = this->previousContentType;
  410. return prev;
  411. }
  412. };
  413. class Screen{
  414. private:
  415. Menu menu[MAX_MENUS]; //Array of menus to use
  416. Graph graph[MAX_GRAPHS]; //Array of graphs to use
  417. Modifier modifier[MAX_MODIFIERS]; //Array of modifiers to use
  418. int counterM = 0; //Number of menus created
  419. int counterG = 0; //Number of graphs created
  420. int counterMod = 0;
  421. bool redraw = true; //Redraw interface for when there is a change of screen
  422. int currentScreen = 0;
  423. int contentType = 0;
  424. public:
  425. void configure(bool fullsetting){ //This method allows the configuration of the display when the parameter is true. Otherwise only prints a greeting message.
  426. if(fullsetting){
  427. //Adafruit_SSD1306 display(DISP_WIDTH, DISP_HEIGHT, &Wire, -1);
  428. Serial.begin(115200);
  429. if (!display.begin(SSD1306_SWITCHCAPVCC, ADDRESS)) {
  430. #ifdef __DEBUG__
  431. Serial.println("Display not found!");
  432. #endif
  433. while (true);
  434. }
  435. }
  436. display.clearDisplay();
  437. // Text size
  438. display.setTextSize(2);
  439. // Text color
  440. display.setTextColor(SSD1306_WHITE);
  441. // Text position
  442. display.setCursor(25, 20);
  443. display.println("Welcome");
  444. display.setTextSize(1);
  445. display.display();
  446. delay(5000);
  447. }
  448. void createMenu(int sizex, int sizey){ //This method is used for the creation of a menu
  449. this->menu[counterM].configure(sizex, sizey);
  450. this->counterM++;
  451. }
  452. void createOption(int menuIndex, String content, int destinationType, int destinationIndex){ //this method should be used for creating an option in a menu
  453. this->menu[menuIndex].createOption(content, destinationType, destinationIndex);
  454. }
  455. void createVGraph(String title, double xpos, double ypos, double width, double height,
  456. double yminimum, double ymaximum, double yStepSize, int digit){ //this method calls the configure() of graph for a vertical graph
  457. this->graph[counterG].configure(title, 'a', xpos, ypos, width, height, yminimum, ymaximum, 0, 0, yStepSize, 0, digit);
  458. this->counterG++;
  459. }
  460. void createHGraph(String title, double xpos, double ypos, double width, double height,
  461. double xminimum, double xmaximum, double xStepSize, int digit){ //this method calls the configure() of graph for a horizontal graph
  462. this->graph[counterG].configure(title, 'b', xpos, ypos, width, height, 0, 0, xminimum, xmaximum, 0, xStepSize, digit);
  463. counterG++;
  464. }
  465. void createCGraph(String title, double xpos, double ypos, double width, double height,
  466. double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, int digit){ //this method calls the configure() of graph for a cartesian chart
  467. this->graph[counterG].configure(title, 'c', xpos, ypos, width, height, yminimum, ymaximum, xminimum, xmaximum, yStepSize, xStepSize, digit);
  468. counterG++;
  469. }
  470. void createModifier(String title, int *value, int max, int min, int step){ //This method is used for the creation of a menu
  471. this->modifier[counterMod].configure(title, value, max, min, step);
  472. this->counterMod++;
  473. }
  474. /*
  475. void redrawFlag(){
  476. this->redraw = true;
  477. }
  478. */
  479. //The following method is used for assingning a value to a graph
  480. //This can be avoided using pointers to the variable to plot in the graph
  481. void graphAssignValue(int graphIndex, double value){
  482. this->graph[graphIndex].assignValue(value);
  483. if(this->currentScreen == graphIndex && this->contentType == 1)
  484. this->redraw = true;
  485. }
  486. //This method controls the whole interface, it needs to be called within a loop
  487. void control(){
  488. if (redraw){
  489. if (contentType == 0){
  490. menu[currentScreen].drawMenu();
  491. }
  492. else if (contentType == 1){
  493. graph[currentScreen].drawGraph();
  494. }
  495. else if (contentType == 2){
  496. modifier[currentScreen].drawModifier();
  497. }
  498. this->redraw = false;
  499. }
  500. }
  501. //The following two methods allow the change in position of the cursor
  502. void increasePos(){
  503. if(this->menu[this->currentScreen].extractPos() < this->menu[this->currentScreen].extractOptNumber() - 1)
  504. this->menu[this->currentScreen].increasePos();
  505. }
  506. void decreasePos(){
  507. if(this->menu[this->currentScreen].extractPos() > 0)
  508. this->menu[this->currentScreen].decreasePos();
  509. }
  510. //This method lets the user go into another screen by selecting an option
  511. void goTo(){
  512. if(this->contentType == 0){
  513. int newScreen = this->menu[this->currentScreen].extractDestinationIndex();
  514. int newContentType = this->menu[this->currentScreen].extractDestinationType();
  515. if (newContentType == 0){
  516. this->menu[newScreen].setPreviousScreen(this->currentScreen);
  517. this->menu[newScreen].setPreviousContentType(this->contentType);
  518. }
  519. else if(newContentType == 1){
  520. this->graph[newScreen].setPreviousScreen(this->currentScreen);
  521. this->graph[newScreen].setPreviousContentType(this->contentType);
  522. this->graph[newScreen].reset();
  523. this->graph[newScreen].redrawFlag();
  524. }
  525. else if(newContentType == 2){
  526. this->modifier[newScreen].setPreviousScreen(this->currentScreen);
  527. this->modifier[newScreen].setPreviousContentType(this->contentType);
  528. }
  529. this->contentType = newContentType;
  530. this->currentScreen = newScreen;
  531. this->redraw = true;
  532. }
  533. }
  534. void goBack(){
  535. if(contentType == 0){
  536. //Gets indexes from previous screen saved in actual screen if it is a menu, and sets them as the current indexes
  537. this->currentScreen = this->menu[this->currentScreen].getPreviousScreen();
  538. this->contentType = this->menu[this->currentScreen].getPreviousContentType();
  539. }
  540. else if(contentType == 1){
  541. //Gets indexes from previous screen saved in actual screen if it is a graph, and sets them as the current indexes
  542. this->currentScreen = this->graph[this->currentScreen].getPreviousScreen();
  543. this->contentType = this->graph[this->currentScreen].getPreviousContentType();
  544. }
  545. else if(contentType == 2){
  546. this->currentScreen = this->modifier[this->currentScreen].getPreviousScreen();
  547. this->contentType = this->modifier[this->currentScreen].getPreviousContentType();
  548. }
  549. this->redraw = true;
  550. }
  551. //These methods control the plus and minus button actions
  552. void plusAction(){
  553. if(contentType == 0){
  554. increasePos();
  555. }
  556. else if(contentType == 2){
  557. this->modifier[currentScreen].increaseValue();
  558. }
  559. this->redraw = true;
  560. }
  561. void minusAction(){
  562. if(contentType == 0){
  563. decreasePos();
  564. }
  565. else if(contentType == 2){
  566. this->modifier[currentScreen].decreaseValue();
  567. }
  568. this->redraw = true;
  569. }
  570. };
  571. class Keyboard{
  572. private:
  573. byte goTo;
  574. byte goBack;
  575. byte plus;
  576. byte minus;
  577. byte debounceTime;
  578. Screen *screen;
  579. public:
  580. //Keyboard constructor
  581. Keyboard(byte goTo, byte goBack, byte plus, byte minus, byte debounceTime, Screen * screen){
  582. this->goTo = goTo;
  583. this->goBack = goBack;
  584. this->plus = plus;
  585. this->minus = minus;
  586. this->debounceTime = debounceTime;
  587. this->screen = screen;
  588. pinMode(goTo, INPUT_PULLUP);
  589. pinMode(goBack, INPUT_PULLUP);
  590. pinMode(plus, INPUT_PULLUP);
  591. pinMode(minus, INPUT_PULLUP);
  592. }
  593. //Debouncing functions
  594. void checkGoTo(){
  595. static char cont;
  596. if(digitalRead(this->goTo) == LOW)
  597. cont++;
  598. else
  599. cont = 0;
  600. if(cont == debounceTime/REFRESH){
  601. this->screen->goTo();
  602. }
  603. }
  604. void checkGoBack(){
  605. static char cont;
  606. if(digitalRead(this->goBack) == LOW){
  607. cont++;
  608. }
  609. else
  610. cont = 0;
  611. if(cont == debounceTime/REFRESH){
  612. this->screen->goBack();
  613. }
  614. }
  615. void checkPlus(){
  616. static char cont;
  617. if(digitalRead(this->plus) == LOW)
  618. cont++;
  619. else
  620. cont = 0;
  621. if(cont == debounceTime/REFRESH){
  622. this->screen->plusAction();
  623. }
  624. }
  625. void checkMinus(){
  626. static char cont;
  627. if(digitalRead(this->minus) == LOW)
  628. cont++;
  629. else
  630. cont = 0;
  631. if(cont == debounceTime/REFRESH){
  632. this->screen->minusAction();
  633. }
  634. }
  635. // All buttons are checked with this method
  636. void control(){
  637. this->checkGoTo();
  638. this->checkGoBack();
  639. this->checkPlus();
  640. this->checkMinus();
  641. }
  642. };
  643. int i = 0;
  644. int multiplier = 1;
  645. Screen screen;
  646. Keyboard keyboard(13, 12, 14, 27, 30, &screen);
  647. void setup(){
  648. screen.configure(true);
  649. screen.createMenu(128, 13); //Menu 0
  650. screen.createMenu(128, 13); //Menu 1
  651. /*String title, char graphType, double xpos, double ypos, double width, double height,
  652. double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, double digit*/
  653. screen.createVGraph("Grafica 1", 25, 60, 40, 40, 0, 100, 10, 0); //Graph 0
  654. screen.createHGraph("Grafica 2", 10, 40, 100, 20, 0, 100, 10, 0); //Graph 1
  655. screen.createCGraph("Grafica 3", 30, 50, 75, 30, 0, 100, 0, 1000, 25, 250, 0); //Graph 2
  656. screen.createModifier("Modify variable", &multiplier, 5, 1, 1);
  657. screen.createOption(0, "Vertical graph", 1, 0);
  658. //Creates the first option in Menu 0, directing to a graph (contentType = 1 (Graph)), 0 (Graph 0)
  659. screen.createOption(0, "Horizontal graph", 1, 1);
  660. screen.createOption(0, "Cartesian graph", 1, 2);
  661. screen.createOption(0, "Extra option", 0, 1);
  662. screen.createOption(1, "Test", 1, 3);
  663. screen.createOption(1, "Working?", 2, 2);
  664. screen.createOption(1, "Modify variable", 2, 0);
  665. // screen.increasePos();
  666. // screen.increasePos();
  667. // screen.goTo();
  668. // screen.graphAssignValue(2, 50);
  669. // screen.goBack();
  670. // screen.increasePos();
  671. // screen.goTo();
  672. // screen.goBack();
  673. // screen.decreasePos();
  674. }
  675. void loop(){
  676. screen.control(); //Controls the screen and redraws if needed
  677. keyboard.control();
  678. if(i <= 100){
  679. screen.graphAssignValue(1, i); //Assigning a demo value to Graph 1
  680. screen.graphAssignValue(2, i); //Assigning a demo value to Graph 2
  681. i += multiplier;
  682. }
  683. else
  684. i = 0;
  685. delay(REFRESH); //Refresh time (approx)
  686. }