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.

538 lines
18 KiB

  1. #define MAX_OPTIONS 10 //Maximum number of options for each menu
  2. #define MAX_MENUS 3
  3. #define MAX_GRAPH 3
  4. #define __DEBUG__
  5. #include <Arduino.h>
  6. #include <SPI.h>
  7. #include <Wire.h>
  8. #include <Adafruit_GFX.h>
  9. #include <Adafruit_SSD1306.h>
  10. #define DISP_WIDTH 128 // OLED display width
  11. #define DISP_HEIGHT 64 // OLED display height
  12. Adafruit_SSD1306 display(DISP_WIDTH, DISP_HEIGHT, &Wire, -1);
  13. void setDisp(bool fullsetting){
  14. if(fullsetting){
  15. //Adafruit_SSD1306 display(DISP_WIDTH, DISP_HEIGHT, &Wire, -1);
  16. Serial.begin(115200);
  17. if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
  18. #ifdef __DEBUG__
  19. Serial.println("Display not found!");
  20. #endif
  21. while (true);
  22. }
  23. }
  24. display.clearDisplay();
  25. // Text size
  26. display.setTextSize(2);
  27. // Text color
  28. display.setTextColor(SSD1306_WHITE);
  29. // Text position
  30. display.setCursor(0, 20);
  31. display.println("Bienvenido");
  32. display.setTextSize(1);
  33. display.display();
  34. delay(5000);
  35. }
  36. class Option{
  37. private:
  38. int sizex;
  39. int sizey;
  40. String content;
  41. int pos;
  42. int textSpacing;
  43. bool fill = false;
  44. bool disp = false;
  45. bool destinationTypeMenu;
  46. int destinationIndex;
  47. public:
  48. //Option(){}
  49. void configure(String content, int sizex, int sizey, int pos, bool destinationTypeMenu, int destinationIndex){
  50. this->sizex = sizex;
  51. this->sizey = sizey;
  52. this->content = content;
  53. this->pos = pos;
  54. this->destinationTypeMenu = destinationTypeMenu;
  55. this->destinationIndex = destinationIndex;
  56. this->disp = true;
  57. this->textSpacing = ((sizey - 7)/2) + 7;
  58. }
  59. bool getDestinationTypeMenu(){
  60. bool destinationType = this->destinationTypeMenu;
  61. return destinationType;
  62. }
  63. int getDestinationIndex(){
  64. int destinationIndex = this->destinationIndex;
  65. return destinationIndex;
  66. }
  67. void drawopt(int page, int pos, int optPPage){
  68. if(this->disp){
  69. if(this->pos == pos){
  70. display.fillRect(0, (this->sizey)*(this->pos) + pos - (page*optPPage*this->sizey), this->sizex, this->sizey, WHITE);
  71. display.setTextColor(SSD1306_BLACK);
  72. display.setCursor(5, (this->sizey)*(this->pos + 1) - (page*optPPage*this->sizey) - this->textSpacing);
  73. display.print(this->content);
  74. display.setTextColor(SSD1306_WHITE);
  75. }
  76. else{
  77. display.drawRect(0, (this->sizey)*(this->pos) + pos - (page*optPPage*this->sizey), this->sizex, this->sizey, WHITE);
  78. display.setCursor(5, (this->sizey)*(this->pos + 1) - (page*optPPage*this->sizey) - this->textSpacing);
  79. display.print(this->content);
  80. }
  81. }
  82. }
  83. };
  84. class Menu{ //ContentTypeMenu true, it is a menu
  85. private:
  86. int sizex;
  87. int sizey; //Y size of each option in the menu
  88. int options = 0; //This indicates the number of options created
  89. int pos = 0; //This indicates the position of the cursor
  90. int page = 0; //If the menu is too long, this indicates the page that is being displayed
  91. Option opt[MAX_OPTIONS];
  92. int previousScreen = 0;
  93. int optPPage;
  94. bool previousContentTypeMenu = true;
  95. public:
  96. void configure(int sizex, int sizey){
  97. this->sizex = sizex;
  98. this->sizey = sizey;
  99. this->optPPage = DISP_HEIGHT / this->sizey;
  100. }
  101. void createOption(String content, bool destinationTypeMenu, int destinationIndex){
  102. this->opt[this->options].configure(content, this->sizex, this->sizey, this->options++, destinationTypeMenu, destinationIndex);
  103. }
  104. bool extractDestinationTypeMenu(){
  105. bool destinationTypeMenu = this->opt[this->pos].getDestinationTypeMenu();
  106. return destinationTypeMenu;
  107. }
  108. int extractDestinationIndex(){
  109. int destinationIndex = this->opt[this->pos].getDestinationIndex();
  110. return destinationIndex;
  111. }
  112. void drawMenu(){
  113. display.clearDisplay();
  114. this->page = pos/this->optPPage;
  115. for(int i = 0; i < options; i++){
  116. this->opt[i].drawopt(this->page, this->pos, this->optPPage);
  117. }
  118. display.display();
  119. }
  120. void increasePos(){
  121. this->pos++;
  122. }
  123. void decreasePos(){
  124. this->pos--;
  125. }
  126. void setPreviousScreen(int prev){
  127. this->previousScreen = prev;
  128. }
  129. void setPreviousContentTypeMenu(bool prev){
  130. this->previousContentTypeMenu = prev;
  131. }
  132. int getPreviousScreen(){
  133. int prev = this->previousScreen;
  134. return prev;
  135. }
  136. bool getPreviousContentTypeMenu(){
  137. bool prev = this->previousContentTypeMenu;
  138. return prev;
  139. }
  140. };
  141. class Graph{ //ContentTypeMenu false, it is not a menu
  142. private:
  143. String title;
  144. char graphType; //'a' Vertical Bar, 'b' Horizontal Bar, 'c' Cartesian Graph
  145. //Assign whatever value in "configure(..." if a parameter is not required for the specified graphType
  146. double value; //For: Vertical Bar Horizontal Bar Cartesian
  147. double xpos; //For: Vertical Bar Horizontal Bar Cartesian
  148. double ypos; //For: Vertical Bar Horizontal Bar Cartesian
  149. double height; //For: Vertical Bar Horizontal Bar Cartesian
  150. double width; //For: Vertical Bar Horizontal Bar Cartesian
  151. double yminimum; //For: Vertical Bar Cartesian
  152. double ymaximum; //For: Vertical Bar Cartesian
  153. double xminimum; //For: Horizontal Bar Cartesian
  154. double xmaximum; //For: Horizontal Bar Cartesian
  155. double yStepSize; //For: Vertical Bar Cartesian
  156. double xStepSize; //For: Horizontal Bar Cartesian
  157. double digit; //For: Vertical Bar Horizontal Bar Cartesian
  158. double x;
  159. double yrange;
  160. double xrange;
  161. double xorigin;
  162. double yorigin;
  163. double graphScale;
  164. bool redraw = true;
  165. int previousScreen = 0;
  166. bool previousContentTypeMenu = true;
  167. public:
  168. void configure(String title, char graphType, double xpos, double ypos, double width, double height,
  169. double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, double digit){
  170. this->title = title;
  171. this->graphType = graphType;
  172. this->yminimum = yminimum;
  173. this->ymaximum = ymaximum;
  174. this->xminimum = xminimum;
  175. this->xmaximum = xmaximum;
  176. this->height = height;
  177. this->width = width;
  178. this->yStepSize = yStepSize;
  179. this->xStepSize = xStepSize;
  180. this->digit = digit;
  181. this->xpos = xpos;
  182. this->ypos = ypos;
  183. switch(graphType){
  184. case 'a':
  185. this->yrange = ymaximum - yminimum;
  186. this->graphScale = (yStepSize) * (height / this->yrange) - .001; //Adjusts the scale of the graph, according to the range and the size of the step
  187. break;
  188. case 'b':
  189. this->xrange = xmaximum - xminimum;
  190. this->graphScale = (xStepSize) * (width / this->xrange) - .001; //Adjusts the scale of the graph, according to the range and the size of the step
  191. break;
  192. case 'c':
  193. this->yrange = ymaximum - yminimum;
  194. this->xrange = xmaximum - xminimum;
  195. break;
  196. }
  197. }
  198. void drawGraph(){
  199. double level, data, i;
  200. switch(graphType){
  201. case 'a':
  202. double my;
  203. if (this->redraw) {
  204. display.clearDisplay();
  205. this->redraw = false;
  206. display.fillRect(0, 0, 127 , 14, SSD1306_WHITE);
  207. display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
  208. display.setTextSize(1);
  209. display.setCursor(2, 4);
  210. display.println(this->title);
  211. for (i = 0; i <= this->height; i += this->graphScale) {
  212. my = this->ypos - this->height + i;
  213. display.drawFastHLine(this->xpos + this->width + 1, my, 5, SSD1306_WHITE);
  214. // draw lables
  215. display.setTextSize(1);
  216. display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
  217. display.setCursor(this->xpos + this->width + 12, my - 3 );
  218. data = this->ymaximum - ( i * (this->yStepSize / this->graphScale));
  219. display.print(data, this->digit);
  220. }
  221. }
  222. // compute level of bar graph that is scaled to the height and the hi and low vals
  223. // this is needed to accompdate for +/- range
  224. level = (this->height * (((this->value - this->yminimum) / (this->yrange))));
  225. // draw the bar graph
  226. // write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update
  227. display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE);
  228. display.fillRect(this->xpos, this->ypos - this->height, this->width, this->height - level, SSD1306_BLACK);
  229. display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE);
  230. display.fillRect(this->xpos, this->ypos - level, this->width, level, SSD1306_WHITE);
  231. // up until now print sends data to a video buffer NOT the screen
  232. // this call sends the data to the screen
  233. display.display();
  234. break;
  235. case 'b':
  236. double mx;
  237. if (this->redraw) {
  238. display.clearDisplay();
  239. this->redraw = false;
  240. display.fillRect(0, 0, 127 , 16, SSD1306_WHITE);
  241. display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
  242. display.setTextSize(1);
  243. display.setCursor(2, 4);
  244. display.println(this->title);
  245. // draw the text
  246. for (i = 0; i <= this->width; i += this->graphScale) {
  247. display.drawFastVLine(i + this->xpos , this->ypos , 5, SSD1306_WHITE);
  248. // draw lables
  249. display.setTextSize(1);
  250. display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
  251. display.setCursor(i + this->xpos , this->ypos + 10);
  252. // addling a small value to eliminate round off errors
  253. // this val may need to be adjusted
  254. data = ( i * (this->xStepSize / this->graphScale)) + this->xminimum + 0.00001;
  255. display.print(data, this->digit);
  256. }
  257. }
  258. // compute level of bar graph that is scaled to the width and the hi and low vals
  259. // this is needed to accompdate for +/- range capability
  260. // draw the bar graph
  261. // write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update
  262. level = (this->width * (((this->value - this->xminimum) / (this->xmaximum - this->xminimum))));
  263. display.fillRect(this->xpos + level, this->ypos - this->height, this->width - level, this->height, SSD1306_BLACK);
  264. display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE);
  265. display.fillRect(this->xpos, this->ypos - this->height, level, this->height, SSD1306_WHITE);
  266. // up until now print sends data to a video buffer NOT the screen
  267. // this call sends the data to the screen
  268. display.display();
  269. break;
  270. case 'c':
  271. double temp, ox, oy;
  272. int rot, newrot;
  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. ox = (this->x - this->xminimum) * (this->width) / (this->xrange) + this->xpos;
  282. oy = (this->value - this->yminimum) * (this->ypos - this->height - this->ypos) / (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->ypos - this->height - this->ypos) / (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->x - this->xminimum) * (this->width) / (this->xrange) + this->xpos;
  318. this->value = (this->value - this->yminimum) * (this->ypos - this->height - this->ypos) / (this->yrange) + this->ypos;
  319. display.drawLine(ox, oy, this->x, this->value, SSD1306_WHITE);
  320. display.drawLine(ox, oy - 1, this->x, this->value - 1, SSD1306_WHITE);
  321. ox = this->x;
  322. oy = this->value;
  323. if(ox == this->xpos + this->width)
  324. this->redraw = true;
  325. this->x = 0;
  326. // up until now print sends data to a video buffer NOT the screen
  327. // this call sends the data to the screen
  328. display.display();
  329. this->x++;
  330. }
  331. }
  332. void redrawFlag(){
  333. this->redraw = true;
  334. }
  335. void setPreviousScreen(int prev){
  336. this->previousScreen = prev;
  337. }
  338. void setPreviousContentTypeMenu(bool prev){
  339. this->previousContentTypeMenu = prev;
  340. }
  341. int getPreviousScreen(){
  342. int prev = this->previousScreen;
  343. return prev;
  344. }
  345. bool getPreviousContentTypeMenu(){
  346. bool prev = this->previousContentTypeMenu;
  347. return prev;
  348. }
  349. void assignValue(double value){
  350. this->value = value;
  351. }
  352. };
  353. class Screen{
  354. private:
  355. Menu menu[MAX_MENUS];
  356. Graph graph[MAX_GRAPH];
  357. int counterM = 0;
  358. int counterG = 0;
  359. int currentScreen = 0;
  360. bool redraw = true;
  361. bool contentTypeMenu = true;
  362. public:
  363. void createMenu(int sizex, int sizey){
  364. this->menu[counterM].configure(sizex, sizey);
  365. counterM++;
  366. }
  367. void createOption(int menuIndex, String content, bool destinationTypeMenu, int destinationIndex){
  368. this->menu[menuIndex].createOption(content, destinationTypeMenu, destinationIndex);
  369. }
  370. void createVGraph(String title, double xpos, double ypos, double width, double height,
  371. double yminimum, double ymaximum, double yStepSize, double digit){
  372. this->graph[counterG].configure(title, 'a', xpos, ypos, width, height, yminimum, ymaximum, 0, 0, yStepSize, 0, digit);
  373. counterG++;
  374. }
  375. void createHGraph(String title, double xpos, double ypos, double width, double height,
  376. double xminimum, double xmaximum, double xStepSize, double digit){
  377. this->graph[counterG].configure(title, 'b', xpos, ypos, width, height, 0, 0, xminimum, xmaximum, 0, xStepSize, digit);
  378. counterG++;
  379. }
  380. void createCGraph(String title, double xpos, double ypos, double width, double height,
  381. double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, double digit){
  382. this->graph[counterG].configure(title, 'c', xpos, ypos, width, height, yminimum, ymaximum, xminimum, xmaximum, yStepSize, xStepSize, digit);
  383. counterG++;
  384. }
  385. void redrawFlag(){
  386. this->redraw = true;
  387. }
  388. void graphAssignValue(int graphIndex, double value){
  389. this->graph[graphIndex].assignValue(value);
  390. this->redraw = true;
  391. }
  392. void control(){
  393. if (redraw){
  394. if (contentTypeMenu){
  395. menu[currentScreen].drawMenu();
  396. }
  397. else{
  398. graph[currentScreen].drawGraph();
  399. }
  400. this->redraw = false;
  401. }
  402. }
  403. void increasePos(){
  404. this->menu[this->currentScreen].increasePos();
  405. }
  406. void decreasePos(){
  407. this->menu[this->currentScreen].decreasePos();
  408. }
  409. void goTo(){
  410. if(this->contentTypeMenu){
  411. int newScreen = this->menu[this->currentScreen].extractDestinationIndex();
  412. bool newContentTypeMenu = this->menu[this->currentScreen].extractDestinationTypeMenu();
  413. if (newContentTypeMenu){
  414. this->menu[newScreen].setPreviousScreen(this->currentScreen);
  415. this->menu[newScreen].setPreviousContentTypeMenu(this->contentTypeMenu);
  416. }
  417. else{
  418. this->graph[newScreen].setPreviousScreen(this->currentScreen);
  419. this->graph[newScreen].setPreviousContentTypeMenu(this->contentTypeMenu);
  420. }
  421. this->contentTypeMenu = newContentTypeMenu;
  422. this->currentScreen = newScreen;
  423. this->redraw = true;
  424. }
  425. }
  426. void goBack(){
  427. if (contentTypeMenu){
  428. this->currentScreen = this->menu[this->currentScreen].getPreviousScreen();
  429. this->contentTypeMenu = this->menu[this->currentScreen].getPreviousContentTypeMenu();
  430. }
  431. else{
  432. this->graph[this->currentScreen].redrawFlag();
  433. this->currentScreen = this->graph[this->currentScreen].getPreviousScreen();
  434. this->contentTypeMenu = this->graph[this->currentScreen].getPreviousContentTypeMenu();
  435. }
  436. }
  437. };
  438. Screen screen;
  439. void setup(){
  440. setDisp(true);
  441. screen.createMenu(128, 13);
  442. /*String title, char graphType, double xpos, double ypos, double width, double height,
  443. double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, double digit*/
  444. screen.createVGraph("Grafica 1", 25, 60, 40, 40, 0, 100, 10, 0);
  445. screen.createHGraph("Grafica 2", 10, 60, 100, 20, 0, 100, 10, 0);
  446. screen.createCGraph("Grafica 3", 30, 50, 75, 30, 0, 1024, 0, 10, 100, 10, 0);
  447. screen.createOption(0, "Grafica vertical", false, 0);
  448. screen.createOption(0, "Grafica horizontal", false, 1);
  449. screen.createOption(0, "Grafica cartesiana", false, 2);
  450. }
  451. void loop(){
  452. screen.control();
  453. delay(10);
  454. }