#include "lcd_hd44780.h" #include static int isStructOk(cm_lcd_hd44780_t *inst){ if(inst == NULL)return 0; if(inst->setGetGpio_event == NULL) return 0; if(inst->wait_event == NULL) return 0; return 1; } void lcd_hd44780_writeToDisp(cm_lcd_hd44780_t *inst){ inst->setGetGpio_event(&(inst->gpio_data),LCD_HD44780_SET); } /* void lcd_hd44780_clearDisp(lcd_hd44780_t *inst){ return; } void lcd_hd44780_printf(lcd_hd44780_t *inst, char *string){ return; }*/ static int WaitUntilReady(cm_lcd_hd44780_t *inst){ // If display is init, then use Polling Busy Flag! if(inst->isInit){ // RS = 0, RW = 1 inst->gpio_data.rs_pin = 0; inst->gpio_data.rw_pin = 1; // Read from the data bus inst->setGetGpio_event(&(inst->gpio_data), LCD_HD44780_GET); // Loop until Busy Flag (D7) is clear while (inst->gpio_data.data_bus & 0x80) { inst->setGetGpio_event(&(inst->gpio_data), LCD_HD44780_GET); } return 1; }else{ inst->wait_event(1); return 1; } } static int lcd_write_8bit(cm_lcd_hd44780_t *inst, uint8_t dataOrCmd, hd44780_InstData_t mode){ // Set cmd on databus inst->gpio_data.data_bus = dataOrCmd; // We want to set display inst->gpio_data.rw_pin = LCD_HD44780_SET; // We want to write an instruction. inst->gpio_data.rs_pin = mode; // E pin must be high when data is not ready yet. inst->gpio_data.e_pin = 1; inst->setGetGpio_event(&(inst->gpio_data),LCD_HD44780_SET); // Then Clock data in with E pin. Data is clocked on Falling edge: inst->gpio_data.e_pin = 0; inst->setGetGpio_event(&(inst->gpio_data),LCD_HD44780_SET); // Wait until display is ready: WaitUntilReady(inst); // Then set E pin high so its ready for next time: inst->gpio_data.e_pin = 1; inst->setGetGpio_event(&(inst->gpio_data),LCD_HD44780_SET); return 0; } static void lcd_writeCmd_disp(cm_lcd_hd44780_t *inst, hd44780_cmd_t cmd, hd44780_setGet_t getSet){ if(inst->bit_mode == LCD_HD44780_BITMODE_8BIT){ lcd_write_8bit(inst, cmd, LCD_HD44780_INSTRUCTION); }else{ // Write MSB first. lcd_write_8bit(inst, ((cmd >> 4) & 0x0F) << 4, LCD_HD44780_INSTRUCTION); // Write LSB last. lcd_write_8bit(inst, (cmd & 0x0F) << 4, LCD_HD44780_INSTRUCTION); } } void lcd_hd44780_printChar(cm_lcd_hd44780_t *inst, char character) { if (inst->bit_mode == LCD_HD44780_BITMODE_8BIT) { lcd_write_8bit(inst, character, LCD_HD44780_DATA); } else { // Write MSB first lcd_write_8bit(inst, ((character >> 4) & 0x0F) << 4, LCD_HD44780_DATA); // Then LSB lcd_write_8bit(inst, (character & 0x0F) << 4, LCD_HD44780_DATA); } } void lcd_hd44780_printf(cm_lcd_hd44780_t *inst, char *string) { while (*string) { lcd_hd44780_printChar(inst, *string++); } } void lcd_hd44780_print_xy(cm_lcd_hd44780_t *inst, uint8_t x, uint8_t y, const char *str) { // Base DDRAM addresses for each row (for 2-line display) const uint8_t row_offsets[] = {0x00, 0x40, 0x14, 0x54}; // for 4-line displays if (y > 3) return; // Prevent invalid row access // Set DDRAM address command: 0x80 | (offset + x) lcd_writeCmd_disp(inst, 0x80 | (row_offsets[y] + x), LCD_HD44780_SET); // Write characters while (*str) { lcd_hd44780_printChar(inst, *str++); } } void lcd_hd44780_cursorHome(cm_lcd_hd44780_t *inst) { lcd_writeCmd_disp(inst, LCD_HD44780_RETURN_HOME, LCD_HD44780_SET); } void lcd_hd44780_clearDisp(cm_lcd_hd44780_t *inst) { lcd_writeCmd_disp(inst, LCD_HD44780_CLEAR_DISP, LCD_HD44780_SET); // Wait for the command to finish. // This is a long operation (? 1.53 ms), so if not polling BF, delay at least 2 ms. if (!inst->isInit) { inst->wait_event(2); } else { WaitUntilReady(inst); } } void lcd_hd44780_initDisp(cm_lcd_hd44780_t *inst){ // Make sure E pin is high when data isnt ready on BUS! inst->gpio_data.e_pin = 1; inst->setGetGpio_event(&(inst->gpio_data),LCD_HD44780_SET); inst->wait_event(1); // Wait for more than 15ms after VCC rise.. inst->wait_event(15); lcd_writeCmd_disp(inst, LCD_HD44780_FUNCTION_SET,LCD_HD44780_SET); // Init display to 4 bit mode if selected! if(inst->bit_mode == LCD_HD44780_BITMODE_4BIT){ lcd_write_8bit(inst, 0x20, LCD_HD44780_INSTRUCTION); inst->wait_event(1); // Small delay } // Wait for 4.1ms.. // Delay(4) inst->wait_event(4); lcd_writeCmd_disp(inst, LCD_HD44780_DISP_ONOFF_CTL,LCD_HD44780_SET); // delay 100us inst->wait_event(1); lcd_writeCmd_disp(inst, LCD_HD44780_ENTRY_MODE,LCD_HD44780_SET); // Init has been done, and we can now use Busy Flag polling instead of delay! //inst->isInit = 0x1; } void lcd_hd44780_regGpioEvt(cm_lcd_hd44780_t *inst, setGet_Gpio_Event_fpt getGpioEvt_fpt){ if(inst == NULL)return; if(getGpioEvt_fpt == NULL) return; inst->setGetGpio_event = getGpioEvt_fpt; } void lcd_hd44780_regWaitEvt(cm_lcd_hd44780_t *inst, wait_ms_Event_fpt waitEvt_fpt){ if(inst == NULL)return; if(waitEvt_fpt == NULL) return; inst->wait_event = waitEvt_fpt; } void lcd_hd44780_init(cm_lcd_hd44780_t *inst, lcd_hd44780_bitmode bit_mode){ if(!isStructOk(inst)) return; inst->bit_mode = bit_mode; lcd_hd44780_initDisp(inst); lcd_hd44780_clearDisp(inst); return; }