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.

522 lines
17 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
  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. switch(graphType){
  182. case 'a':
  183. this->yrange = ymaximum - yminimum;
  184. this->graphScale = (yStepSize) * (height / this->yrange) - .001; //Adjusts the scale of the graph, according to the range and the size of the step
  185. break;
  186. case 'b':
  187. this->xrange = xmaximum - xminimum;
  188. this->graphScale = (xStepSize) * (width / this->xrange) - .001; //Adjusts the scale of the graph, according to the range and the size of the step
  189. break;
  190. case 'c':
  191. this->yrange = ymaximum - yminimum;
  192. this->xrange = xmaximum - xminimum;
  193. break;
  194. }
  195. }
  196. void drawGraph(){
  197. double level, data, i;
  198. switch(graphType){
  199. case 'a':
  200. double my;
  201. if (this->redraw) {
  202. display.clearDisplay();
  203. this->redraw = false;
  204. display.fillRect(0, 0, 127 , 14, SSD1306_WHITE);
  205. display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
  206. display.setTextSize(1);
  207. display.setCursor(2, 4);
  208. display.println(this->title);
  209. for (i = 0; i <= this->height; i += this->graphScale) {
  210. my = this->ypos - this->height + i;
  211. display.drawFastHLine(this->xpos + this->width + 1, my, 5, SSD1306_WHITE);
  212. // draw lables
  213. display.setTextSize(1);
  214. display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
  215. display.setCursor(this->xpos + this->width + 12, my - 3 );
  216. data = this->ymaximum - ( i * (this->yStepSize / this->graphScale));
  217. display.print(data, this->digit);
  218. }
  219. }
  220. // compute level of bar graph that is scaled to the height and the hi and low vals
  221. // this is needed to accompdate for +/- range
  222. level = (this->height * (((this->value - this->yminimum) / (this->yrange))));
  223. // draw the bar graph
  224. // write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update
  225. display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE);
  226. display.fillRect(this->xpos, this->ypos - this->height, this->width, this->height - level, SSD1306_BLACK);
  227. display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE);
  228. display.fillRect(this->xpos, this->ypos - level, this->width, level, SSD1306_WHITE);
  229. // up until now print sends data to a video buffer NOT the screen
  230. // this call sends the data to the screen
  231. display.display();
  232. break;
  233. case 'b':
  234. double mx;
  235. if (this->redraw) {
  236. display.clearDisplay();
  237. this->redraw = false;
  238. display.fillRect(0, 0, 127 , 16, SSD1306_WHITE);
  239. display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
  240. display.setTextSize(1);
  241. display.setCursor(2, 4);
  242. display.println(this->title);
  243. // draw the text
  244. for (i = 0; i <= this->width; i += this->graphScale) {
  245. display.drawFastVLine(i + this->xpos , this->ypos , 5, SSD1306_WHITE);
  246. // draw lables
  247. display.setTextSize(1);
  248. display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
  249. display.setCursor(i + this->xpos , this->ypos + 10);
  250. // addling a small value to eliminate round off errors
  251. // this val may need to be adjusted
  252. data = ( i * (this->xStepSize / this->graphScale)) + this->xminimum + 0.00001;
  253. display.print(data, this->digit);
  254. }
  255. }
  256. // compute level of bar graph that is scaled to the width and the hi and low vals
  257. // this is needed to accompdate for +/- range capability
  258. // draw the bar graph
  259. // write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update
  260. level = (this->width * (((this->value - this->xminimum) / (this->xmaximum - this->xminimum))));
  261. display.fillRect(this->xpos + level, this->ypos - this->height, this->width - level, this->height, SSD1306_BLACK);
  262. display.drawRect(this->xpos, this->ypos - this->height, this->width, this->height, SSD1306_WHITE);
  263. display.fillRect(this->xpos, this->ypos - this->height, level, this->height, SSD1306_WHITE);
  264. // up until now print sends data to a video buffer NOT the screen
  265. // this call sends the data to the screen
  266. display.display();
  267. break;
  268. case 'c':
  269. double temp, ox, oy;
  270. int rot, newrot;
  271. if (this->redraw == true) {
  272. this->redraw = false;
  273. display.clearDisplay();
  274. display.fillRect(0, 0, 127 , 16, SSD1306_WHITE);
  275. display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
  276. display.setTextSize(1);
  277. display.setCursor(2, 4);
  278. display.println(title);
  279. ox = (this->x - this->xminimum) * (this->width) / (this->xrange) + this->xpos;
  280. oy = (this->value - this->yminimum) * (this->ypos - this->height - this->ypos) / (this->yrange) + this->ypos;
  281. // draw y scale
  282. display.setTextSize(1);
  283. display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
  284. for ( i = this->yminimum; i <= this->ymaximum; i += this->yStepSize) {
  285. // compute the transform
  286. // note my transform funcition is the same as the map function, except the map uses long and we need doubles
  287. temp = (i - this->yminimum) * (this->ypos - this->height - this->ypos) / (this->ymaximum - this->yminimum) + this->ypos;
  288. if (i == 0) {
  289. display.drawFastHLine(this->xpos - 3, temp, this->width + 3, SSD1306_WHITE);
  290. }
  291. else {
  292. display.drawFastHLine(this->xpos - 3, temp, 3, SSD1306_WHITE);
  293. }
  294. display.setCursor(this->xpos - 27, temp - 3);
  295. display.println(i, this->digit);
  296. }
  297. // draw x scale
  298. for (i = this->xminimum; i <= this->xmaximum; i += this->xStepSize) {
  299. // compute the transform
  300. display.setTextSize(1);
  301. display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
  302. temp = (i - this->xminimum) * (this->width) / (this->xrange) + this->xpos;
  303. if (i == 0) {
  304. display.drawFastVLine(temp, this->ypos - this->height, this->height + 3, SSD1306_WHITE);
  305. }
  306. else {
  307. display.drawFastVLine(temp, this->ypos, 3, SSD1306_WHITE);
  308. }
  309. display.setCursor(temp, this->ypos + 6);
  310. display.println(i, this->digit);
  311. }
  312. }
  313. // graph drawn now plot the data
  314. // the entire plotting code are these few lines...
  315. this->x = (this->x - this->xminimum) * (this->width) / (this->xrange) + this->xpos;
  316. this->value = (this->value - this->yminimum) * (this->ypos - this->height - this->ypos) / (this->yrange) + this->ypos;
  317. display.drawLine(ox, oy, this->x, this->value, SSD1306_WHITE);
  318. display.drawLine(ox, oy - 1, this->x, this->value - 1, SSD1306_WHITE);
  319. ox = this->x;
  320. oy = this->value;
  321. if(ox == this->xpos + this->width)
  322. this->redraw = true;
  323. this->x = 0;
  324. // up until now print sends data to a video buffer NOT the screen
  325. // this call sends the data to the screen
  326. display.display();
  327. this->x++;
  328. }
  329. }
  330. void redrawFlag(){
  331. this->redraw = true;
  332. }
  333. void setPreviousScreen(int prev){
  334. this->previousScreen = prev;
  335. }
  336. void setPreviousContentTypeMenu(bool prev){
  337. this->previousContentTypeMenu = prev;
  338. }
  339. int getPreviousScreen(){
  340. int prev = this->previousScreen;
  341. return prev;
  342. }
  343. bool getPreviousContentTypeMenu(){
  344. bool prev = this->previousContentTypeMenu;
  345. return prev;
  346. }
  347. void assignValue(double value){
  348. this->value = value;
  349. }
  350. };
  351. class Screen{
  352. private:
  353. Menu menu[MAX_MENUS];
  354. Graph graph[MAX_GRAPH];
  355. int counterM = 0;
  356. int counterG = 0;
  357. int currentScreen = 0;
  358. bool redraw = true;
  359. bool contentTypeMenu = true;
  360. public:
  361. void createMenu(int sizex, int sizey){
  362. this->menu[counterM].configure(sizex, sizey);
  363. counterM++;
  364. }
  365. void createOption(int menuIndex, String content, bool destinationTypeMenu, int destinationIndex){
  366. this->menu[menuIndex].createOption(content, destinationTypeMenu, destinationIndex);
  367. }
  368. void createGraph(String title, char graphType, double xpos, double ypos, double width, double height,
  369. double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, double digit){
  370. this->graph[counterG].configure(title, graphType, xpos, ypos, width, height, yminimum, ymaximum, xminimum, xmaximum, yStepSize, xStepSize, digit);
  371. counterG++;
  372. }
  373. void redrawFlag(){
  374. this->redraw = true;
  375. }
  376. void graphAssignValue(int graphIndex, double value){
  377. this->graph[graphIndex].assignValue(value);
  378. this->redraw = true;
  379. }
  380. void control(){
  381. if (redraw){
  382. if (contentTypeMenu){
  383. menu[currentScreen].drawMenu();
  384. }
  385. else{
  386. graph[currentScreen].drawGraph();
  387. }
  388. this->redraw = false;
  389. }
  390. }
  391. void increasePos(){
  392. this->menu[this->currentScreen].increasePos();
  393. }
  394. void decreasePos(){
  395. this->menu[this->currentScreen].decreasePos();
  396. }
  397. void goTo(){
  398. int newScreen = this->menu[this->currentScreen].extractDestinationIndex();
  399. bool newContentTypeMenu = this->menu[this->currentScreen].extractDestinationTypeMenu();
  400. if (contentTypeMenu){
  401. this->menu[newScreen].setPreviousScreen(this->currentScreen);
  402. this->menu[newScreen].setPreviousContentTypeMenu(this->contentTypeMenu);
  403. }
  404. else{
  405. this->graph[newScreen].setPreviousScreen(this->currentScreen);
  406. this->graph[newScreen].setPreviousContentTypeMenu(this->contentTypeMenu);
  407. }
  408. this->contentTypeMenu = newContentTypeMenu;
  409. this->currentScreen = newScreen;
  410. this->redraw = true;
  411. }
  412. void goBack(){
  413. if (contentTypeMenu){
  414. this->currentScreen = this->menu[this->currentScreen].getPreviousScreen();
  415. this->contentTypeMenu = this->menu[this->currentScreen].getPreviousContentTypeMenu();
  416. }
  417. else{
  418. this->graph[this->currentScreen].redrawFlag();
  419. this->currentScreen = this->graph[this->currentScreen].getPreviousScreen();
  420. this->contentTypeMenu = this->graph[this->currentScreen].getPreviousContentTypeMenu();
  421. }
  422. }
  423. };
  424. Screen screen;
  425. void setup(){
  426. setDisp(true);
  427. screen.createMenu(128, 9);
  428. /*String title, char graphType, double xpos, double ypos, double width, double height,
  429. double yminimum, double ymaximum, double xminimum, double xmaximum, double yStepSize, double xStepSize, double digit*/
  430. screen.createGraph("Grafica 1", 'a', 25, 60, 40, 40, 0, 100, 0, 0, 10, 0, 0);
  431. screen.createGraph("Grafica 2", 'b', 10, 60, 100, 20, 0, 0, 0, 100, 0, 10, 0);
  432. screen.createGraph("Grafica 3", 'c', 30, 50, 75, 30, 0, 1024, 0, 10, 100, 10, 0);
  433. screen.createOption(0, "Grafica vertical", false, 0);
  434. screen.createOption(0, "Grafica horizontal", false, 1);
  435. screen.createOption(0, "Grafica cartesiana", false, 2);
  436. }
  437. void loop(){
  438. screen.control();
  439. delay(10);
  440. }