|
| 1 | +/****************** |
| 2 | +This is my development file... not a good example |
| 3 | +Rui Azevedo 2014 |
| 4 | + |
| 5 | +********/ |
| 6 | + |
| 7 | +#include <VPinsI2C.h> |
| 8 | +#include <virtual_pins.h> |
| 9 | +#include <HardwareSerial.h> |
| 10 | +#include <LiquidCrystal.h> |
| 11 | +#include <menu.h>//menu macros and objects |
| 12 | +#include <pcint.h>//this is incompatible with software serial (arduino needs an handler!) |
| 13 | +#include <quadEncoder.h>//quadrature encoder driver and fake stream |
| 14 | +#include <keyStream.h>//keyboard driver and fake stream (for the encoder button) |
| 15 | +#include <chainStream.h>// concatenate multiple input streams (this allows adding a button to the encoder) |
| 16 | +#include <menuPrint.h>//Print (Serial) menu |
| 17 | + |
| 18 | +#define LCDWIRE_NONE 0 |
| 19 | +#define LCDWIRE_VPINS_I2C 1 |
| 20 | +#define LCDWIRE_VPINS_SPI 2 |
| 21 | +#define LCDWIRE_I2C 3 |
| 22 | +#define LCDWIRE_DIRECT 4 |
| 23 | + |
| 24 | +//how the LCD is wired |
| 25 | +//#define LCD_WIRE LCDWIRE_NONE |
| 26 | +//#define LCD_WIRE LCDWIRE_VPINS_I2C |
| 27 | +#define LCD_WIRE LCDWIRE_VPINS_SPI//on shift registers thru vpins (same library) |
| 28 | +//#define LCD_WIRE LCDWIRE_I2C//not tested |
| 29 | +//#define LCD_WIRE LCDWIRE_DIRECT//not tested |
| 30 | + |
| 31 | +#define USE_TFT 1//0|1 |
| 32 | + #define tftCS 5 |
| 33 | + |
| 34 | +#if (USE_TFT == 1) |
| 35 | + #include <Adafruit_GFX.h> // Co1re graphics library |
| 36 | + #include <Adafruit_ST7735.h> // Hardware-specific library |
| 37 | + #include <menuGFX.h> |
| 38 | + |
| 39 | + /////////////////////////////////////////////////////////////////////////// |
| 40 | + //TFT + SD |
| 41 | + //#define sdCS 4 |
| 42 | + #define dc 6 |
| 43 | + #define rst 7 // you can also connect this to the Arduino reset |
| 44 | + |
| 45 | + Adafruit_ST7735 tft(tftCS, dc, rst); |
| 46 | +#endif |
| 47 | + |
| 48 | +#define vpinsSPI_CS 9//vpins SPI CS |
| 49 | +#if (LCD_WIRE == LCDWIRE_VPINS_SPI)//LCD wired on shift registers using vpins |
| 50 | + #include <SPI.h> |
| 51 | + #include <VPinsSPI.h> |
| 52 | + #include "menuLCD.h" |
| 53 | + #define STCP 9//stcp or latch pin |
| 54 | + |
| 55 | + #define RS 26 |
| 56 | + //#define RW 25 |
| 57 | + #define EN 24 |
| 58 | + SPIBranch spi(SPI,STCP,VPA,1);//TODO: add version that finds a free port and make pin() fynctions the only methid to get a pin number |
| 59 | + LiquidCrystal lcd1(RS,EN,20,21,22,23); |
| 60 | +#endif |
| 61 | + |
| 62 | +#if (LCD_WIRE == LCDWIRE_VPINS_I2C)// LCD is wired over i2c to another AVR that uses virtual pins and shift registers to control it and virtual port server to share it |
| 63 | + #include <Wire.h> |
| 64 | + #include "menuLCD.h" |
| 65 | + //remote pins over I2C to VPort server |
| 66 | + #define vpinsSPI_CS srv_pb.pin(1)//vpins SPI CS |
| 67 | + #define STCP srv_pb.pin(1)//stcp or latch pin |
| 68 | + |
| 69 | + //setup i2c network and port/pin/device maps |
| 70 | + // my LCD is remote wired... other LCD's should initialize as usual |
| 71 | + I2CServerBranch srv_vpa(Wire,0x11,VPA,VPA,1);//virtual (spi) port on i2c vport server (2 bytes) |
| 72 | + I2CServerBranch srv_pb(Wire,0x11,VPB,PB,1);//physical port B on i2c vport server is now local virtual port VPB (tied) |
| 73 | + I2CServerBranch srv_pc(Wire,0x11,VPC,PC,1);//physical port C on i2c vport server is now local virtual port VPC (tied) |
| 74 | + I2CServerBranch srv_pd(Wire,0x11,VPD,PD,1);//physical port D on i2c vport server is now local virtual port VPD (tied) |
| 75 | + //here wiring the LCD screen and other stuff over the I2C network... |
| 76 | + LiquidCrystal lcd1(srv_vpa.pin(6), srv_vpa.pin(4), srv_vpa.pin(0), srv_vpa.pin(1), srv_vpa.pin(2), srv_vpa.pin(3)); |
| 77 | +#endif |
| 78 | + |
| 79 | +/////////////////////////////////////////////////////////////////////////////// |
| 80 | +//set CS pins for LCD or TFT |
| 81 | +void selectLCD() { |
| 82 | + digitalWrite(vpinsSPI_CS,LOW); |
| 83 | + digitalWrite(tftCS,LOW); |
| 84 | +} |
| 85 | + |
| 86 | +void selectTFT() { |
| 87 | + digitalWrite(vpinsSPI_CS,HIGH); |
| 88 | + digitalWrite(tftCS,HIGH); |
| 89 | +} |
| 90 | + |
| 91 | +//////////////////////////////////////////// |
| 92 | +// ENCODER (aka rotary switch) PINS |
| 93 | +// rotary |
| 94 | +#define encA 2 |
| 95 | +#define encB 4 |
| 96 | +//this encoder has a button here |
| 97 | +#define encBtn A0 |
| 98 | +#define LEDPIN A3//on uno use pin 13 |
| 99 | + |
| 100 | +/////////////////////////////////////////////////////////////////////////// |
| 101 | +//functions to wire as menu actions |
| 102 | + |
| 103 | +//aux function |
| 104 | +void nothing() {} |
| 105 | + |
| 106 | +void setValue(int &value,prompt &p,menuOut &o, Stream &i,const char* text,const char* units="",int sensivity=5,int low=0,int hi=100,int steps=0,void (*func)()=nothing); |
| 107 | + |
| 108 | +void ledOn() {digitalWrite(LEDPIN,1);} |
| 109 | +void ledOff() {digitalWrite(LEDPIN,0);} |
| 110 | +void disabledTest(prompt &p,menuOut &o,Stream &i) { |
| 111 | + o.clear(); |
| 112 | + o.setCursor(0,0); |
| 113 | + o.print("THIS IS AN ERROR, this option should never be called as it is disabled"); |
| 114 | + while(i.read()!=13); |
| 115 | +} |
| 116 | + |
| 117 | +int frequency=100; |
| 118 | +void setFreq(prompt &p,menuOut &o,Stream &i) {setValue(frequency,p,o,i,"Freq:","0 Hz",20,1,1000);} |
| 119 | + |
| 120 | +int dutty=50; |
| 121 | +void setDutty(prompt &p,menuOut &o,Stream &i) {setValue(dutty,p,o,i,"Dutty:","%",1,0,100);} |
| 122 | + |
| 123 | +void completeHandlerTest(prompt &p,menuOut &o,Stream &i) { |
| 124 | + o.clear(); |
| 125 | + o.setCursor(0,0); |
| 126 | + o.print("Handler test ok!"); |
| 127 | + while(i.read()!=13); |
| 128 | +} |
| 129 | + |
| 130 | +int stv=8; |
| 131 | +void scrollUp_test(prompt &p,menuOut &o,Stream &i); |
| 132 | +void scrollDown_test(prompt &p,menuOut &o,Stream &i); |
| 133 | + |
| 134 | +///////////////////////////////////////////////////////////////////////// |
| 135 | +// MENU DEFINITION |
| 136 | +// here we define the menu structure and wire actions functions to it |
| 137 | +MENU(subMenu,"LED ON/OFF", |
| 138 | + OP("LED On",ledOn), |
| 139 | + OP("LED Off",ledOff) |
| 140 | +); |
| 141 | + |
| 142 | +MENU(mainMenu,"Sistema", |
| 143 | + OP("Frequency",setFreq), |
| 144 | + OP("Dutty",setDutty), |
| 145 | + OP("Disabled",disabledTest), |
| 146 | + /*OP("Scroll up", scrollUp_test), |
| 147 | + OP("scroll down", scrollDown_test), |
| 148 | + OP("Handler test",completeHandlerTest), |
| 149 | + OP("Handler test",completeHandlerTest), |
| 150 | + OP("Handler test",completeHandlerTest), |
| 151 | + OP("Handler test",completeHandlerTest), |
| 152 | + OP("Handler test",completeHandlerTest), |
| 153 | + OP("Handler test",completeHandlerTest), |
| 154 | + OP("Handler test",completeHandlerTest), |
| 155 | + OP("Handler test",completeHandlerTest), |
| 156 | + OP("Handler test",completeHandlerTest), |
| 157 | + OP("Handler test",completeHandlerTest),*/ |
| 158 | + SUBMENU(subMenu) |
| 159 | +); |
| 160 | + |
| 161 | +//the quadEncoder |
| 162 | +quadEncoder quadEncoder(encA,encB);//simple quad encoder driver |
| 163 | +quadEncoderStream enc(quadEncoder,5);// simple quad encoder fake Stream |
| 164 | + |
| 165 | +//a keyboard with only one key :D, this is the encoder button |
| 166 | +keyMap encBtn_map[]={{-encBtn,13}};//negative pin numbers means we have a pull-up, this is on when low |
| 167 | +keyLook<1> encButton(encBtn_map); |
| 168 | + |
| 169 | +//multiple inputs allow conjugation of the quadEncoder with a single key keyboard that is the quadEncoder button |
| 170 | +Stream* in[]={&enc,&encButton}; |
| 171 | +chainStream<2> quadEncoder_button(in); |
| 172 | + |
| 173 | +//alternative to previous but now we can input from Serial too... |
| 174 | +Stream* in3[]={&enc,&encButton,&Serial}; |
| 175 | +chainStream<3> allIn(in3); |
| 176 | + |
| 177 | +//describing a menu output, alternatives so far are Serial or LiquidCrystal LCD |
| 178 | +menuPrint serial(Serial); |
| 179 | +#if (LCD_WIRE!=LCDWIRE_NONE) |
| 180 | + menuLCD lcd(lcd1,16,2); |
| 181 | +#endif |
| 182 | +#if (USE_TFT == 1) |
| 183 | + menuGFX gfx(tft); |
| 184 | + //menuGFX gfx(tft,BLUE,BLACK,WHITE,SILVER,5,8); |
| 185 | +#endif |
| 186 | +menuPrint menuSerialOut(Serial);//describe output device |
| 187 | + |
| 188 | +///////////////////////////////////////////////////////////////////////// |
| 189 | +void setup() { |
| 190 | + mainMenu.data[2]->enabled=false;//disabling option |
| 191 | + |
| 192 | + Serial.begin(9600); |
| 193 | + Serial.println("menu system test"); |
| 194 | + |
| 195 | +#if ((LCD_WIRE != LCDWIRE_NONE) || (USE_TFT == 1)) |
| 196 | + pinMode(vpinsSPI_CS,OUTPUT); |
| 197 | + digitalWrite(vpinsSPI_CS,LOW); |
| 198 | +#endif |
| 199 | + |
| 200 | +#if (LCD_WIRE == LCDWIRE_VPINS_SPI) |
| 201 | + SPI.begin(); |
| 202 | + lcd1.begin(16,2); |
| 203 | + lcd1.print("Menu test"); |
| 204 | +#endif |
| 205 | + |
| 206 | +#if (LCD_WIRE == LCDWIRE_VPINS_I2C) |
| 207 | + Wire.begin(); |
| 208 | + // LCD is wired over i2c to another AVR that uses virtual pins and shift registers to control it and virtual port server to share it Serial.println("waiting for servers..."); |
| 209 | + srv_vpa.begin();// wait for server ready (all on same server, so) |
| 210 | + //srv_vpb.begin();// wait for server ready |
| 211 | + Serial.println("all servers ready!"); |
| 212 | + |
| 213 | +#endif |
| 214 | + |
| 215 | +#if (USE_TFT == 1) |
| 216 | + digitalWrite(vpinsSPI_CS,HIGH); |
| 217 | + digitalWrite(tftCS,HIGH); |
| 218 | + tft.initR(INITR_BLACKTAB); |
| 219 | + tft.setRotation(3); |
| 220 | + tft.setTextWrap(false); |
| 221 | + tft.setTextColor(ST7735_RED); |
| 222 | + tft.setTextSize(2); |
| 223 | + gfx.resX*=2;//update resolution after font size change |
| 224 | + gfx.resY*=2;//update resolution after font size change |
| 225 | + tft.fillScreen(ST7735_BLACK); |
| 226 | + tft.print("Menu test on GFX"); |
| 227 | + tft.setCursor(0,10); |
| 228 | + //update limits after screen rotation |
| 229 | + gfx.maxX=tft.width()/gfx.resX; |
| 230 | + gfx.maxY=tft.height()/gfx.resY; |
| 231 | +#endif |
| 232 | + |
| 233 | + pinMode(encBtn, INPUT); |
| 234 | + digitalWrite(encBtn,1); |
| 235 | + |
| 236 | + pinMode(LEDPIN,OUTPUT); |
| 237 | + |
| 238 | + delay(300); |
| 239 | +} |
| 240 | + |
| 241 | +/////////////////////////////////////////////////////////////////////////////// |
| 242 | +// testing the menu system |
| 243 | +void loop() { |
| 244 | + //mainMenu.activate(menuSerialOut,Serial);//show menu to Serial and read keys from Serial |
| 245 | + //Serial.println(""); |
| 246 | + //Serial.println("Restarting..."); |
| 247 | + |
| 248 | + #if (LCD_WIRE != LCDWIRE_NONE) |
| 249 | + //digitalWrite(vpinsSPI_CS,LOW); |
| 250 | + //digitalWrite(tftCS,LOW); |
| 251 | + //mainMenu.activate(lcd,allIn);//show menu on LCD and use multiple inputs to navigate (defined encoder, encoder button, serial) |
| 252 | + //mainMenu.activate(lcd,Serial);//very bad combination! |
| 253 | + #endif |
| 254 | + |
| 255 | + #if (USE_TFT == 1) |
| 256 | + digitalWrite(vpinsSPI_CS,HIGH); |
| 257 | + digitalWrite(tftCS,HIGH); |
| 258 | + mainMenu.activate(gfx,allIn);//show menu on LCD and use multiple inputs to navigate (defined encoder, encoder button, serial) |
| 259 | + #endif |
| 260 | + |
| 261 | +} |
| 262 | + |
| 263 | +void percentBar(menuOut &o,int percent) { |
| 264 | + int i=map(percent, 0, 100, 0, o.maxX); |
| 265 | + for(int n=0;n<o.maxX;n++) |
| 266 | + o.print((char)(n<i?255:' ')); |
| 267 | +} |
| 268 | + |
| 269 | +//read a value from the input stream device (encoder or serial) |
| 270 | +void setValue(int &value,prompt &p,menuOut &o, Stream &i,const char* text,const char* units,int sensivity,int low,int hi,int steps,void (*func)()) { |
| 271 | + o.clear(); |
| 272 | + int at=strlen(text);//.length(); |
| 273 | + o.setCursor(0,0); |
| 274 | + o.print(text); |
| 275 | + /*if (o.style==menuOut::enumerated) {//probably a Serial terminal ------------------------------------- |
| 276 | + //long timeout because some terminals send data righ away when typed, and parseInt would parse a partial number |
| 277 | + i.setTimeout(10000);//lib gives no access to previous timeout value :( ... cant restore it then, i would wait forever if possible |
| 278 | + value=i.parseInt();//assuming data was all delivered to the buffer (we had a large timeout) |
| 279 | + //clamp the entry |
| 280 | + if (value>hi) value=hi; |
| 281 | + else if (value<low) value=low; |
| 282 | + i.setTimeout(1000);//assuming it was default |
| 283 | + Serial.println(value);//feed back |
| 284 | + while(i.available()) i.read();//clean up extra characters to avoid reentry |
| 285 | + } else {*/// then we assume its some kind of encoder --------------------------------------------------- |
| 286 | + if (!steps) steps=(hi-low)/(float)o.maxX; |
| 287 | + float fact=((float)sensivity)/((float)steps);//sensivity factor |
| 288 | + float pos=quadEncoder.pos*fact; |
| 289 | + float last=pos; |
| 290 | + while(encButton.read()!=13) { |
| 291 | + //clamp value |
| 292 | + if (value>hi) value=hi; |
| 293 | + else if (value<low) value=low; |
| 294 | + o.setCursor(at,0); |
| 295 | + o.print(value); |
| 296 | + o.print(units); |
| 297 | + o.print(" "); |
| 298 | + o.setCursor(0,1); |
| 299 | + percentBar(o,map(value,low,hi,0,100)); |
| 300 | + pos=quadEncoder.pos*fact; |
| 301 | + int delta=pos-last; |
| 302 | + if (delta) { |
| 303 | + value+=delta; |
| 304 | + last=pos; |
| 305 | + } |
| 306 | + //func(); |
| 307 | + } |
| 308 | + delay(100); |
| 309 | + while(encButton.read()==13); |
| 310 | + //} |
| 311 | +} |
| 312 | + |
0 commit comments