1 #include <LiquidCrystal.h>
4 #define LEDS_GRN 15 // Analog 1; Common green anode
5 #define LEDS_RED 16 // Analog 2; Common red anode
6 #define LED1 13 // LED1 cathode
7 #define LED2 12 // LED2 cathode
8 #define LED3 11 // LED3 cathode
9 #define LED4 10 // LED4 cathode
14 #define LED_BLINK 0x04
26 #define BUTTON 14 // Analog 0; push button
29 #define LCD_REGSEL 3 // Register select
30 #define LCD_ENABLE 4 // Chip enable
31 #define LCD_D4 5 // Data line
32 #define LCD_D5 6 // Data line
33 #define LCD_D6 7 // Data line
34 #define LCD_D7 8 // Data line
35 #define LCD_BL 2 // Backlight
37 LiquidCrystal lcd(LCD_REGSEL, LCD_ENABLE, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
39 enum backlight_state {
45 enum backlight_state state;
48 struct backlight backlight;
55 * See https://www.quinapalus.com/hd44780udg.html to make more.
56 * Define which ones are used (max. 8) in setup().
57 * When they need to be changed at runtime, make sure the cursor is disabled
58 * and call setCursor afterwards.
60 byte char_music[8] = {0x02,0x03,0x02,0x0e,0x1e,0x0c,0x00};
61 byte char_smile[8] = {0x00,0x00,0x0a,0x00,0x11,0x0e,0x00};
62 byte char_bar_1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x1f};
63 byte char_bar_2[8] = {0x00,0x00,0x00,0x00,0x00,0x1f,0x1f};
64 byte char_bar_3[8] = {0x00,0x00,0x00,0x00,0x1f,0x1f,0x1f};
65 byte char_bar_4[8] = {0x00,0x00,0x00,0x1f,0x1f,0x1f,0x1f};
66 byte char_bar_5[8] = {0x00,0x00,0x1f,0x1f,0x1f,0x1f,0x1f};
67 byte char_bar_6[8] = {0x00,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f};
68 byte char_bar_7[8] = {0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f};
69 byte char_hbar_start_empty[8] = {0x1f,0x10,0x10,0x10,0x10,0x10,0x1f};
70 byte char_hbar_start_full[8] = {0x1f,0x10,0x17,0x17,0x17,0x10,0x1f};
71 byte char_hbar_inner_empty[8] = {0x1f,0x00,0x00,0x00,0x00,0x00,0x1f};
72 byte char_hbar_inner_half[8] = {0x1f,0x00,0x1c,0x1c,0x1c,0x00,0x1f};
73 byte char_hbar_inner_full[8] = {0x1f,0x00,0x1f,0x1f,0x1f,0x00,0x1f};
74 byte char_hbar_end_empty[8] = {0x1f,0x01,0x01,0x01,0x01,0x01,0x1f};
75 byte char_hbar_end_full[8] = {0x1f,0x01,0x1d,0x1d,0x1d,0x01,0x1f};
80 char contents[COLS * ROWS];
83 void redraw(struct terminal *term)
88 for (byte i = 0; i < COLS * ROWS; i++) {
90 lcd.setCursor(i % COLS, i / COLS);
91 lcd.write(term->contents[i]);
96 void scroll_up(struct terminal *term)
98 for (byte i = 0; i < COLS * (ROWS - 1); i++)
99 term->contents[i] = term->contents[i + COLS];
100 for (byte i = COLS * (ROWS - 1); i < COLS * ROWS; i++)
101 term->contents[i] = ' ';
106 * Special character meanings are defined here.
108 void write(struct terminal *term, char ch)
113 lcd.setCursor(term->x, term->y);
116 if (++term->y >= ROWS) {
120 lcd.setCursor(term->x, term->y);
125 term->contents[term->x + term->y * COLS] = 0x00;
126 lcd.setCursor(term->x, term->y);
128 lcd.setCursor(term->x, term->y);
132 term->contents[term->x + term->y * COLS] = ch;
134 if (++term->x >= COLS) {
136 if (++term->y >= ROWS) {
140 lcd.setCursor(term->x, term->y);
145 struct terminal term;
148 "Beste Mart, van harte gefeliciteerd! \x01\x00\r\n"
149 "Hier een herprogrammeerbare terminal. ";
152 * Tasks for the LEDs. Needs to be called every few ms(?) for multiplexing.
153 * When an LED is blinking and in the off period, it is necessary to call
154 * digitalWrite() twice and set the cathode. This ensures that the function
155 * takes equally long to return on every iteration, s.t. the blinking duty
156 * cycle is exactly 50% and LEDs blink equally bright, regardless of the status
162 switch (leds.counter & 0x03) {
164 digitalWrite(LED4, 1);
165 if ((leds.a & LED_BLINK) && leds.counter & 0x4000) {
166 digitalWrite(LEDS_GRN, 0);
167 digitalWrite(LEDS_RED, 0);
169 digitalWrite(LEDS_GRN, leds.a & 1);
170 digitalWrite(LEDS_RED, leds.a & 2);
172 digitalWrite(LED1, 0);
175 digitalWrite(LED1, 1);
176 if ((leds.b & LED_BLINK) && leds.counter & 0x4000) {
177 digitalWrite(LEDS_GRN, 0);
178 digitalWrite(LEDS_RED, 0);
180 digitalWrite(LEDS_GRN, leds.b & 1);
181 digitalWrite(LEDS_RED, leds.b & 2);
183 digitalWrite(LED2, 0);
186 digitalWrite(LED2, 1);
187 if ((leds.c & LED_BLINK) && leds.counter & 0x4000) {
188 digitalWrite(LEDS_GRN, 0);
189 digitalWrite(LEDS_RED, 0);
191 digitalWrite(LEDS_GRN, leds.c & 1);
192 digitalWrite(LEDS_RED, leds.c & 2);
194 digitalWrite(LED3, 0);
197 digitalWrite(LED3, 1);
198 if ((leds.d & LED_BLINK) && leds.counter & 0x4000) {
199 digitalWrite(LEDS_GRN, 0);
200 digitalWrite(LEDS_RED, 0);
202 digitalWrite(LEDS_GRN, leds.d & 1);
203 digitalWrite(LEDS_RED, leds.d & 2);
205 digitalWrite(LED4, 0);
212 if (digitalRead(BUTTON)) {
219 if (backlight.state == BL_FLASH)
220 if (!--backlight.timer)
221 backlight.state = BL_OFF;
223 switch (backlight.state) {
225 digitalWrite(LCD_BL, 0);
229 digitalWrite(LCD_BL, 1);
236 backlight.state = BL_FLASH;
237 backlight.timer = (unsigned int) -1;
242 lcd.createChar(0, char_music);
243 lcd.createChar(1, char_smile);
245 lcd.begin(COLS, ROWS);
247 Serial.begin(115200);
249 for (byte i = 0; i < ROWS * COLS; i++)
250 term.contents[i] = ' ';
252 for (byte i = 0; i < sizeof(message) - 1; i++)
253 write(&term, message[i]);
255 pinMode(LCD_BL, OUTPUT);
257 pinMode(LEDS_GRN, OUTPUT);
258 pinMode(LEDS_RED, OUTPUT);
259 pinMode(LED1, OUTPUT);
260 pinMode(LED2, OUTPUT);
261 pinMode(LED3, OUTPUT);
262 pinMode(LED4, OUTPUT);
264 pinMode(BUTTON, INPUT);
266 leds.a = LED_GRN | LED_BLINK;
267 leds.b = LED_RED | LED_BLINK;
268 leds.c = LED_GRN | LED_BLINK;
269 leds.d = LED_RED | LED_BLINK;
277 enum read_state read_state;
279 void handle_character(char c)
281 switch (read_state) {
288 read_state = S_BACKLIGHT;
298 case 0x00: leds.a = c & 0x0f; break;
299 case 0x10: leds.b = c & 0x0f; break;
300 case 0x20: leds.c = c & 0x0f; break;
301 case 0x30: leds.d = c & 0x0f; break;
303 read_state = S_DEFAULT;
310 backlight.state = (enum backlight_state) c;
311 read_state = S_DEFAULT;
322 while (Serial.available())
323 handle_character(Serial.read());