HD44780

Display that is used is HD44780 with I2C IO-expander connected to it. This was an practical way to reduce used IO’s since otherwise minimun of 7-IO’s would be required by display(4-data,EN,RW,RS). Using expander, only two I2C-pins is used. Expander have been bought at ebay many years ago but aliexpress sells same thing still. I2C-expander chip is PCF8574.

expander

memset function is used to init lcdbuf array to show clear on LCD. Otherwise first four init dataset is used for just in case, since some LCD-screen variations seems to require it. Rest of inits are done like HD44780 datasheet tells. Only reason why LCD is set to use 4-bit data is since this is ported to this platform from my old Atmel Atmega128 microcontroller code where 4-bit bus was used.

void lcdinit(){
        memset((void*)&lcdbuf, 20, sizeof(int)*32);             //alustetaan lcdbufferi näyttämään tyhjää
        volatile unsigned char lcd_data;
        lcd_data=0b00110000;
        i2c_write_byte_no_reg(DEV_ADDR,lcd_data);
        e_puls(lcd_data);
        nrf_delay_ms(6);

        lcd_data=0b00110000;
        i2c_write_byte_no_reg(DEV_ADDR,lcd_data);
        e_puls(lcd_data);
        nrf_delay_ms(6);

        lcd_data=0b00110000;
        i2c_write_byte_no_reg(DEV_ADDR,lcd_data);
        e_puls(lcd_data);
        nrf_delay_ms(6);

        lcd_data=0b00100000;
        i2c_write_byte_no_reg(DEV_ADDR,lcd_data);
        e_puls(lcd_data);
        nrf_delay_ms(6);

        sendcmd(0x28); nrf_delay_ms(2); //Function set,  4bit, 2rivinen, 42 us  :0b00101000
        sendcmd(0x08); nrf_delay_ms(2); //display off,curs off, blink off, 42 us:0b00001000
        sendcmd(0x01); nrf_delay_ms(2); //clear display, min 1.64 ms                    :0b00000001
        sendcmd(0x06); nrf_delay_ms(2); //entry mode set                                                :0b00000110
        sendcmd(0x0C); nrf_delay_ms(2); //display on,curs off,blink off                 :0b00001011
        sendcmd(0x80); nrf_delay_ms(2); //DD-address=0                                                  :0b10000000

        sendcmd(2); nrf_delay_ms(2);

}

Since data is 4-bit, data send operation is done two times where first four high bits are send first, then lower four. This version of fuction is used to send commands, so RS bit is set to 0.

void sendcmd(volatile unsigned char a)
{
        volatile unsigned char lcd_data=0;
        lcd_data = (0b11110000 & a);                                    //get high 4 bits
        i2c_write_byte_no_reg(DEV_ADDR,lcd_data);
        e_puls(lcd_data);                                               //pulse to set D4-D7 bits

        lcd_data = a<<4;                                                                                                //get low 4 bits
        lcd_data =(lcd_data & 0b11110000);
        i2c_write_byte_no_reg(DEV_ADDR,lcd_data);
        e_puls(lcd_data);

}

This is same as previous, but RS bit is set to 1, signaling to LCD that character is send.

void sendchar(volatile unsigned char a)
        {
        volatile unsigned char lcd_data=0;
        lcd_data = (0b11110000 & a)+1;                                                                  //get high 4 bits
        //RS 1-tilaan
        i2c_write_byte_no_reg(DEV_ADDR,lcd_data);
        e_puls(lcd_data);                                               //pulse to set D4-D7 bits

        lcd_data = a<<4;                                                //get low 4 bits
        lcd_data=(0b11110000 & lcd_data)+1;
        i2c_write_byte_no_reg(DEV_ADDR,lcd_data);
        e_puls(lcd_data);

}

This function is called whenever character on LCD is changed. Basically every character from buffer is send always when this function is called.

void lcdkirj()
{

        int a;

        sendcmd(128); nrf_delay_ms(2);
        sendcmd(2); nrf_delay_ms(2);
        for(a=0;a<=31;a++)
        {
                sendchar(lcdbuf[a]); nrf_delay_us(40);
                if(a==15){ sendcmd(0b11000000); nrf_delay_us(40);}


        }
}