@ -1,6 +1,6 @@
# define MAX_OPTIONS 10 //Maximum number of options for each menu
# define MAX_MENUS 10
# define MAX_GRAPH 10
# define MAX_MENUS 3
# define MAX_GRAPH 3
# define __DEBUG__
# include <Arduino.h>
@ -8,8 +8,6 @@
# include <Wire.h>
# include <Adafruit_GFX.h>
# include <Adafruit_SSD1306.h>
# include <Fonts/FreeSans12pt7b.h>
# define DISP_WIDTH 128 // OLED display width
# define DISP_HEIGHT 64 // OLED display height
@ -23,28 +21,27 @@ void setDisp(bool fullsetting){
Serial . begin ( 115200 ) ;
if ( ! display . begin ( SSD1306_SWITCHCAPVCC , 0x3C ) ) {
# ifdef __DEBUG__
Serial . println ( " No se encuentra la pantalla OLED " ) ;
Serial . println ( " Display not found! " ) ;
# endif
while ( true ) ;
}
}
display . clearDisplay ( ) ;
// Tamaño del texto
// Text size
display . setTextSize ( 2 ) ;
// Color del texto
// Text color
display . setTextColor ( SSD1306_WHITE ) ;
// Posición del texto
display . setCursor ( 0 , 16 ) ;
// Escribir texto
display . println ( " Hola " ) ;
display . display ( ) ;
// Text position
display . setCursor ( 0 , 32 ) ;
display . println ( " mundo!! " ) ;
display . setCursor ( 0 , 20 ) ;
display . println ( " Bienvenido " ) ;
display . setTextSize ( 1 ) ;
display . display ( ) ;
delay ( 5000 ) ;
}
class Option {
@ -54,87 +51,97 @@ class Option{
int sizey ;
String content ;
int pos ;
int textSpacing ;
bool fill = false ;
bool disp = false ;
void ( * f ) ( void ) ;
bool destinationTypeMenu ;
int destinationIndex ;
public :
//Option(){}
void configure ( String content , int sizex , int sizey , int pos ) {
void configure ( String content , int sizex , int sizey , int pos , bool destinationTypeMenu , int destinationIndex ) {
this - > sizex = sizex ;
this - > sizey = sizey ;
this - > content = content ;
this - > pos = pos ;
this - > destinationTypeMenu = destinationTypeMenu ;
this - > destinationIndex = destinationIndex ;
this - > disp = true ;
this - > textSpacing = ( ( sizey - 7 ) / 2 ) + 7 ;
}
bool getDestinationTypeMenu ( ) {
bool destinationType = this - > destinationTypeMenu ;
return destinationType ;
}
void drawopt ( int page , int pos ) {
int getDestinationIndex ( ) {
int destinationIndex = this - > destinationIndex ;
return destinationIndex ;
}
void drawopt ( int page , int pos , int optPPage ) {
if ( this - > disp ) {
if ( this - > pos = = pos ) {
display . fillRect ( 0 , ( this - > sizey ) * ( this - > pos ) - ( page * DISP_WIDTH ) , this - > sizex , this - > sizey , WHITE ) ;
display . fillRect ( 0 , ( this - > sizey ) * ( this - > pos ) + pos - ( page * optPPage * this - > sizey ) , this - > sizex , this - > sizey , WHITE ) ;
display . setTextColor ( SSD1306_BLACK ) ;
display . setCursor ( ( this - > sizex ) + 3 , ( this - > sizey ) - 3 ) ;
display . println ( this - > content ) ;
display . setCursor ( 5 , ( this - > sizey ) * ( this - > pos + 1 ) - ( page * optPPage * this - > sizey ) - this - > textSpacing ) ;
display . print ( this - > content ) ;
display . setTextColor ( SSD1306_WHITE ) ;
}
else {
display . drawRect ( 0 , ( this - > sizey ) * ( this - > pos ) , this - > sizex , this - > sizey , WHITE ) ;
display . setCursor ( ( this - > sizex ) + 3 , ( this - > sizey ) - 3 - ( DISP_WIDTH * 128 ) ) ;
display . println ( this - > content ) ;
display . drawRect ( 0 , ( this - > sizey ) * ( this - > pos ) + pos - ( page * optPPage * this - > sizey ) , this - > sizex , this - > sizey , WHITE ) ;
display . setCursor ( 5 , ( this - > sizey ) * ( this - > pos + 1 ) - ( page * optPPage * this - > sizey ) - this - > textSpacing ) ;
display . print ( this - > content ) ;
}
}
}
void task ( void ( * f ) ( void ) ) {
this - > f = f ;
}
} ;
class Menu {
class Menu { //ContentTypeMenu true, it is a menu
private :
int id ;
int sizex ;
int sizey ;
int sizey ; //Y size of each option in the menu
int options = 0 ; //This indicates the number of options created
int pos = 0 ; //This indicates the position of the cursor
int page = 0 ; //If the menu is too long, this indicates the page that is being displayed
Option opt [ MAX_OPTIONS ] ;
int previousScreen = 0 ;
int optPPage ;
bool previousContentTypeMenu = true ;
public :
void configure ( int id , int sizex , int sizey ) {
this - > id = id ;
void configure ( int sizex , int sizey ) {
this - > sizex = sizex ;
this - > sizey = sizey ;
this - > optPPage = DISP_HEIGHT / this - > sizey ;
}
void createOption ( String content ) {
this - > opt [ this - > options ] . configure ( content , this - > sizex , this - > sizey , this - > options + + ) ;
void createOption ( String content , bool destinationTypeMenu , int destinationIndex ) {
this - > opt [ this - > options ] . configure ( content , this - > sizex , this - > sizey , this - > options + + , destinationTypeMenu , destinationIndex ) ;
}
void function ( int optionindex , void ( * f ) ( void ) ) { //Defines functions for each option
this - > opt [ optionindex ] . task ( f ) ;
bool extractDestinationTypeMenu ( ) {
bool destinationTypeMenu = this - > opt [ this - > pos ] . getDestinationTypeMenu ( ) ;
return destinationTypeMenu ;
}
int extractDestinationIndex ( ) {
int destinationIndex = this - > opt [ this - > pos ] . getDestinationIndex ( ) ;
return destinationIndex ;
}
void drawMenu ( ) {
int dir ;
this - > page = pos / 3 ;
display . clearDisplay ( ) ;
this - > page = pos / this - > optPPage ;
for ( int i = 0 ; i < options ; i + + ) {
this - > opt [ i ] . drawopt ( this - > page , this - > pos ) ;
this - > opt [ i ] . drawopt ( this - > page , this - > pos , this - > optPPage ) ;
}
}
int getid ( ) {
int id = this - > id ;
return id ;
}
int getoptions ( ) {
int options = this - > options ;
return options ;
display . display ( ) ;
}
void increasePos ( ) {
@ -144,42 +151,372 @@ class Menu{
void decreasePos ( ) {
this - > pos - - ;
}
void setPreviousScreen ( int prev ) {
this - > previousScreen = prev ;
}
void setPreviousContentTypeMenu ( bool prev ) {
this - > previousContentTypeMenu = prev ;
}
int getPreviousScreen ( ) {
int prev = this - > previousScreen ;
return prev ;
}
bool getPreviousContentTypeMenu ( ) {
bool prev = this - > previousContentTypeMenu ;
return prev ;
}
} ;
class Graph { //ContentTypeMenu false, it is not a menu
private :
String title ;
char graphType ; //'a' Vertical Bar, 'b' Horizontal Bar, 'c' Cartesian Graph
//Assign whatever value in "configure(..." if a parameter is not required for the specified graphType
double value ; //For: Vertical Bar Horizontal Bar Cartesian
double xpos ; //For: Vertical Bar Horizontal Bar Cartesian
double ypos ; //For: Vertical Bar Horizontal Bar Cartesian
double height ; //For: Vertical Bar Horizontal Bar Cartesian
double width ; //For: Vertical Bar Horizontal Bar Cartesian
double yminimum ; //For: Vertical Bar Cartesian
double ymaximum ; //For: Vertical Bar Cartesian
double xminimum ; //For: Horizontal Bar Cartesian
double xmaximum ; //For: Horizontal Bar Cartesian
double yStepSize ; //For: Vertical Bar Cartesian
double xStepSize ; //For: Horizontal Bar Cartesian
double digit ; //For: Vertical Bar
double x ;
double yrange ;
double xrange ;
double xorigin ;
double yorigin ;
double graphScale ;
bool redraw = true ;
int previousScreen = 0 ;
bool previousContentTypeMenu = true ;
public :
void configure ( String title , char graphType , double xpos , double ypos , double width , double height ,
double yminimum , double ymaximum , double xminimum , double xmaximum , double yStepSize , double xStepSize , double digit ) {
this - > title = title ;
this - > graphType = graphType ;
this - > yminimum = yminimum ;
this - > ymaximum = ymaximum ;
this - > xminimum = xminimum ;
this - > xmaximum = xmaximum ;
this - > height = height ;
this - > width = width ;
this - > yStepSize = yStepSize ;
this - > xStepSize = xStepSize ;
this - > digit = digit ;
switch ( graphType ) {
case ' a ' :
this - > yrange = ymaximum - yminimum ;
this - > graphScale = ( yStepSize ) * ( height / this - > yrange ) - .001 ; //Adjusts the scale of the graph, according to the range and the size of the step
break ;
case ' b ' :
this - > xrange = xmaximum - xminimum ;
this - > graphScale = ( xStepSize ) * ( width / this - > xrange ) - .001 ; //Adjusts the scale of the graph, according to the range and the size of the step
break ;
case ' c ' :
this - > yrange = ymaximum - yminimum ;
this - > xrange = xmaximum - xminimum ;
break ;
}
}
void drawGraph ( ) {
double level , data , i ;
switch ( graphType ) {
case ' a ' :
double my ;
if ( this - > redraw ) {
display . clearDisplay ( ) ;
this - > redraw = false ;
display . fillRect ( 0 , 0 , 127 , 14 , SSD1306_WHITE ) ;
display . setTextColor ( SSD1306_BLACK , SSD1306_WHITE ) ;
display . setTextSize ( 1 ) ;
display . setCursor ( 2 , 4 ) ;
display . println ( this - > title ) ;
for ( i = 0 ; i < = this - > height ; i + = this - > graphScale ) {
my = this - > ypos - this - > height + i ;
display . drawFastHLine ( this - > xpos + this - > width + 1 , my , 5 , SSD1306_WHITE ) ;
// draw lables
display . setTextSize ( 1 ) ;
display . setTextColor ( SSD1306_WHITE , SSD1306_BLACK ) ;
display . setCursor ( this - > xpos + this - > width + 12 , my - 3 ) ;
data = this - > ymaximum - ( i * ( this - > yStepSize / this - > graphScale ) ) ;
display . print ( data , this - > digit ) ;
}
}
// compute level of bar graph that is scaled to the height and the hi and low vals
// this is needed to accompdate for +/- range
level = ( this - > height * ( ( ( this - > value - this - > yminimum ) / ( this - > yrange ) ) ) ) ;
// draw the bar graph
// write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update
display . drawRect ( this - > xpos , this - > ypos - this - > height , this - > width , this - > height , SSD1306_WHITE ) ;
display . fillRect ( this - > xpos , this - > ypos - this - > height , this - > width , this - > height - level , SSD1306_BLACK ) ;
display . drawRect ( this - > xpos , this - > ypos - this - > height , this - > width , this - > height , SSD1306_WHITE ) ;
display . fillRect ( this - > xpos , this - > ypos - level , this - > width , level , SSD1306_WHITE ) ;
// up until now print sends data to a video buffer NOT the screen
// this call sends the data to the screen
display . display ( ) ;
break ;
case ' b ' :
double mx ;
if ( this - > redraw ) {
display . clearDisplay ( ) ;
this - > redraw = false ;
display . fillRect ( 0 , 0 , 127 , 16 , SSD1306_WHITE ) ;
display . setTextColor ( SSD1306_BLACK , SSD1306_WHITE ) ;
display . setTextSize ( 1 ) ;
display . setCursor ( 2 , 4 ) ;
display . println ( this - > title ) ;
// draw the text
for ( i = 0 ; i < = this - > width ; i + = this - > graphScale ) {
display . drawFastVLine ( i + this - > xpos , this - > ypos , 5 , SSD1306_WHITE ) ;
// draw lables
display . setTextSize ( 1 ) ;
display . setTextColor ( SSD1306_WHITE , SSD1306_BLACK ) ;
display . setCursor ( i + this - > xpos , this - > ypos + 10 ) ;
// addling a small value to eliminate round off errors
// this val may need to be adjusted
data = ( i * ( this - > xStepSize / this - > graphScale ) ) + this - > xminimum + 0.00001 ;
display . print ( data , this - > digit ) ;
}
}
// compute level of bar graph that is scaled to the width and the hi and low vals
// this is needed to accompdate for +/- range capability
// draw the bar graph
// write a upper and lower bar to minimize flicker cause by blanking out bar and redraw on update
level = ( this - > width * ( ( ( this - > value - this - > xminimum ) / ( this - > xmaximum - this - > xminimum ) ) ) ) ;
display . fillRect ( this - > xpos + level , this - > ypos - this - > height , this - > width - level , this - > height , SSD1306_BLACK ) ;
display . drawRect ( this - > xpos , this - > ypos - this - > height , this - > width , this - > height , SSD1306_WHITE ) ;
display . fillRect ( this - > xpos , this - > ypos - this - > height , level , this - > height , SSD1306_WHITE ) ;
// up until now print sends data to a video buffer NOT the screen
// this call sends the data to the screen
display . display ( ) ;
break ;
case ' c ' :
double temp , ox , oy ;
int rot , newrot ;
if ( this - > redraw = = true ) {
this - > redraw = false ;
display . clearDisplay ( ) ;
display . fillRect ( 0 , 0 , 127 , 16 , SSD1306_WHITE ) ;
display . setTextColor ( SSD1306_BLACK , SSD1306_WHITE ) ;
display . setTextSize ( 1 ) ;
display . setCursor ( 2 , 4 ) ;
display . println ( title ) ;
ox = ( this - > x - this - > xminimum ) * ( this - > width ) / ( this - > xrange ) + this - > xpos ;
oy = ( this - > value - this - > yminimum ) * ( this - > ypos - this - > height - this - > ypos ) / ( this - > yrange ) + this - > ypos ;
// draw y scale
display . setTextSize ( 1 ) ;
display . setTextColor ( SSD1306_WHITE , SSD1306_BLACK ) ;
for ( i = this - > yminimum ; i < = this - > ymaximum ; i + = this - > yStepSize ) {
// compute the transform
// note my transform funcition is the same as the map function, except the map uses long and we need doubles
temp = ( i - this - > yminimum ) * ( this - > ypos - this - > height - this - > ypos ) / ( this - > ymaximum - this - > yminimum ) + this - > ypos ;
if ( i = = 0 ) {
display . drawFastHLine ( this - > xpos - 3 , temp , this - > width + 3 , SSD1306_WHITE ) ;
}
else {
display . drawFastHLine ( this - > xpos - 3 , temp , 3 , SSD1306_WHITE ) ;
}
display . setCursor ( this - > xpos - 27 , temp - 3 ) ;
display . println ( i , this - > digit ) ;
}
// draw x scale
for ( i = this - > xminimum ; i < = this - > xmaximum ; i + = this - > xStepSize ) {
// compute the transform
display . setTextSize ( 1 ) ;
display . setTextColor ( SSD1306_WHITE , SSD1306_BLACK ) ;
temp = ( i - this - > xminimum ) * ( this - > width ) / ( this - > xrange ) + this - > xpos ;
if ( i = = 0 ) {
display . drawFastVLine ( temp , this - > ypos - this - > height , this - > height + 3 , SSD1306_WHITE ) ;
}
else {
display . drawFastVLine ( temp , this - > ypos , 3 , SSD1306_WHITE ) ;
}
display . setCursor ( temp , this - > ypos + 6 ) ;
display . println ( i , this - > digit ) ;
}
}
// graph drawn now plot the data
// the entire plotting code are these few lines...
this - > x = ( this - > x - this - > xminimum ) * ( this - > width ) / ( this - > xrange ) + this - > xpos ;
this - > value = ( this - > value - this - > yminimum ) * ( this - > ypos - this - > height - this - > ypos ) / ( this - > yrange ) + this - > ypos ;
display . drawLine ( ox , oy , this - > x , this - > value , SSD1306_WHITE ) ;
display . drawLine ( ox , oy - 1 , this - > x , this - > value - 1 , SSD1306_WHITE ) ;
ox = this - > x ;
oy = this - > value ;
if ( ox = = this - > xpos + this - > width )
this - > redraw = true ;
this - > x = 0 ;
// up until now print sends data to a video buffer NOT the screen
// this call sends the data to the screen
display . display ( ) ;
this - > x + + ;
}
}
void redrawFlag ( ) {
this - > redraw = true ;
}
void setPreviousScreen ( int prev ) {
this - > previousScreen = prev ;
}
void setPreviousContentTypeMenu ( bool prev ) {
this - > previousContentTypeMenu = prev ;
}
int getPreviousScreen ( ) {
int prev = this - > previousScreen ;
return prev ;
}
bool getPreviousContentTypeMenu ( ) {
bool prev = this - > previousContentTypeMenu ;
return prev ;
}
void assignValue ( double value ) {
this - > value = value ;
}
} ;
class Screen {
private :
Menu menu [ MAX_MENUS ] ;
int ids [ MAX_MENUS ] ;
int counter = 0 ;
int actualScreen ;
Graph graph [ MAX_GRAPH ] ;
int counterM = 0 ;
int counterG = 0 ;
int currentScreen = 0 ;
bool redraw = true ;
bool contentTypeMenu = true ;
public :
void createMenu ( int id , int sizex , int sizey ) {
this - > menu [ counter ] . configure ( id , sizex , sizey ) ;
counter + + ;
void createMenu ( int sizex , int sizey ) {
this - > menu [ counterM ] . configure ( sizex , sizey ) ;
counterM + + ;
}
void createOption ( int idMenu , String content ) {
int mem = 0 ;
for ( int i = 0 ; i < counter ; i + + ) {
if ( this - > ids [ i ] = = idMenu )
mem = i ;
break ;
}
this - > menu [ mem ] . createOption ( content ) ;
void createOption ( int menuIndex , String content , bool destinationTypeMenu , int destinationIndex ) {
this - > menu [ menuIndex ] . createOption ( content , destinationTypeMenu , destinationIndex ) ;
}
void createGraph ( String title , char graphType , double xpos , double ypos , double width , double height ,
double yminimum , double ymaximum , double xminimum , double xmaximum , double yStepSize , double xStepSize , double digit ) {
this - > graph [ counterG ] . configure ( title , graphType , xpos , ypos , width , height , yminimum , ymaximum , xminimum , xmaximum , yStepSize , xStepSize , digit ) ;
counterG + + ;
}
void redrawFlag ( ) {
this - > redraw = true ;
}
void graphAssignValue ( int graphIndex , double value ) {
this - > graph [ graphIndex ] . assignValue ( value ) ;
this - > redraw = true ;
}
void control ( ) {
if ( redraw ) {
if ( contentTypeMenu ) {
menu [ currentScreen ] . drawMenu ( ) ;
}
else {
graph [ currentScreen ] . drawGraph ( ) ;
}
this - > redraw = false ;
}
}
void increasePos ( ) {
this - > menu [ this - > currentScreen ] . increasePos ( ) ;
}
void decreasePos ( ) {
this - > menu [ this - > currentScreen ] . decreasePos ( ) ;
}
void goTo ( ) {
int newScreen = this - > menu [ this - > currentScreen ] . extractDestinationIndex ( ) ;
bool newContentTypeMenu = this - > menu [ this - > currentScreen ] . extractDestinationTypeMenu ( ) ;
if ( contentTypeMenu ) {
this - > menu [ newScreen ] . setPreviousScreen ( this - > currentScreen ) ;
this - > menu [ newScreen ] . setPreviousContentTypeMenu ( this - > contentTypeMenu ) ;
}
else {
this - > graph [ newScreen ] . setPreviousScreen ( this - > currentScreen ) ;
this - > graph [ newScreen ] . setPreviousContentTypeMenu ( this - > contentTypeMenu ) ;
}
this - > contentTypeMenu = newContentTypeMenu ;
this - > currentScreen = newScreen ;
this - > redraw = true ;
}
void goBack ( ) {
if ( contentTypeMenu ) {
this - > currentScreen = this - > menu [ this - > currentScreen ] . getPreviousScreen ( ) ;
this - > contentTypeMenu = this - > menu [ this - > currentScreen ] . getPreviousContentTypeMenu ( ) ;
}
else {
this - > graph [ this - > currentScreen ] . redrawFlag ( ) ;
this - > currentScreen = this - > graph [ this - > currentScreen ] . getPreviousScreen ( ) ;
this - > contentTypeMenu = this - > graph [ this - > currentScreen ] . getPreviousContentTypeMenu ( ) ;
}
}
} ;
Screen screen ;
void setup ( ) {
setDisp ( true ) ;
screen . createMenu ( 128 , 9 ) ;
/*String title, char graphType, double xpos, double ypos, double width, double height,
double yminimum , double ymaximum , double xminimum , double xmaximum , double yStepSize , double xStepSize , double digit */
screen . createGraph ( " Grafica 1 " , ' a ' , 25 , 60 , 40 , 40 , 0 , 100 , 0 , 0 , 10 , 0 , 0 ) ;
screen . createGraph ( " Grafica 2 " , ' b ' , 10 , 60 , 100 , 20 , 0 , 0 , 0 , 100 , 0 , 10 , 0 ) ;
screen . createGraph ( " Grafica 3 " , ' c ' , 30 , 50 , 75 , 30 , 0 , 1024 , 0 , 10 , 100 , 10 , 0 ) ;
screen . createOption ( 0 , " Grafica vertical " , false , 0 ) ;
screen . createOption ( 0 , " Grafica horizontal " , false , 1 ) ;
screen . createOption ( 0 , " Grafica cartesiana " , false , 2 ) ;
}
void loop ( ) {
screen . control ( ) ;
delay ( 10 ) ;
}