Example of how to use an Ada Fruit RGB LCD with the Ada Fruit RGB LCD Shield Library

Dependencies:   AdaFruit_RGBLCDShield MCP23017 mbed RTclock

Dependents:   SX1276_GPS

Fork of MCP_test by Wim Huiskamp

Updated the Adafruit RGB LCD Shield test app with a module system.

It pulls in RTclock which is another library I did for controlling the DS1307 RTC in a sane way (marries stdlib time and the RTC together cleanly). You don't need an RTC to run the example, it'll just use stdlib time instead. This class also maps RTC to system time, so if you loose the RTC the mbed will free run.

Four modules are defined in the modules folder plus the module base class. These examples provide:

  • title menu item
  • time menu item (updates automatically)
  • date menu item
  • fake temp menu item

Press select to switch modes: menu->cursor->change

Menu switches menu items going up/down. Cursor allows you to move around editable fields using the cursor keys / marker. Change allows you to move left/right on a particular line and change values by using up/down on an item with the blink box.

Custom fonts are defined for UI arrows and degree character.

If you want a menu item to update over time then you need to implement the canRefresh() member function in any child module you derive from class Module. Make it return true to receive update requests in your show() member function. Date and time both check when refreshing to see if anything has changed, then update.

main() registers a table of modules with the MenuManager. Others can be added easily by creating children derived from the Module base class..

Depending on what you want to do you may need to adjust the loop wait time in MenuManager::loop(). If you don't balance this based on work you need to do then the key presses may get a little lively. I may adjust the key checking to be fixed to 200ms regardless of loop wait time, however the catch there is that you'll consume more power the more loops you do so the wait is still important.

Happy coding!

Committer:
vtraveller
Date:
Fri Oct 10 11:10:56 2014 +0000
Revision:
28:fbcd3bac0cd7
Parent:
27:b6c3dd9a1d8c
Reduced write delay - faster LCD response

Who changed what in which revision?

UserRevisionLine numberNew contents of line
vtraveller 25:24654d08a99a 1 #include "mbed.h"
vtraveller 25:24654d08a99a 2 #include "module.h"
vtraveller 25:24654d08a99a 3 #include "extra_chars.h"
vtraveller 25:24654d08a99a 4
vtraveller 25:24654d08a99a 5 #include "MenuManager.h"
vtraveller 25:24654d08a99a 6
vtraveller 25:24654d08a99a 7 MenuManager::MenuManager
vtraveller 25:24654d08a99a 8 (
vtraveller 25:24654d08a99a 9 Module ** in_pModules,
vtraveller 25:24654d08a99a 10 size_t in_nModules,
vtraveller 25:24654d08a99a 11 LCD & in_cLCD,
vtraveller 25:24654d08a99a 12 Keys & in_cKeys
vtraveller 25:24654d08a99a 13 )
vtraveller 25:24654d08a99a 14 : m_pModules(in_pModules)
vtraveller 25:24654d08a99a 15 , m_nModules(in_nModules)
vtraveller 25:24654d08a99a 16 , m_cLCD(in_cLCD)
vtraveller 25:24654d08a99a 17 , m_cKeys(in_cKeys)
vtraveller 25:24654d08a99a 18 , m_eMode(Module::eModeLast)
vtraveller 25:24654d08a99a 19 , m_nMenuPos(0)
vtraveller 25:24654d08a99a 20 , m_nIndex(0)
vtraveller 25:24654d08a99a 21 , m_nCursorX(0)
vtraveller 25:24654d08a99a 22 , m_nCursorY(0)
vtraveller 25:24654d08a99a 23 {
vtraveller 25:24654d08a99a 24 }
vtraveller 25:24654d08a99a 25
vtraveller 25:24654d08a99a 26 void MenuManager::changeModule(bool in_bUp)
vtraveller 25:24654d08a99a 27 {
vtraveller 25:24654d08a99a 28 size_t nModule = (m_nMenuPos + m_nCursorY) % m_nModules;
vtraveller 25:24654d08a99a 29 m_pModules[nModule]->change(m_nIndex,in_bUp);
vtraveller 25:24654d08a99a 30 }
vtraveller 25:24654d08a99a 31
vtraveller 25:24654d08a99a 32 void MenuManager::createChars()
vtraveller 25:24654d08a99a 33 {
vtraveller 25:24654d08a99a 34 //uint8_t k_aUp[] = { 0x4,0xe,0x1f,0x15,0x4,0x4,0x4,0x4 };
vtraveller 25:24654d08a99a 35 //uint8_t k_aDown[] = { 0x4,0x4,0x4,0x4,0x15,0x1f,0xe,0x4 };
vtraveller 25:24654d08a99a 36
vtraveller 25:24654d08a99a 37 uint8_t k_aUp[] = { 0x0,0x0,0x4,0xe,0x1f,0x0,0x0 };
vtraveller 25:24654d08a99a 38 uint8_t k_aDown[] = { 0x0,0x0,0x1f,0xe,0x4,0x0,0x0 };
vtraveller 25:24654d08a99a 39 uint8_t k_aRight[] = { 0x0,0x8,0xc,0xe,0xc,0x8,0x0 };
vtraveller 25:24654d08a99a 40 uint8_t k_aLeft[] = { 0x0,0x2,0x6,0xe,0x6,0x2,0x0 };
vtraveller 25:24654d08a99a 41 uint8_t k_aDegree[] = { 0xc,0x12,0x12,0xc,0x0,0x0,0x0,0x0 };
vtraveller 25:24654d08a99a 42
vtraveller 25:24654d08a99a 43 m_cLCD.createChar(eUp,k_aUp);
vtraveller 25:24654d08a99a 44 m_cLCD.createChar(eDown,k_aDown);
vtraveller 25:24654d08a99a 45 m_cLCD.createChar(eRight,k_aRight);
vtraveller 25:24654d08a99a 46 m_cLCD.createChar(eLeft,k_aLeft);
vtraveller 25:24654d08a99a 47 m_cLCD.createChar(eDegree,k_aDegree);
vtraveller 25:24654d08a99a 48 }
vtraveller 25:24654d08a99a 49
vtraveller 25:24654d08a99a 50 void MenuManager::initialise()
vtraveller 25:24654d08a99a 51 {
vtraveller 25:24654d08a99a 52 createChars();
vtraveller 25:24654d08a99a 53
vtraveller 25:24654d08a99a 54 m_cLCD.setCursor(0,0);
vtraveller 25:24654d08a99a 55 m_cLCD._putc(eUp);
vtraveller 25:24654d08a99a 56
vtraveller 25:24654d08a99a 57 m_cLCD.setCursor(0,m_cLCD.rows() - 1);
vtraveller 25:24654d08a99a 58 m_cLCD._putc(eDown);
vtraveller 25:24654d08a99a 59
vtraveller 25:24654d08a99a 60 m_nCursorX = 2;
vtraveller 25:24654d08a99a 61 m_nCursorY = 0;
vtraveller 25:24654d08a99a 62 }
vtraveller 25:24654d08a99a 63
vtraveller 25:24654d08a99a 64 void MenuManager::loop()
vtraveller 25:24654d08a99a 65 {
vtraveller 25:24654d08a99a 66 setMode(Module::eModeMenu);
vtraveller 25:24654d08a99a 67
vtraveller 25:24654d08a99a 68 m_nMenuPos = 0;
vtraveller 25:24654d08a99a 69 m_nIndex = 0;
vtraveller 25:24654d08a99a 70
vtraveller 25:24654d08a99a 71 initialise();
vtraveller 25:24654d08a99a 72
vtraveller 25:24654d08a99a 73 showModules();
vtraveller 25:24654d08a99a 74
vtraveller 25:24654d08a99a 75 while (true)
vtraveller 25:24654d08a99a 76 {
vtraveller 25:24654d08a99a 77 uint8_t nKeys = m_cKeys.readButtons();
vtraveller 25:24654d08a99a 78 if (Keys::eButtonNone != nKeys)
vtraveller 25:24654d08a99a 79 {
vtraveller 25:24654d08a99a 80 processKeys(nKeys);
vtraveller 25:24654d08a99a 81 }
vtraveller 25:24654d08a99a 82 else
vtraveller 25:24654d08a99a 83 {
vtraveller 25:24654d08a99a 84 switch (m_eMode)
vtraveller 25:24654d08a99a 85 {
vtraveller 25:24654d08a99a 86 case Module::eModeMenu:
vtraveller 25:24654d08a99a 87 showModules(true);
vtraveller 25:24654d08a99a 88
vtraveller 25:24654d08a99a 89 int nOffsetX = m_pModules[m_nMenuPos]->getCursorOffset(m_nIndex);
vtraveller 25:24654d08a99a 90 m_cLCD.setCursor(m_nCursorY + nOffsetX,m_nCursorY);
vtraveller 25:24654d08a99a 91 break;
vtraveller 25:24654d08a99a 92 }
vtraveller 25:24654d08a99a 93 }
vtraveller 25:24654d08a99a 94
vtraveller 25:24654d08a99a 95 wait(0.2);
vtraveller 25:24654d08a99a 96 }
vtraveller 25:24654d08a99a 97 }
vtraveller 25:24654d08a99a 98
vtraveller 25:24654d08a99a 99 void MenuManager::processKeys(uint8_t in_nKeys)
vtraveller 25:24654d08a99a 100 {
vtraveller 25:24654d08a99a 101 // Change mode based on select
vtraveller 25:24654d08a99a 102 if (in_nKeys & Keys::eButtonSelect)
vtraveller 25:24654d08a99a 103 {
vtraveller 25:24654d08a99a 104 Module::EModes eMode = (Module::EModes)((m_eMode + 1) % Module::eModeLast);
vtraveller 25:24654d08a99a 105 setMode(eMode);
vtraveller 25:24654d08a99a 106
vtraveller 27:b6c3dd9a1d8c 107 // Start at top corner or first good item
vtraveller 25:24654d08a99a 108 if (Module::eModeSelect == m_eMode)
vtraveller 25:24654d08a99a 109 {
vtraveller 25:24654d08a99a 110 m_nIndex = 0;
vtraveller 25:24654d08a99a 111 m_nCursorY = 0;
vtraveller 27:b6c3dd9a1d8c 112
vtraveller 27:b6c3dd9a1d8c 113 // Move to next valid module for editing
vtraveller 27:b6c3dd9a1d8c 114 for (size_t i = 0; i < m_cLCD.rows(); i++)
vtraveller 27:b6c3dd9a1d8c 115 {
vtraveller 27:b6c3dd9a1d8c 116 size_t nPos = (m_nMenuPos + i) % m_nModules;
vtraveller 27:b6c3dd9a1d8c 117
vtraveller 27:b6c3dd9a1d8c 118 if (-1 != m_pModules[nPos]->getCursorOffset(i))
vtraveller 27:b6c3dd9a1d8c 119 {
vtraveller 27:b6c3dd9a1d8c 120 m_nCursorY = i;
vtraveller 27:b6c3dd9a1d8c 121 break;
vtraveller 27:b6c3dd9a1d8c 122 }
vtraveller 27:b6c3dd9a1d8c 123 }
vtraveller 25:24654d08a99a 124 }
vtraveller 25:24654d08a99a 125 }
vtraveller 25:24654d08a99a 126
vtraveller 25:24654d08a99a 127 switch (m_eMode)
vtraveller 25:24654d08a99a 128 {
vtraveller 25:24654d08a99a 129 case Module::eModeMenu:
vtraveller 25:24654d08a99a 130 setCursor(false,false);
vtraveller 25:24654d08a99a 131 showTracking(false);
vtraveller 25:24654d08a99a 132
vtraveller 25:24654d08a99a 133 if (in_nKeys & Keys::eButtonUp) m_nMenuPos--;
vtraveller 25:24654d08a99a 134 if (in_nKeys & Keys::eButtonDown) m_nMenuPos++;
vtraveller 25:24654d08a99a 135
vtraveller 25:24654d08a99a 136 m_nMenuPos = m_nMenuPos % m_nModules;
vtraveller 25:24654d08a99a 137 break;
vtraveller 25:24654d08a99a 138
vtraveller 25:24654d08a99a 139 case Module::eModeSelect:
vtraveller 25:24654d08a99a 140 setCursor(true,false);
vtraveller 25:24654d08a99a 141 showTracking(true);
vtraveller 25:24654d08a99a 142
vtraveller 25:24654d08a99a 143 if (m_nCursorY > 0 && (in_nKeys & Keys::eButtonUp)) m_nCursorY--;
vtraveller 25:24654d08a99a 144 if ((m_nCursorY < m_cLCD.rows() - 1) && (in_nKeys & Keys::eButtonDown)) m_nCursorY++;
vtraveller 25:24654d08a99a 145
vtraveller 25:24654d08a99a 146 if (in_nKeys & Keys::eButtonLeft) m_nIndex--;
vtraveller 25:24654d08a99a 147 if (in_nKeys & Keys::eButtonRight) m_nIndex++;
vtraveller 25:24654d08a99a 148 break;
vtraveller 25:24654d08a99a 149
vtraveller 25:24654d08a99a 150 case Module::eModeChange:
vtraveller 25:24654d08a99a 151 setCursor(false,true);
vtraveller 25:24654d08a99a 152 showTracking(true);
vtraveller 25:24654d08a99a 153
vtraveller 25:24654d08a99a 154 if (in_nKeys & (Keys::eButtonUp | Keys::eButtonDown))
vtraveller 25:24654d08a99a 155 {
vtraveller 25:24654d08a99a 156 bool bUp = (in_nKeys & Keys::eButtonUp) ? true : false;
vtraveller 25:24654d08a99a 157 changeModule(bUp);
vtraveller 25:24654d08a99a 158 }
vtraveller 25:24654d08a99a 159
vtraveller 25:24654d08a99a 160 if (in_nKeys & Keys::eButtonLeft) m_nIndex--;
vtraveller 25:24654d08a99a 161 if (in_nKeys & Keys::eButtonRight) m_nIndex++;
vtraveller 25:24654d08a99a 162 break;
vtraveller 25:24654d08a99a 163 }
vtraveller 25:24654d08a99a 164
vtraveller 25:24654d08a99a 165 updateDisplay();
vtraveller 25:24654d08a99a 166 }
vtraveller 25:24654d08a99a 167
vtraveller 25:24654d08a99a 168 void MenuManager::setCursor(bool in_bCursor,bool in_bBlink)
vtraveller 25:24654d08a99a 169 {
vtraveller 25:24654d08a99a 170 m_cLCD.showCursor(in_bCursor);
vtraveller 25:24654d08a99a 171 m_cLCD.showBlink(in_bBlink);
vtraveller 25:24654d08a99a 172 }
vtraveller 25:24654d08a99a 173
vtraveller 25:24654d08a99a 174 void MenuManager::setMode(Module::EModes in_eMode)
vtraveller 25:24654d08a99a 175 {
vtraveller 25:24654d08a99a 176 m_eMode = in_eMode;
vtraveller 25:24654d08a99a 177
vtraveller 25:24654d08a99a 178 for (size_t i = 0; i < m_nModules; i++)
vtraveller 25:24654d08a99a 179 {
vtraveller 25:24654d08a99a 180 m_pModules[i]->onModeChange(m_eMode);
vtraveller 25:24654d08a99a 181 }
vtraveller 25:24654d08a99a 182 }
vtraveller 25:24654d08a99a 183
vtraveller 25:24654d08a99a 184 void MenuManager::showModules(bool in_bRefresh)
vtraveller 25:24654d08a99a 185 {
vtraveller 25:24654d08a99a 186 for (size_t i = 0; i < m_cLCD.rows(); i++)
vtraveller 25:24654d08a99a 187 {
vtraveller 25:24654d08a99a 188 size_t nPos = (m_nMenuPos + i) % m_nModules;
vtraveller 25:24654d08a99a 189 m_cLCD.setCursor(2,i);
vtraveller 25:24654d08a99a 190
vtraveller 25:24654d08a99a 191 if (m_pModules[nPos]->canRefresh() || !in_bRefresh) m_pModules[nPos]->show(in_bRefresh);
vtraveller 25:24654d08a99a 192 }
vtraveller 25:24654d08a99a 193 }
vtraveller 25:24654d08a99a 194
vtraveller 25:24654d08a99a 195 void MenuManager::showTracking(bool in_bShow)
vtraveller 25:24654d08a99a 196 {
vtraveller 26:0cfd95d8f270 197 int nX = (m_cLCD.rows() >= 4) ? 0:1;
vtraveller 26:0cfd95d8f270 198 int nTop = nX ? 0:1;
vtraveller 26:0cfd95d8f270 199 int nBottom = m_cLCD.rows() - (nX ? 1:2);
vtraveller 26:0cfd95d8f270 200
vtraveller 25:24654d08a99a 201 if (in_bShow)
vtraveller 25:24654d08a99a 202 {
vtraveller 26:0cfd95d8f270 203 m_cLCD.setCursor(nX,nTop);
vtraveller 25:24654d08a99a 204 m_cLCD._putc(eLeft);
vtraveller 25:24654d08a99a 205
vtraveller 26:0cfd95d8f270 206 m_cLCD.setCursor(nX,nBottom);
vtraveller 26:0cfd95d8f270 207 m_cLCD._putc(eRight);
vtraveller 25:24654d08a99a 208 }
vtraveller 25:24654d08a99a 209 else
vtraveller 25:24654d08a99a 210 {
vtraveller 26:0cfd95d8f270 211 m_cLCD.setCursor(nX,nTop);
vtraveller 25:24654d08a99a 212 m_cLCD._putc(' ');
vtraveller 25:24654d08a99a 213
vtraveller 26:0cfd95d8f270 214 m_cLCD.setCursor(nX,nBottom);
vtraveller 26:0cfd95d8f270 215 m_cLCD._putc(' ');
vtraveller 27:b6c3dd9a1d8c 216 }
vtraveller 25:24654d08a99a 217 }
vtraveller 25:24654d08a99a 218
vtraveller 25:24654d08a99a 219 void MenuManager::updateDisplay()
vtraveller 25:24654d08a99a 220 {
vtraveller 25:24654d08a99a 221 showModules();
vtraveller 25:24654d08a99a 222
vtraveller 25:24654d08a99a 223 size_t nCurrent = (m_nMenuPos + m_nCursorY) % m_nModules;
vtraveller 25:24654d08a99a 224
vtraveller 25:24654d08a99a 225 int nOffsetX = m_pModules[nCurrent]->getCursorOffset(m_nIndex);
vtraveller 25:24654d08a99a 226
vtraveller 25:24654d08a99a 227 // If we didn't have anything, move the line
vtraveller 25:24654d08a99a 228 if (-1 == nOffsetX)
vtraveller 25:24654d08a99a 229 {
vtraveller 25:24654d08a99a 230 m_nCursorY = (m_nCursorY + 1) % m_cLCD.rows();
vtraveller 25:24654d08a99a 231
vtraveller 25:24654d08a99a 232 nCurrent = (m_nMenuPos + m_nCursorY) % m_nModules;
vtraveller 25:24654d08a99a 233
vtraveller 25:24654d08a99a 234 m_nIndex = 0;
vtraveller 25:24654d08a99a 235 nOffsetX = m_pModules[nCurrent]->getCursorOffset(m_nIndex);
vtraveller 25:24654d08a99a 236 }
vtraveller 25:24654d08a99a 237
vtraveller 25:24654d08a99a 238 if ((size_t)-1 != m_nIndex)
vtraveller 25:24654d08a99a 239 {
vtraveller 25:24654d08a99a 240 // Move cursor to new position
vtraveller 25:24654d08a99a 241 m_cLCD.setCursor(m_nCursorX + nOffsetX,m_nCursorY);
vtraveller 25:24654d08a99a 242 }
vtraveller 25:24654d08a99a 243 else
vtraveller 25:24654d08a99a 244 {
vtraveller 25:24654d08a99a 245 // If nothing to show - hide everything
vtraveller 25:24654d08a99a 246 setCursor(false,false);
vtraveller 25:24654d08a99a 247 }
vtraveller 25:24654d08a99a 248 }