hd44780_hal/
lib.rs

1#![no_std]
2
3extern crate embedded_hal;
4
5use embedded_hal::blocking::delay::DelayMs;
6use embedded_hal::blocking::delay::DelayUs;
7use embedded_hal::digital::OutputPin;
8
9pub trait DataBus {
10    fn write<D: DelayUs<u16> + DelayMs<u8>>(&mut self, byte: u8, data: bool, delay: &mut D);
11
12    // TODO
13    // fn read(...)
14}
15
16pub struct EightBitBus<
17    RS: OutputPin,
18    EN: OutputPin,
19    D0: OutputPin,
20    D1: OutputPin,
21    D2: OutputPin,
22    D3: OutputPin,
23    D4: OutputPin,
24    D5: OutputPin,
25    D6: OutputPin,
26    D7: OutputPin,
27> {
28    rs: RS,
29    en: EN,
30    d0: D0,
31    d1: D1,
32    d2: D2,
33    d3: D3,
34    d4: D4,
35    d5: D5,
36    d6: D6,
37    d7: D7,
38}
39
40impl<
41        RS: OutputPin,
42        EN: OutputPin,
43        D0: OutputPin,
44        D1: OutputPin,
45        D2: OutputPin,
46        D3: OutputPin,
47        D4: OutputPin,
48        D5: OutputPin,
49        D6: OutputPin,
50        D7: OutputPin,
51    > EightBitBus<RS, EN, D0, D1, D2, D3, D4, D5, D6, D7>
52{
53    fn set_bus_bits(&mut self, data: u8) {
54        let db0: bool = (0b0000_0001 & data) != 0;
55        let db1: bool = (0b0000_0010 & data) != 0;
56        let db2: bool = (0b0000_0100 & data) != 0;
57        let db3: bool = (0b0000_1000 & data) != 0;
58        let db4: bool = (0b0001_0000 & data) != 0;
59        let db5: bool = (0b0010_0000 & data) != 0;
60        let db6: bool = (0b0100_0000 & data) != 0;
61        let db7: bool = (0b1000_0000 & data) != 0;
62
63        if db0 {
64            self.d0.set_high();
65        } else {
66            self.d0.set_low();
67        }
68
69        if db1 {
70            self.d1.set_high();
71        } else {
72            self.d1.set_low();
73        }
74
75        if db2 {
76            self.d2.set_high();
77        } else {
78            self.d2.set_low();
79        }
80
81        if db3 {
82            self.d3.set_high();
83        } else {
84            self.d3.set_low();
85        }
86
87        if db4 {
88            self.d4.set_high();
89        } else {
90            self.d4.set_low();
91        }
92
93        if db5 {
94            self.d5.set_high();
95        } else {
96            self.d5.set_low();
97        }
98
99        if db6 {
100            self.d6.set_high();
101        } else {
102            self.d6.set_low();
103        }
104
105        if db7 {
106            self.d7.set_high();
107        } else {
108            self.d7.set_low();
109        }
110    }
111}
112
113impl<
114        RS: OutputPin,
115        EN: OutputPin,
116        D0: OutputPin,
117        D1: OutputPin,
118        D2: OutputPin,
119        D3: OutputPin,
120        D4: OutputPin,
121        D5: OutputPin,
122        D6: OutputPin,
123        D7: OutputPin,
124    > DataBus for EightBitBus<RS, EN, D0, D1, D2, D3, D4, D5, D6, D7>
125{
126    fn write<D: DelayUs<u16> + DelayMs<u8>>(&mut self, byte: u8, data: bool, delay: &mut D) {
127        if data {
128            self.rs.set_high();
129        } else {
130            self.rs.set_low();
131        }
132
133        self.set_bus_bits(byte);
134
135        self.en.set_high();
136        delay.delay_ms(2u8);
137        self.en.set_low();
138
139        if data {
140            self.rs.set_low();
141        }
142    }
143}
144
145pub struct FourBitBus<
146    RS: OutputPin,
147    EN: OutputPin,
148    D4: OutputPin,
149    D5: OutputPin,
150    D6: OutputPin,
151    D7: OutputPin,
152> {
153    rs: RS,
154    en: EN,
155    d4: D4,
156    d5: D5,
157    d6: D6,
158    d7: D7,
159}
160
161impl<RS: OutputPin, EN: OutputPin, D4: OutputPin, D5: OutputPin, D6: OutputPin, D7: OutputPin>
162    FourBitBus<RS, EN, D4, D5, D6, D7>
163{
164    fn write_lower_nibble(&mut self, data: u8) {
165        let db0: bool = (0b0000_0001 & data) != 0;
166        let db1: bool = (0b0000_0010 & data) != 0;
167        let db2: bool = (0b0000_0100 & data) != 0;
168        let db3: bool = (0b0000_1000 & data) != 0;
169
170        if db0 {
171            self.d4.set_high();
172        } else {
173            self.d4.set_low();
174        }
175
176        if db1 {
177            self.d5.set_high();
178        } else {
179            self.d5.set_low();
180        }
181
182        if db2 {
183            self.d6.set_high();
184        } else {
185            self.d6.set_low();
186        }
187
188        if db3 {
189            self.d7.set_high();
190        } else {
191            self.d7.set_low();
192        }
193    }
194
195    fn write_upper_nibble(&mut self, data: u8) {
196        let db4: bool = (0b0001_0000 & data) != 0;
197        let db5: bool = (0b0010_0000 & data) != 0;
198        let db6: bool = (0b0100_0000 & data) != 0;
199        let db7: bool = (0b1000_0000 & data) != 0;
200
201        if db4 {
202            self.d4.set_high();
203        } else {
204            self.d4.set_low();
205        }
206
207        if db5 {
208            self.d5.set_high();
209        } else {
210            self.d5.set_low();
211        }
212
213        if db6 {
214            self.d6.set_high();
215        } else {
216            self.d6.set_low();
217        }
218
219        if db7 {
220            self.d7.set_high();
221        } else {
222            self.d7.set_low();
223        }
224    }
225}
226
227impl<RS: OutputPin, EN: OutputPin, D4: OutputPin, D5: OutputPin, D6: OutputPin, D7: OutputPin>
228    DataBus for FourBitBus<RS, EN, D4, D5, D6, D7>
229{
230    fn write<D: DelayUs<u16> + DelayMs<u8>>(&mut self, byte: u8, data: bool, delay: &mut D) {
231        if data {
232            self.rs.set_high();
233        } else {
234            self.rs.set_low();
235        }
236
237        self.write_upper_nibble(byte);
238
239        self.en.set_high();
240        delay.delay_ms(2u8);
241        self.en.set_low();
242
243        self.write_lower_nibble(byte);
244
245        self.en.set_high();
246        delay.delay_ms(2u8);
247        self.en.set_low();
248
249        if data {
250            self.rs.set_low();
251        }
252    }
253}
254
255pub struct HD44780<D: DelayUs<u16> + DelayMs<u8>, B: DataBus> {
256    bus: B,
257    delay: D,
258}
259
260/// Used in the direction argument for shifting the cursor and the display
261pub enum Direction {
262    Left,
263    Right,
264}
265
266impl<
267        D: DelayUs<u16> + DelayMs<u8>,
268        RS: OutputPin,
269        EN: OutputPin,
270        D0: OutputPin,
271        D1: OutputPin,
272        D2: OutputPin,
273        D3: OutputPin,
274        D4: OutputPin,
275        D5: OutputPin,
276        D6: OutputPin,
277        D7: OutputPin,
278    > HD44780<D, EightBitBus<RS, EN, D0, D1, D2, D3, D4, D5, D6, D7>>
279{
280    /// Create an instance of a `HD44780` from 8 data pins, a register select
281    /// pin, an enable pin and a struct implementing the delay trait.
282    /// - The delay instance is used to sleep between commands to
283    /// ensure the `HD44780` has enough time to process commands.
284    /// - The eight db0..db7 pins are used to send and recieve with
285    ///  the `HD44780`.
286    /// - The register select pin is used to tell the `HD44780`
287    /// if incoming data is a command or data.
288    /// - The enable pin is used to tell the `HD44780` that there
289    /// is data on the 8 data pins and that it should read them in.
290    ///
291    pub fn new_8bit(
292        rs: RS,
293        en: EN,
294        d0: D0,
295        d1: D1,
296        d2: D2,
297        d3: D3,
298        d4: D4,
299        d5: D5,
300        d6: D6,
301        d7: D7,
302        delay: D,
303    ) -> HD44780<D, EightBitBus<RS, EN, D0, D1, D2, D3, D4, D5, D6, D7>> {
304        let mut hd = HD44780 {
305            bus: EightBitBus {
306                rs,
307                en,
308                d0,
309                d1,
310                d2,
311                d3,
312                d4,
313                d5,
314                d6,
315                d7,
316            },
317            delay,
318        };
319
320        hd.init_8bit();
321
322        return hd;
323    }
324}
325
326impl<
327        D: DelayUs<u16> + DelayMs<u8>,
328        RS: OutputPin,
329        EN: OutputPin,
330        D4: OutputPin,
331        D5: OutputPin,
332        D6: OutputPin,
333        D7: OutputPin,
334    > HD44780<D, FourBitBus<RS, EN, D4, D5, D6, D7>>
335{
336    /// Create an instance of a `HD44780` from 4 data pins, a register select
337    /// pin, an enable pin and a struct implementing the delay trait.
338    /// - The delay instance is used to sleep between commands to
339    /// ensure the `HD44780` has enough time to process commands.
340    /// - The four db0..db3 pins are used to send and recieve with
341    ///  the `HD44780`.
342    /// - The register select pin is used to tell the `HD44780`
343    /// if incoming data is a command or data.
344    /// - The enable pin is used to tell the `HD44780` that there
345    /// is data on the 4 data pins and that it should read them in.
346    ///
347    /// This mode operates differently than 8 bit mode by using 4 less
348    /// pins for data, which is nice on devices with less I/O
349    ///
350    /// Instead of commands being sent byte by byte each command is
351    /// broken up into it's upper and lower nibbles (4 bits) before
352    /// being sent over the data bus
353    ///
354    pub fn new_4bit(
355        rs: RS,
356        en: EN,
357        d4: D4,
358        d5: D5,
359        d6: D6,
360        d7: D7,
361        delay: D,
362    ) -> HD44780<D, FourBitBus<RS, EN, D4, D5, D6, D7>> {
363        let mut hd = HD44780 {
364            bus: FourBitBus {
365                rs,
366                en,
367                d4,
368                d5,
369                d6,
370                d7,
371            },
372            delay,
373        };
374
375        hd.init_4bit();
376
377        return hd;
378    }
379}
380
381impl<D, B> HD44780<D, B>
382where
383    D: DelayUs<u16> + DelayMs<u8>,
384    B: DataBus,
385{
386    /// Unshifts the display and sets the cursor position to 0
387    ///
388    /// ```
389    /// lcd.reset();
390    /// ```
391    pub fn reset(&mut self) {
392        self.bus.write(0b0000_0010, false, &mut self.delay);
393
394        // Wait for the command to be processed
395        self.delay.delay_us(150);
396    }
397
398    /// Set if the display should be on, if the cursor should be visible, and if the cursor should blink
399    ///
400    /// ```
401    /// // Set the display to be on, the cursor to be visible, and the cursor to be blinking.
402    /// lcd.set_display_mode(true, true, true);
403    /// ```
404    pub fn set_display_mode(&mut self, display_on: bool, cursor_visible: bool, cursor_blink: bool) {
405        let display_bit = {
406            if display_on {
407                0b0000_0100
408            } else {
409                0b0000_0000
410            }
411        };
412
413        let cursor_visible_bit = {
414            if cursor_visible {
415                0b0000_0010
416            } else {
417                0b0000_0000
418            }
419        };
420
421        let cursor_blink_bit = {
422            if cursor_blink {
423                0b0000_0001
424            } else {
425                0b0000_0000
426            }
427        };
428
429        let cmd_byte = 0b0000_1000 | display_bit | cursor_visible_bit | cursor_blink_bit;
430
431        self.bus.write(cmd_byte, false, &mut self.delay);
432
433        // Wait for the command to be processed
434        self.delay.delay_us(150);
435    }
436
437    /// Clear the entire display
438    ///
439    /// ```
440    /// lcd.clear();
441    /// ```
442    pub fn clear(&mut self) {
443        self.bus.write(0b0000_0001, false, &mut self.delay);
444
445        // Wait for the command to be processed
446        self.delay.delay_ms(15u8);
447    }
448
449    /// Set the cursor position
450    ///
451    /// ```
452    /// // Move to line 2
453    /// lcd.set_cursor_pos(40)
454    /// ```
455    pub fn set_cursor_pos(&mut self, position: u8) {
456        let lower_7_bits = 0b0111_1111 & position;
457
458        self.bus
459            .write(0b1000_0000 | lower_7_bits, false, &mut self.delay);
460
461        // Wait for the command to be processed
462        self.delay.delay_us(150);
463    }
464
465    /// Shift just the cursor to the left or the right
466    ///
467    /// ```
468    /// lcd.shift_cursor(Direction::Left);
469    /// lcd.shift_cursor(Direction::Right);
470    /// ```
471    pub fn shift_cursor(&mut self, dir: Direction) {
472        let bits = match dir {
473            Direction::Left => 0b0000_0000,
474            Direction::Right => 0b0000_0100,
475        };
476
477        self.bus.write(0b0001_0000 | bits, false, &mut self.delay);
478
479        // Wait for the command to be processed
480        self.delay.delay_us(150);
481    }
482
483    /// Shift the entire display to the left or the right
484    ///
485    /// ```
486    /// lcd.shift_display(Direction::Left);
487    /// lcd.shift_display(Direction::Right);
488    /// ```
489    pub fn shift_display(&mut self, dir: Direction) {
490        let bits = match dir {
491            Direction::Left => 0b0000_0000,
492            Direction::Right => 0b0000_0100,
493        };
494
495        self.bus.write(0b0001_1000 | bits, false, &mut self.delay);
496
497        // Wait for the command to be processed
498        self.delay.delay_us(150);
499    }
500
501    fn init_4bit(&mut self) {
502        // Wait for the LCD to wakeup if it was off
503        self.delay.delay_ms(15u8);
504
505        // Initialize Lcd in 4-bit mode
506        self.bus.write(0x33, false, &mut self.delay);
507
508        // Wait for the command to be processed
509        self.delay.delay_ms(5u8);
510
511        // Sets 4-bit operation and enables 5x7 mode for chars
512        self.bus.write(0x32, false, &mut self.delay);
513
514        // Wait for the command to be processed
515        self.delay.delay_us(100);
516
517        self.bus.write(0x28, false, &mut self.delay);
518
519        // Wait for the command to be processed
520        self.delay.delay_us(100);
521
522        // Clear Display
523        self.bus.write(0x0E, false, &mut self.delay);
524
525        // Wait for the command to be processed
526        self.delay.delay_us(100);
527
528        // Move the cursor to beginning of first line
529        self.bus.write(0x01, false, &mut self.delay);
530
531        // Wait for the command to be processed
532        self.delay.delay_us(100);
533
534        // Set entry mode to increment by one
535        self.bus.write(0x06, false, &mut self.delay);
536
537        // Wait for the command to be processed
538        self.delay.delay_us(100);
539
540        self.bus.write(0x80, false, &mut self.delay);
541
542        // Wait for the command to be processed
543        self.delay.delay_us(100);
544    }
545
546    // Follow the 8-bit setup procedure as specified in the HD44780 datasheet
547    fn init_8bit(&mut self) {
548        // Wait for the LCD to wakeup if it was off
549        self.delay.delay_ms(15u8);
550
551        // Initialize Lcd in 8-bit mode
552        self.bus.write(0b0011_0000, false, &mut self.delay);
553
554        // Wait for the command to be processed
555        self.delay.delay_ms(5u8);
556
557        // Sets 8-bit operation and enables 5x7 mode for chars
558        self.bus.write(0b0011_1000, false, &mut self.delay);
559
560        // Wait for the command to be processed
561        self.delay.delay_us(100);
562
563        self.bus.write(0b0000_1110, false, &mut self.delay);
564
565        // Wait for the command to be processed
566        self.delay.delay_us(100);
567
568        // Clear Display
569        self.bus.write(0b0000_0001, false, &mut self.delay);
570
571        // Wait for the command to be processed
572        self.delay.delay_us(100);
573
574        // Move the cursor to beginning of first line
575        self.bus.write(0b000_0111, false, &mut self.delay);
576
577        // Wait for the command to be processed
578        self.delay.delay_us(100);
579
580        // Set entry mode to increment by one
581        self.bus.write(0b000_0110, false, &mut self.delay);
582
583        // Wait for the command to be processed
584        self.delay.delay_us(100);
585    }
586
587    /// Writes an entire string to the `HD44780`
588    ///
589    /// ```
590    /// lcd.write_str("Hello, world!");
591    /// ```
592    pub fn write_str(&mut self, string: &str) {
593        for c in string.chars() {
594            self.write_char(c);
595        }
596    }
597
598    /// Write a single character to the `HD44780`
599    ///
600    /// ```
601    /// lcd.write_char('A');
602    /// ```
603    pub fn write_char(&mut self, data: char) {
604        self.bus.write(data as u8, true, &mut self.delay);
605
606        // Wait for the command to be processed
607        self.delay.delay_us(100);
608    }
609
610    // Send a byte to the HD44780 by setting the data on the bus and
611    // also pulsing the enable pin
612    /*fn send_byte(&mut self, data: u8) {
613        // Pulse the enable pin
614        self.set_bus_bits(data);
615        self.pulse_enable();
616    }*/
617
618    // Pulse the enable pin telling the HD44780 that we something for it
619    /*fn pulse_enable(&mut self) {
620        self.en.set_high();
621        self.delay.delay_ms(15u8);
622        self.en.set_low();
623    }*/
624}