Skip to content

Commit e09f2ff

Browse files
committed
groveRGBLCD: Add support for I2C Grove RGB LCD
Add support for the Grove RGB LCD: https://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/ along with example file. This was as simple as replacing a standard 'lcd' element with the correct header and an 'rgb_lcd' object. Tested on a PJRC Teensy 4.0 board with a KY-040 click shaft encoder. Signed-off-by: Graham Whaley <graham.whaley@gmail.com>
1 parent 6d7dd1c commit e09f2ff

File tree

4 files changed

+270
-0
lines changed

4 files changed

+270
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,10 @@ https://github.com/neu-rah/AnsiStream
283283
284284
- Unix terminal
285285
286+
**Grove RGB LCD I2C 2x16**
287+
288+
https://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/
289+
286290
**Web browser**
287291
288292
- ESP8266 (builtin)
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
#include <Arduino.h>
2+
3+
/********************
4+
Sept. 2014 Rui Azevedo - ruihfazevedo(@rrob@)gmail.com
5+
Nov. 2020 Graham Whaley - adapted to Grove RGB LCD
6+
7+
menu output to Grove RGB LCD I2C
8+
output: GROVERGBLCD : https://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/
9+
input: click encoder and Serial
10+
board: PJRC Teensy 4.0 : https://www.pjrc.com/store/teensy40.html
11+
***/
12+
13+
#include <Wire.h>
14+
#include <menu.h>
15+
#include <menuIO/groveRGBLCDOut.h>
16+
#include <menuIO/serialOut.h>
17+
#include <menuIO/serialIn.h>
18+
#include <menuIO/clickEncoderIn.h>
19+
#include <menuIO/chainStream.h>
20+
21+
using namespace Menu;
22+
23+
// LCD, standard Grove I2C devices /////////////
24+
rgb_lcd lcd;
25+
26+
// Encoder /////////////////////////////////////
27+
#define encA 3
28+
#define encB 2
29+
//this encoder has a button here
30+
#define encBtn 4
31+
32+
ClickEncoder clickEncoder(encA,encB,encBtn,2);
33+
ClickEncoderStream encStream(clickEncoder,1);
34+
35+
//input from the clickencoder + serial
36+
serialIn serial(Serial);
37+
menuIn* inputsList[]={&encStream,&serial};
38+
chainStream<2> in(inputsList);//3 is the number of inputs
39+
40+
#define LEDPIN LED_BUILTIN //Teensy 4.0 LED pin
41+
42+
result doAlert(eventMask e, prompt &item);
43+
44+
result showEvent(eventMask e,navNode& nav,prompt& item) {
45+
Serial.print("event: ");
46+
Serial.println(e);
47+
return proceed;
48+
}
49+
50+
int test=55;
51+
52+
result action1(eventMask e,navNode& nav, prompt &item) {
53+
Serial.print("action1 event: ");
54+
Serial.print(e);
55+
Serial.println(", proceed menu");
56+
Serial.flush();
57+
return proceed;
58+
}
59+
60+
result action2(eventMask e,navNode& nav, prompt &item) {
61+
Serial.print("action2 event: ");
62+
Serial.print(e);
63+
Serial.print(", quiting menu.");
64+
Serial.flush();
65+
return quit;
66+
}
67+
68+
int ledCtrl=LOW;
69+
70+
result myLedOn() {
71+
ledCtrl=HIGH;
72+
return proceed;
73+
}
74+
result myLedOff() {
75+
ledCtrl=LOW;
76+
return proceed;
77+
}
78+
79+
TOGGLE(ledCtrl,setLed,"Led: ",doNothing,noEvent,noStyle//,doExit,enterEvent,noStyle
80+
,VALUE("On",HIGH,doNothing,noEvent)
81+
,VALUE("Off",LOW,doNothing,noEvent)
82+
);
83+
84+
int selTest=0;
85+
SELECT(selTest,selMenu,"Select",doNothing,noEvent,noStyle
86+
,VALUE("Zero",0,doNothing,noEvent)
87+
,VALUE("One",1,doNothing,noEvent)
88+
,VALUE("Two",2,doNothing,noEvent)
89+
);
90+
91+
int chooseTest=-1;
92+
CHOOSE(chooseTest,chooseMenu,"Choose",doNothing,noEvent,noStyle
93+
,VALUE("First",1,doNothing,noEvent)
94+
,VALUE("Second",2,doNothing,noEvent)
95+
,VALUE("Third",3,doNothing,noEvent)
96+
,VALUE("Last",-1,doNothing,noEvent)
97+
);
98+
99+
//customizing a prompt look!
100+
//by extending the prompt class
101+
class altPrompt:public prompt {
102+
public:
103+
altPrompt(constMEM promptShadow& p):prompt(p) {}
104+
Used printTo(navRoot &root,bool sel,menuOut& out, idx_t idx,idx_t len,idx_t) override {
105+
return out.printRaw(F("special prompt!"),len);;
106+
}
107+
};
108+
109+
MENU(subMenu,"Sub-Menu",showEvent,anyEvent,noStyle
110+
,OP("Sub1",showEvent,anyEvent)
111+
,OP("Sub2",showEvent,anyEvent)
112+
,OP("Sub3",showEvent,anyEvent)
113+
,altOP(altPrompt,"",showEvent,anyEvent)
114+
,EXIT("<Back")
115+
);
116+
117+
/*extern menu mainMenu;
118+
TOGGLE((mainMenu[1].enabled),togOp,"Op 2:",doNothing,noEvent,noStyle
119+
,VALUE("Enabled",enabledStatus,doNothing,noEvent)
120+
,VALUE("disabled",disabledStatus,doNothing,noEvent)
121+
);*/
122+
123+
// char* constMEM hexDigit MEMMODE="0123456789ABCDEF";
124+
// char* constMEM hexNr[] MEMMODE={"0","x",hexDigit,hexDigit};
125+
// char buf1[]="0x11";
126+
127+
MENU(mainMenu,"Main menu",doNothing,noEvent,wrapStyle
128+
,OP("Op1",action1,anyEvent)
129+
,OP("Op2",action2,enterEvent)
130+
//,SUBMENU(togOp)
131+
,FIELD(test,"Test","%",0,100,10,1,doNothing,noEvent,wrapStyle)
132+
,SUBMENU(subMenu)
133+
,SUBMENU(setLed)
134+
,OP("LED On",myLedOn,enterEvent)
135+
,OP("LED Off",myLedOff,enterEvent)
136+
,SUBMENU(selMenu)
137+
,SUBMENU(chooseMenu)
138+
,OP("Alert test",doAlert,enterEvent)
139+
// ,EDIT("Hex",buf1,hexNr,doNothing,noEvent,noStyle)
140+
,EXIT("<Back")
141+
);
142+
143+
//const panel panels[] MEMMODE={{0,0,16,2}};
144+
//navNode* nodes[sizeof(panels)/sizeof(panel)];
145+
//panelsList pList(panels,nodes,1);
146+
147+
#define MAX_DEPTH 2
148+
/*idx_t tops[MAX_DEPTH];
149+
liquidCrystalOut outLCD(lcd,tops,pList);//output device for LCD
150+
menuOut* constMEM outputs[] MEMMODE={&outLCD};//list of output devices
151+
outputsList out(outputs,1);//outputs list with 2 outputs*/
152+
153+
MENU_OUTPUTS(out, MAX_DEPTH
154+
,GROVERGBLCD_OUT(lcd, {0, 0, 16, 2})
155+
,NONE
156+
);
157+
NAVROOT(nav,mainMenu,MAX_DEPTH,in,out);//the navigation root object
158+
159+
result alert(menuOut& o,idleEvent e) {
160+
if (e==idling) {
161+
o.setCursor(0,0);
162+
o.print("alert test");
163+
o.setCursor(0,1);
164+
o.print("[select] to continue...");
165+
}
166+
return proceed;
167+
}
168+
169+
result doAlert(eventMask e, prompt &item) {
170+
nav.idleOn(alert);
171+
return proceed;
172+
}
173+
174+
result idle(menuOut& o,idleEvent e) {
175+
switch(e) {
176+
case idleStart:o.print("suspending menu!");break;
177+
case idling:o.print("suspended...");break;
178+
case idleEnd:o.print("resuming menu.");break;
179+
}
180+
return proceed;
181+
}
182+
183+
void setup() {
184+
pinMode(encBtn,INPUT_PULLUP);
185+
pinMode(LEDPIN,OUTPUT);
186+
Serial.begin(115200);
187+
while(!Serial);
188+
Serial.println("Arduino Menu Library");Serial.flush();
189+
190+
lcd.begin(16,2);
191+
lcd.setRGB(32, 32, 32);
192+
nav.idleTask=idle;//point a function to be used when menu is suspended
193+
mainMenu[1].enabled=disabledStatus;
194+
nav.showTitle=false;
195+
lcd.setCursor(0, 0);
196+
lcd.print("Menu 4.x LCD");
197+
lcd.setCursor(0, 1);
198+
lcd.print("r-site.net");
199+
delay(2000);
200+
}
201+
202+
void loop() {
203+
clickEncoder.service();
204+
nav.poll();
205+
digitalWrite(LEDPIN, ledCtrl);
206+
delay(100);//simulate a delay as if other tasks are running
207+
}

src/macros.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
#define ANSISERIAL_OUT(...) ON(ANSISERIAL_OUT,__COUNTER__,__VA_ARGS__)
9090
#define LIQUIDCRYSTAL_OUT(...) ON(LIQUIDCRYSTAL_OUT,__COUNTER__,__VA_ARGS__)
9191
#define LCD_OUT(...) ON(LCD_OUT,__COUNTER__,__VA_ARGS__)
92+
#define GROVERGBLCD_OUT(...) ON(GROVERGBLCD_OUT,__COUNTER__,__VA_ARGS__)
9293
#define ADAGFX_OUT(...) ON(ADAGFX_OUT,__COUNTER__,__VA_ARGS__)
9394
#define TFT_eSPI_OUT(...) ON(TFT_eSPI_OUT,__COUNTER__,__VA_ARGS__)
9495
#define TFT_OUT(...) ON(TFT_OUT,__COUNTER__,__VA_ARGS__)
@@ -123,6 +124,11 @@ Menu::idx_t id##Tops##n[md];\
123124
PANELS(id##Panels##n,__VA_ARGS__);\
124125
Menu::lcdOut id##n(&device,id##Tops##n,id##Panels##n);
125126

127+
#define VAR_GROVERGBLCD_OUT(id,md,n,device,...)\
128+
Menu::idx_t id##Tops##n[md];\
129+
PANELS(id##Panels##n,__VA_ARGS__);\
130+
Menu::grovergblcdOut id##n(&device,id##Tops##n,id##Panels##n);
131+
126132
#define VAR_ADAGFX_OUT(id,md,n,gfx,color,fontW,fontH,...)\
127133
Menu::idx_t id##Tops##n[md];\
128134
PANELS(id##Panels##n,__VA_ARGS__);\
@@ -173,6 +179,7 @@ Menu::utftOut id##n(gfx,color,id##Tops##n,id##Panels##n,fontW,fontH);
173179
#define REF_ANSISERIAL_OUT(id,md,n,...) &id##n,
174180
#define REF_LIQUIDCRYSTAL_OUT(id,md,n,...) &id##n,
175181
#define REF_LCD_OUT(id,md,n,...) &id##n,
182+
#define REF_GROVERGBLCD_OUT(id,md,n,...) &id##n,
176183
#define REF_ADAGFX_OUT(id,md,n,...) &id##n,
177184
#define REF_TFT_eSPI_OUT(id,md,n,...) &id##n,
178185
#define REF_U8GLIB_OUT(id,md,n,...) &id##n,

src/menuIO/groveRGBLCDOut.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* -*- C++ -*- */
2+
3+
//for using the Grove 2x16 RGB LCD i2c
4+
// https://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/
5+
// https://github.com/Seeed-Studio/Grove_LCD_RGB_Backlight
6+
// Uses default I2C device addresses on default I2C bus
7+
8+
#ifndef RSITE_ARDUINO_MENU_GROVERGBLCDOUT
9+
#define RSITE_ARDUINO_MENU_GROVERGBLCDOUT
10+
11+
#ifndef ARDUINO_SAM_DUE
12+
#include "../menuDefs.h"
13+
#include <Wire.h>
14+
#include <rgb_lcd.h>
15+
16+
namespace Menu {
17+
18+
class grovergblcdOut:public cursorOut {
19+
public:
20+
rgb_lcd* device;
21+
inline grovergblcdOut(rgb_lcd* o,idx_t *t,panelsList &p,menuOut::styles s=menuOut::minimalRedraw)
22+
:cursorOut(t,p,s),device(o) {}
23+
size_t write(uint8_t ch) override {return device->write(ch);}
24+
void clear() override {
25+
device->clear();
26+
panels.reset();
27+
}
28+
void setCursor(idx_t x,idx_t y,idx_t panelNr=0) override {
29+
const panel p=panels[panelNr];
30+
device->setCursor(p.x+x,p.y+y);
31+
}
32+
idx_t startCursor(navRoot& root,idx_t x,idx_t y,bool charEdit,idx_t panelNr=0) override {return 0;}
33+
idx_t endCursor(navRoot& root,idx_t x,idx_t y,bool charEdit,idx_t panelNr=0) override {return 0;}
34+
idx_t editCursor(navRoot& root,idx_t x,idx_t y,bool editing,bool charEdit,idx_t panelNr=0) override {
35+
trace(MENU_DEBUG_OUT<<"lcdOut::editCursor "<<x<<","<<y<<endl);
36+
//text editor cursor
37+
device->noBlink();
38+
device->noCursor();
39+
if (editing) {
40+
device->setCursor(x, y);
41+
if (charEdit) device->cursor();
42+
else device->blink();
43+
}
44+
return 0;
45+
}
46+
47+
};
48+
49+
}//namespace Menu
50+
51+
#endif
52+
#endif

0 commit comments

Comments
 (0)