#include "LiquidCrystal.h" #include "nrf_gpio.h" #include "app_timer.h" /* * Arduino | LCD | nrf51 * D4 | DB4 | P0.16 * D5 | DB5 | P0.17 * D6 | DB6 | P0.18 * D7 | DB7 | P0.10 * D8 | RS | P0.20, register select. 0=instruction (write), 0=busy (read), 1=data * D9 | EN | P0.23, clock, data is clocked in/out on falling edge * D10 | DB4 | P0.24 */ enum liquid_crystal_cmd { LIQUID_CRYSTAL_CMD_CLEAR = 0x01, LIQUID_CRYSTAL_CMD_RETURN_HOME = 0x02, LIQUID_CRYSTAL_CMD_ENTRY_MODE_SET = 0x04, LIQUID_CRYSTAL_CMD_DISPLAY = 0x08, LIQUID_CRYSTAL_CMD_SHIFT = 0x10, LIQUID_CRYSTAL_CMD_FUNCTION_SET = 0x20, LIQUID_CRYSTAL_CMD_SET_CGRAM_ADDDRESS = 0x40, LIQUID_CRYSTAL_CMD_SET_DDRAM_ADDDRESS = 0x80, }; static struct { uint8_t pin_db4; uint8_t pin_db5; uint8_t pin_db6; uint8_t pin_db7; uint8_t pin_rs; uint8_t pin_en; app_gpiote_user_id_t gpio_user_id; } data = { .pin_db4 = 16, .pin_db5 = 17, .pin_db6 = 18, .pin_db7 = 19, .pin_rs = 20, .pin_en = 23, }; static uint32_t ticks_per_ms; static void event_handler() { } static void wait_ms(uint32_t ms) { uint32_t ticks; app_timer_cnt_get(&ticks); const uint32_t end_ticks = ticks + ms * ticks_per_ms; do { app_timer_cnt_get(&ticks); } while (ticks < end_ticks); } static void write_4(uint8_t value) { nrf_gpio_pin_write(data.pin_db4, value & 0x01); nrf_gpio_pin_write(data.pin_db5, value & 0x02); nrf_gpio_pin_write(data.pin_db6, value & 0x04); nrf_gpio_pin_write(data.pin_db7, value & 0x08); nrf_gpio_pin_set(data.pin_en); nrf_gpio_pin_clear(data.pin_en); } static void write_value(uint8_t value, bool is_data) { nrf_gpio_pin_write(data.pin_rs, is_data); write_4(value >> 4); write_4(value); } static void begin() { nrf_gpio_pin_clear(data.pin_rs); nrf_gpio_pin_clear(data.pin_en); // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! // according to datasheet, we need at least 40ms after power rises above 2.7V // before sending commands. Arduino can turn on way before 4.5V so we'll wait 50 wait_ms(50); write_4(0x03); wait_ms(5); // 4.5ms write_4(0x03); wait_ms(5); // 4.5ms write_4(0x03); wait_ms(5); // 4.5ms write_4(0x02); write_value(LIQUID_CRYSTAL_CMD_DISPLAY, false); // _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; liquid_crystal_display(true, true, true); } void liquid_crystal_write_char(char chr) { write_value(chr, true); } void liquid_crystal_write_string(char *chr) { while (*chr != '\0') { liquid_crystal_write_char(*chr); } } uint32_t liquid_crystal_display(bool display_on, bool cursor_on, bool blink) { uint8_t value = LIQUID_CRYSTAL_CMD_DISPLAY; value |= display_on ? 0x04 : 0x00; value |= cursor_on ? 0x02 : 0x00; value |= blink ? 0x01 : 0x00; write_value(value, false); return NRF_SUCCESS; } uint32_t liquid_crystal_init(uint32_t _ticks_per_ms) { ticks_per_ms = _ticks_per_ms; uint32_t err_code = app_gpiote_user_register(&data.gpio_user_id, 0x0000, 0x0000, event_handler); if (err_code != NRF_SUCCESS) { return err_code; } nrf_gpio_cfg_output(data.pin_db4); nrf_gpio_cfg_output(data.pin_db5); nrf_gpio_cfg_output(data.pin_db6); nrf_gpio_cfg_output(data.pin_db7); nrf_gpio_cfg_output(data.pin_rs); nrf_gpio_cfg_output(data.pin_en); begin(data); return NRF_SUCCESS; }