Skip to content

Commit 18d6f0f

Browse files
authored
Merge pull request #256 from nathandarnell/master
ESP32 example with a rotary encoder and TFT using TFT_eSPI library
2 parents 6cc23db + cf119c7 commit 18d6f0f

File tree

1 file changed

+232
-0
lines changed

1 file changed

+232
-0
lines changed

examples/ESP32/ClickEncoderTFT.ino

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
#include <Arduino.h>
2+
#include <TFT_eSPI.h>
3+
// Pin Description for this screen:
4+
// https://www.arthurwiz.com/software-development/177-inch-tft-lcd-display-with-st7735s-on-arduino-mega-2560
5+
// GND - GND
6+
// VCC - 3.3v
7+
// SCK - TFT_SCLK 5
8+
// SDA - TFT_MOSI 18
9+
// RES - TFT_RST 22
10+
// RS - TFT_DC 21
11+
// CS - TFT_CS 19
12+
// LEDA- 3.3v
13+
#include <menu.h>
14+
#include <menuIO/TFT_eSPIOut.h>
15+
#include <streamFlow.h>
16+
#include <ClickEncoder.h>
17+
// Using this library: https://github.com/soligen2010/encoder.git
18+
#include <menuIO/clickEncoderIn.h>
19+
#include <menuIO/keyIn.h>
20+
#include <menuIO/chainStream.h>
21+
#include <menuIO/serialIO.h>
22+
// For debugging the TFT_eSPIOut.h library
23+
#include <menuIO/serialOut.h>
24+
#include <menuIO/serialIn.h>
25+
26+
using namespace Menu;
27+
28+
// Declare pins for rotary encoder
29+
#define encA 4
30+
#define encB 15
31+
#define encBtn 2
32+
#define encSteps 4
33+
34+
// Setup TFT colors. Probably stop using these and use the colors defined by ArduinoMenu
35+
#define BACKCOLOR TFT_BLACK
36+
#define TEXTCOLOR TFT_WHITE
37+
38+
int chooseField = 1;
39+
int cutsMade = 0;
40+
int numberOfCuts = 5;
41+
int lengthOfCuts = 50; // Length in mm
42+
int feedLength = 304;
43+
int exitMenuOptions = 0; //Forces the menu to exit and cut the copper tape
44+
45+
// Declare the clickencoder
46+
// Disable doubleclicks in setup makes the response faster. See: https://github.com/soligen2010/encoder/issues/6
47+
ClickEncoder clickEncoder = ClickEncoder(encA, encB, encBtn, encSteps);
48+
ClickEncoderStream encStream(clickEncoder, 1);
49+
50+
// TFT gfx is what the ArduinoMenu TFT_eSPIOut.h is expecting
51+
TFT_eSPI gfx = TFT_eSPI();
52+
53+
void feedInOut(); // Function to manually feed the tape without cutting
54+
void runCuts(); // Main loop that feeds tape and calls servoCuts()
55+
void IRAM_ATTR onTimer(); // Start the timer to read the clickEncoder every 1 ms
56+
57+
//////////////////////////////////////////////////////////
58+
// Start ArduinoMenu
59+
//////////////////////////////////////////////////////////
60+
61+
result doFeed()
62+
{
63+
delay(500);
64+
exitMenuOptions = 2;
65+
return proceed;
66+
}
67+
68+
result doRunCuts()
69+
{
70+
delay(500);
71+
exitMenuOptions = 1;
72+
return proceed;
73+
}
74+
75+
result updateEEPROM()
76+
{
77+
// writeEEPROM();
78+
return quit;
79+
}
80+
81+
#define MAX_DEPTH 3
82+
83+
MENU(subMenuAdjustServo, "Adjust Servo Settings", doNothing, noEvent, noStyle
84+
// ,FIELD(settingsEEPROM.servoOpen, "Servo Open", " degrees", 0, 180, 10, 1, doNothing, noEvent, noStyle)
85+
// ,FIELD(settingsEEPROM.servoClosed, "Servo Closed", " degrees", 0, 180, 10, 1, doNothing, noEvent, noStyle)
86+
// ,SUBMENU(subMenu)
87+
,
88+
OP("Run!", doFeed, enterEvent), EXIT("<Back"));
89+
90+
CHOOSE(chooseField, feedDirChoose, "Choose Direction:", doNothing, noEvent, noStyle, VALUE("Forward", 1, doNothing, noEvent), VALUE("Backwards", 0, doNothing, noEvent));
91+
92+
MENU(subMenuFeedInOut, "Feed Tape", doNothing, noEvent, noStyle, FIELD(feedLength, "Length of Feed:", "mm", 0, 1000, 10, 1, doNothing, noEvent, noStyle), SUBMENU(feedDirChoose), OP("Run!", doFeed, enterEvent), EXIT("<Back"));
93+
94+
MENU(mainMenu, "COPPER TAPE CUTTER", doNothing, noEvent, wrapStyle, FIELD(lengthOfCuts, "Cut Size:", "mm", 0, 2000, 10, 1, doNothing, noEvent, noStyle), FIELD(numberOfCuts, "Pieces:", "", 0, 1000, 10, 1, doNothing, noEvent, noStyle), OP("Cut!", doRunCuts, enterEvent), SUBMENU(subMenuFeedInOut), SUBMENU(subMenuAdjustServo));
95+
96+
// define menu colors --------------------------------------------------------
97+
#define Black RGB565(0,0,0)
98+
#define Red RGB565(255,0,0)
99+
#define Green RGB565(0,255,0)
100+
#define Blue RGB565(0,0,255)
101+
#define Gray RGB565(128,128,128)
102+
#define LighterRed RGB565(255,150,150)
103+
#define LighterGreen RGB565(150,255,150)
104+
#define LighterBlue RGB565(150,150,255)
105+
#define LighterGray RGB565(211,211,211)
106+
#define DarkerRed RGB565(150,0,0)
107+
#define DarkerGreen RGB565(0,150,0)
108+
#define DarkerBlue RGB565(0,0,150)
109+
#define Cyan RGB565(0,255,255)
110+
#define Magenta RGB565(255,0,255)
111+
#define Yellow RGB565(255,255,0)
112+
#define White RGB565(255,255,255)
113+
#define DarkerOrange RGB565(255,140,0)
114+
115+
// TFT color table
116+
const colorDef<uint16_t> colors[] MEMMODE = {
117+
//{{disabled normal,disabled selected},{enabled normal,enabled selected, enabled editing}}
118+
{{(uint16_t)Black, (uint16_t)Black}, {(uint16_t)Black, (uint16_t)Red, (uint16_t)Red}}, //bgColor
119+
{{(uint16_t)White, (uint16_t)White}, {(uint16_t)White, (uint16_t)White, (uint16_t)White}},//fgColor
120+
{{(uint16_t)Red, (uint16_t)Red}, {(uint16_t)Yellow, (uint16_t)Yellow, (uint16_t)Yellow}}, //valColor
121+
{{(uint16_t)White, (uint16_t)White}, {(uint16_t)White, (uint16_t)White, (uint16_t)White}}, //unitColor
122+
{{(uint16_t)White, (uint16_t)Gray}, {(uint16_t)Black, (uint16_t)Red, (uint16_t)White}}, //cursorColor
123+
{{(uint16_t)White, (uint16_t)Yellow}, {(uint16_t)Black, (uint16_t)Red, (uint16_t)Red}}, //titleColor
124+
};
125+
126+
127+
// Define the width and height of the TFT and how much of it to take up
128+
#define GFX_WIDTH 160
129+
#define GFX_HEIGHT 128
130+
#define fontW 6
131+
#define fontH 9
132+
133+
constMEM panel panels[] MEMMODE = {{0, 0, GFX_WIDTH / fontW, GFX_HEIGHT / fontH}}; // Main menu panel
134+
navNode* nodes[sizeof(panels) / sizeof(panel)]; //navNodes to store navigation status
135+
panelsList pList(panels, nodes, sizeof(panels) / sizeof(panel)); //a list of panels and nodes
136+
//idx_t tops[MAX_DEPTH]={0,0}; // store cursor positions for each level
137+
idx_t eSpiTops[MAX_DEPTH] = {0};
138+
TFT_eSPIOut eSpiOut(gfx, colors, eSpiTops, pList, fontW, fontH + 1);
139+
idx_t serialTops[MAX_DEPTH] = {0};
140+
serialOut outSerial(Serial, serialTops);
141+
menuOut *constMEM outputs[] MEMMODE = {&outSerial, &eSpiOut}; //list of output devices
142+
outputsList out(outputs, sizeof(outputs) / sizeof(menuOut *)); //outputs list
143+
serialIn serial(Serial);
144+
MENU_INPUTS(in, &encStream, &serial); // &encButton,
145+
NAVROOT(nav, mainMenu, MAX_DEPTH, in, out);
146+
147+
// ESP32 timer thanks to: http://www.iotsharing.com/2017/06/how-to-use-interrupt-timer-in-arduino-esp32.html
148+
// and: https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
149+
hw_timer_t *timer = NULL;
150+
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
151+
152+
//////////////////////////////////////////////////////////
153+
// End Arduino Menu
154+
//////////////////////////////////////////////////////////
155+
156+
void setup()
157+
{
158+
Serial.begin(115200);
159+
delay(3000);
160+
161+
clickEncoder.setAccelerationEnabled(true);
162+
clickEncoder.setDoubleClickEnabled(false); // Disable doubleclicks makes the response faster. See: https://github.com/soligen2010/encoder/issues/6
163+
164+
// // ESP32 timer
165+
timer = timerBegin(0, 80, true);
166+
timerAttachInterrupt(timer, &onTimer, true);
167+
timerAlarmWrite(timer, 1000, true);
168+
timerAlarmEnable(timer);
169+
170+
// Use this initializer if you're using a 1.8" TFT
171+
// SPI.begin();
172+
gfx.init(); // Initialize a ST7735S chip
173+
gfx.setRotation(0); // Set the rotation (0-3) to vertical
174+
Serial.println("Initialized ST7735S TFT");
175+
gfx.fillScreen(TFT_BLACK);
176+
Serial.println("done");
177+
178+
179+
nav.showTitle = true; // Show titles in the menus and submenus
180+
// nav.timeOut = 60; // Timeout after 60 seconds of inactivity
181+
// nav.idleOn(); // Start with the main screen and not the menu
182+
}
183+
184+
void loop()
185+
{
186+
// Slow down the menu redraw rate
187+
constexpr int menuFPS = 1000 / 30;
188+
static unsigned long lastMenuFrame = -menuFPS;
189+
unsigned long now = millis();
190+
//... other stuff on loop, will keep executing
191+
switch (exitMenuOptions)
192+
{
193+
case 1:
194+
{
195+
delay(500); // Pause to allow the button to come up
196+
runCuts();
197+
break;
198+
}
199+
case 2:
200+
{
201+
delay(500); // Pause to allow the button to come up
202+
feedInOut();
203+
break;
204+
}
205+
default: // Do the normal program functions with ArduinoMenu
206+
if (now - lastMenuFrame >= menuFPS)
207+
{
208+
lastMenuFrame = millis();
209+
nav.poll(); // Poll the input devices
210+
}
211+
}
212+
}
213+
214+
void runCuts()
215+
{
216+
exitMenuOptions = 0; // Return to the menu
217+
delay(500);
218+
mainMenu.dirty = true; // Force the main menu to redraw itself
219+
}
220+
221+
void feedInOut()
222+
{
223+
exitMenuOptions = 0; // Return to the menu
224+
delay(500);
225+
mainMenu.dirty = true; // Force the main menu to redraw itself
226+
}
227+
228+
// ESP32 timer
229+
void IRAM_ATTR onTimer()
230+
{
231+
clickEncoder.service();
232+
}

0 commit comments

Comments
 (0)