216 lines
5.0 KiB
C
216 lines
5.0 KiB
C
#include "lcd_hd44780.h"
|
|
#include <stddef.h>
|
|
|
|
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;
|
|
}
|
|
|