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_bar_1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x1f};
62 byte char_bar_2[8] = {0x00,0x00,0x00,0x00,0x00,0x1f,0x1f};
63 byte char_bar_3[8] = {0x00,0x00,0x00,0x00,0x1f,0x1f,0x1f};
64 byte char_bar_4[8] = {0x00,0x00,0x00,0x1f,0x1f,0x1f,0x1f};
65 byte char_bar_5[8] = {0x00,0x00,0x1f,0x1f,0x1f,0x1f,0x1f};
66 byte char_bar_6[8] = {0x00,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f};
67 byte char_bar_7[8] = {0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f};
68 byte char_hbar_start_empty[8] = {0x1f,0x10,0x10,0x10,0x10,0x10,0x1f};
69 byte char_hbar_start_full[8] = {0x1f,0x10,0x17,0x17,0x17,0x10,0x1f};
70 byte char_hbar_inner_empty[8] = {0x1f,0x00,0x00,0x00,0x00,0x00,0x1f};
71 byte char_hbar_inner_half[8] = {0x1f,0x00,0x1c,0x1c,0x1c,0x00,0x1f};
72 byte char_hbar_inner_full[8] = {0x1f,0x00,0x1f,0x1f,0x1f,0x00,0x1f};
73 byte char_hbar_end_empty[8] = {0x1f,0x01,0x01,0x01,0x01,0x01,0x1f};
74 byte char_hbar_end_full[8] = {0x1f,0x01,0x1d,0x1d,0x1d,0x01,0x1f};
79 char contents[COLS * ROWS];
82 void redraw(struct terminal *term)
87 for (byte i = 0; i < COLS * ROWS; i++) {
89 lcd.setCursor(i % COLS, i / COLS);
90 lcd.write(term->contents[i]);
95 void scroll_up(struct terminal *term)
97 for (byte i = 0; i < COLS * (ROWS - 1); i++)
98 term->contents[i] = term->contents[i + COLS];
99 for (byte i = COLS * (ROWS - 1); i < COLS * ROWS; i++)
100 term->contents[i] = ' ';
105 * Special character meanings are defined here.
107 void write(struct terminal *term, char ch)
112 lcd.setCursor(term->x, term->y);
115 if (++term->y >= ROWS) {
119 lcd.setCursor(term->x, term->y);
124 term->contents[term->x + term->y * COLS] = 0x00;
125 lcd.setCursor(term->x, term->y);
127 lcd.setCursor(term->x, term->y);
131 term->contents[term->x + term->y * COLS] = ch;
133 if (++term->x >= COLS) {
135 if (++term->y >= ROWS) {
139 lcd.setCursor(term->x, term->y);
144 struct terminal term;
147 "Beste Mart, van harte gefeliciteerd! \x00\x00\r\n"
148 "Hier een herprogrammeerbare terminal. ";
151 * Tasks for the LEDs. Needs to be called every few ms(?) for multiplexing.
152 * When an LED is blinking and in the off period, it is necessary to call
153 * digitalWrite() twice and set the cathode. This ensures that the function
154 * takes equally long to return on every iteration, s.t. the blinking duty
155 * cycle is exactly 50% and LEDs blink equally bright, regardless of the status
161 switch (leds.counter & 0x03) {
163 digitalWrite(LED4, 1);
164 if ((leds.a & LED_BLINK) && leds.counter & 0x4000) {
165 digitalWrite(LEDS_GRN, 0);
166 digitalWrite(LEDS_RED, 0);
168 digitalWrite(LEDS_GRN, leds.a & 1);
169 digitalWrite(LEDS_RED, leds.a & 2);
171 digitalWrite(LED1, 0);
174 digitalWrite(LED1, 1);
175 if ((leds.b & LED_BLINK) && leds.counter & 0x4000) {
176 digitalWrite(LEDS_GRN, 0);
177 digitalWrite(LEDS_RED, 0);
179 digitalWrite(LEDS_GRN, leds.b & 1);
180 digitalWrite(LEDS_RED, leds.b & 2);
182 digitalWrite(LED2, 0);
185 digitalWrite(LED2, 1);
186 if ((leds.c & LED_BLINK) && leds.counter & 0x4000) {
187 digitalWrite(LEDS_GRN, 0);
188 digitalWrite(LEDS_RED, 0);
190 digitalWrite(LEDS_GRN, leds.c & 1);
191 digitalWrite(LEDS_RED, leds.c & 2);
193 digitalWrite(LED3, 0);
196 digitalWrite(LED3, 1);
197 if ((leds.d & LED_BLINK) && leds.counter & 0x4000) {
198 digitalWrite(LEDS_GRN, 0);
199 digitalWrite(LEDS_RED, 0);
201 digitalWrite(LEDS_GRN, leds.d & 1);
202 digitalWrite(LEDS_RED, leds.d & 2);
204 digitalWrite(LED4, 0);
211 if (digitalRead(BUTTON)) {
218 if (backlight.state == BL_FLASH)
219 if (!--backlight.timer)
220 backlight.state = BL_OFF;
222 switch (backlight.state) {
224 digitalWrite(LCD_BL, 0);
228 digitalWrite(LCD_BL, 1);
235 backlight.state = BL_FLASH;
236 backlight.timer = (unsigned int) -1;
241 lcd.createChar(0, char_music);
242 lcd.createChar(1, char_hbar_start_full);
243 lcd.createChar(2, char_hbar_start_empty);
244 lcd.createChar(3, char_hbar_inner_full);
245 lcd.createChar(4, char_hbar_inner_half);
246 lcd.createChar(5, char_hbar_inner_empty);
247 lcd.createChar(6, char_hbar_end_full);
248 lcd.createChar(7, char_hbar_end_empty);
250 lcd.begin(COLS, ROWS);
252 Serial.begin(115200);
254 for (byte i = 0; i < ROWS * COLS; i++)
255 term.contents[i] = ' ';
257 for (byte i = 0; i < sizeof(message) - 1; i++)
258 write(&term, message[i]);
260 pinMode(LCD_BL, OUTPUT);
262 pinMode(LEDS_GRN, OUTPUT);
263 pinMode(LEDS_RED, OUTPUT);
264 pinMode(LED1, OUTPUT);
265 pinMode(LED2, OUTPUT);
266 pinMode(LED3, OUTPUT);
267 pinMode(LED4, OUTPUT);
269 pinMode(BUTTON, INPUT);
271 leds.a = LED_GRN | LED_BLINK;
272 leds.b = LED_RED | LED_BLINK;
273 leds.c = LED_GRN | LED_BLINK;
274 leds.d = LED_RED | LED_BLINK;
282 enum read_state read_state;
284 void handle_character(char c)
286 switch (read_state) {
293 read_state = S_BACKLIGHT;
303 case 0x00: leds.a = c & 0x0f; break;
304 case 0x10: leds.b = c & 0x0f; break;
305 case 0x20: leds.c = c & 0x0f; break;
306 case 0x30: leds.d = c & 0x0f; break;
308 read_state = S_DEFAULT;
315 backlight.state = (enum backlight_state) c;
316 read_state = S_DEFAULT;
327 while (Serial.available())
328 handle_character(Serial.read());