dahnielson
Posts: 1
Joined: Thu Jun 28, 2018 8:25 pm
Location: Sweden

Can't get I2C enabled LCD to work in C

Sun Jul 01, 2018 7:28 pm

I'm trying to learn how to communicate with I2C devices in C. So as a first project I'm using a 16x2 LCD. After wiring up the LCD I checked that it worked by using the RPiSpy test script (it did.) I then tried to get my own version of it in C to work (it didn't) and I can't figure out why. It compile and run but doesn't display anything on the LCD.

Here's a gist with my code: https://gist.github.com/dahnielson/2c74 ... 4e535f6f97

Any help would be appreciated.

User avatar
DougieLawson
Posts: 33350
Joined: Sun Jun 16, 2013 11:19 pm
Location: Basingstoke, UK
Contact: Website

Re: Can't get I2C enabled LCD to work in C

Mon Jul 02, 2018 10:17 am

/home/pi/c/commonLcd.h

Code: Select all

#ifndef COMMONLCD_H
#define COMMONLCD_H

//Lcd instructions
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_CGRAMADDRESS 0x40
#define LCD_DDRAMADDRESS 0x80

//display control flags
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_HIDECURSOR 0x00
#define LCD_SHOWCURSOR 0x02
#define LCD_CURSORBLINKON 0x01
#define LCD_CURSORBLINKOFF 0x00

//cursor/display flags
#define LCD_MOVECURSOR 0x00
#define LCD_SHIFTDISPLAY 0x08
#define LCD_LEFT 0x00
#define LCD_RIGHT 0x04

#define PIN_ENABLE 4
#define PIN_RS 6
#define PIN_BACKLIGHT 7

#define I2C_ADDR 0x27
#define IODIRA   0x00
#define IODIRB   0x01
#define OLATA    0x14
#define OLATB    0x15

typedef enum
{ CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HOME } cursorMovement;
typedef enum
{ DISPLAY_SCROLLEFT, DISPLAY_SCROLLRIGHT } displayScroll;
typedef enum
{ LCD_COMMAND_MODE, LCD_CHARACTER_MODE } modes;

typedef struct
{
  int registerSelect;
  int enable;

  int D4;
  int D5;
  int D6;
  int D7;

  int colNumber;
  int rowNumber;
  int displayControl;
} hd44780;

void byte_to_binary (int x);
void moveCursor (hd44780 * header, cursorMovement movement);
void scrollDisplay (hd44780 * header, displayScroll scroll);
void printString (hd44780 * header, char *string);
void clearDisplay (hd44780 * header);
void cursorControl (hd44780 * header, int state);
void cursorBlink (hd44780 * header, int state);
void printInt32 (hd44780 * header, int val);
void setPrintPosn (hd44780 * header, int offset);
void defineCGChars (hd44780 * header, char array[8][8]);
void setDefaultHd44780 (hd44780 * header);
void initialiseDisplay (hd44780 * header);
void writeBytes (hd44780 * header, int byte, int mode);
void delay (unsigned int howLong);

#endif
/home/pi/c/mainLcd.c

Code: Select all

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "linux/i2c-dev.h"
#include "commonLcd.h"

hd44780 header;

struct tm *timeinfo;

time_t rawtime;

char time_of_day[16];
char fortySP[40];
static char *i2cDevice = "/dev/i2c-1";

int gpio_reg;
int i2c_fd;
int offset = 0;
int len;

void byte_to_binary (int x)
{
  int z;
  static char b[9];
  b[0] = '\0';

  for (z = 128; z > 0; z >>= 1)
    {
      strcat (b, ((x & z) == z) ? "1" : "0");
    }
  printf ("%c %02x %s\n", x, x, b);
}

void moveCursor (hd44780 * header, cursorMovement movement)
{
  if (!header) return;
  if (movement == CURSOR_RIGHT)
    writeBytes (header, 0b00010100, LCD_COMMAND_MODE);
  else if (movement == CURSOR_LEFT)
    writeBytes (header, 0b00010000, LCD_COMMAND_MODE);
  else
    writeBytes (header, 0b00000010, LCD_COMMAND_MODE);

}

void printString (hd44780 * header, char *string)
{
  int positionInLine = 0;
  int i;

  if (!header || !string || !*string) return;
  for (i = 0; string[i] != '\0'; i++)
    {
      if (positionInLine == header->rowNumber)
        {
          writeBytes (header, LCD_DDRAMADDRESS | 0xC0, LCD_COMMAND_MODE);      //jump to next line
          positionInLine = 0;
        }
      if (string[i] == '\n')
        {
          writeBytes (header, LCD_DDRAMADDRESS | 0xC0, LCD_COMMAND_MODE);
          positionInLine = 0;
        }
      else
        {
          writeBytes (header, string[i], LCD_CHARACTER_MODE);
          positionInLine = positionInLine + 1;
        }
    }

}

void scrollDisplay (hd44780 * header, displayScroll scroll)
{
  if (!header) return;
  if (scroll == DISPLAY_SCROLLEFT)
    {
      writeBytes (header, LCD_CURSORSHIFT | LCD_SHIFTDISPLAY | LCD_LEFT,
                  LCD_COMMAND_MODE);
    }
  else if (scroll == DISPLAY_SCROLLRIGHT)
    {
      writeBytes (header, LCD_CURSORSHIFT | LCD_SHIFTDISPLAY | LCD_RIGHT,
                  LCD_COMMAND_MODE);
    }
}

void clearDisplay (hd44780 * header)
{
  if (!header) return;
  writeBytes (header, LCD_CLEARDISPLAY, LCD_COMMAND_MODE);
}

void cursorControl (hd44780 * header, int state)
{
  if (!header) return;
  if (state)
    header->displayControl =
      (header->
       displayControl | LCD_DISPLAYON | LCD_DISPLAYCONTROL | LCD_SHOWCURSOR);
  else
    header->displayControl =
      (header->
       displayControl | LCD_DISPLAYON | LCD_DISPLAYCONTROL | LCD_HIDECURSOR) &
      ~LCD_SHOWCURSOR;
  writeBytes (header, header->displayControl, LCD_COMMAND_MODE);
}
void setPrintPosn (hd44780 * header, int offset)
{
  if (!header) return;
  int posn = LCD_DDRAMADDRESS | offset;
  writeBytes (header, posn, LCD_COMMAND_MODE);
}

void cursorBlink (hd44780 * header, int state)
{
  if (!header) return;
  if (state)
    header->displayControl =
      (header->
       displayControl | LCD_DISPLAYON | LCD_DISPLAYCONTROL |
       LCD_CURSORBLINKON);
  else
    header->displayControl =
      (header->
       displayControl | LCD_DISPLAYON | LCD_DISPLAYCONTROL |
       LCD_CURSORBLINKOFF) & ~LCD_CURSORBLINKON;
  writeBytes (header, header->displayControl, LCD_COMMAND_MODE);
}

void printInt32 (hd44780 * header, int val)
{
  int i;
  if (!header) return;
  for (i = 0; i < 32; i++)
    {
      if (i == header->rowNumber)
        writeBytes (header, LCD_DDRAMADDRESS | 0xC0, LCD_COMMAND_MODE); //jump to next line
      if ((val >> i) & 0x01)
        writeBytes (header, 0x31, LCD_CHARACTER_MODE);
      else
        writeBytes (header, 0x30, LCD_CHARACTER_MODE);
    }
}

void defineCGChars (hd44780 * header, char array[8][8])
{
  char CGbyte;
  int i, j;

  for (i = 0; i < 8; i++)
    {
      CGbyte = LCD_CGRAMADDRESS | (i << 3);
      writeBytes (header, CGbyte, LCD_COMMAND_MODE);
      for (j = 0; j < 8; j++)
        {
          writeBytes (header, array[i][j], LCD_CHARACTER_MODE);
        }
    }
}

int i2c_open (char *dev)
{
  if ((i2c_fd = open (dev, O_RDWR)) < 0)
    {
      printf ("error opening %s\n", dev);
      return -1;
    }
  if (ioctl (i2c_fd, I2C_SLAVE, I2C_ADDR) < 0)
    {
      printf ("Failed to set slave address");
      return -2;
    }
  return 0;
}

void delay (unsigned int howLong)
{
  struct timespec sleeper, dummy;

  sleeper.tv_sec = (time_t) (howLong / 1000);
  sleeper.tv_nsec = (long) (howLong % 1000) * 1000000;

  nanosleep (&sleeper, &dummy);
}

static void writeByte (uint8_t reg, uint8_t data)
{
  i2c_smbus_write_byte_data (i2c_fd, reg, data);
}

static void pulse (hd44780 * header)
{
  delay (1);
  gpio_reg &= (0xff - (1 << PIN_ENABLE));
  writeByte (OLATA, gpio_reg);
  delay (1);
  gpio_reg |= 1 << PIN_ENABLE;
  writeByte (OLATA, gpio_reg);
  delay (1);
  gpio_reg &= (0xff - (1 << PIN_ENABLE));
  writeByte (OLATA, gpio_reg);
  delay (1);

}

void initialiseDisplay (hd44780 * header)
{
  header->colNumber = 2;
  header->rowNumber = 16;
  i2c_open (i2cDevice);
  writeByte (IODIRA, 0x00);
  gpio_reg |= 1 << PIN_BACKLIGHT;
  writeByte (OLATA, gpio_reg);

  writeBytes (header, 0b00110011, LCD_COMMAND_MODE);
  writeBytes (header, 0b00110000, LCD_COMMAND_MODE);
  writeBytes (header, 0b00000110, LCD_COMMAND_MODE);

  header->displayControl =
    (header->displayControl | LCD_DISPLAYCONTROL) | LCD_DISPLAYON;
  writeBytes (header, header->displayControl, LCD_COMMAND_MODE);
}

void
writeBytes (hd44780 * header, int byte, int mode)
{
  if (!header)
    return;

  gpio_reg |= mode << PIN_RS;
  writeByte (OLATA, gpio_reg);
  delay (1);

  gpio_reg = gpio_reg | (byte >> 4);
  pulse (header);
  gpio_reg = gpio_reg & (0xff - (0x0f));
  gpio_reg = gpio_reg | (byte & 0x0f);
  pulse (header);
  gpio_reg = gpio_reg & (0xff - (1 << PIN_RS) - (0x0f));
}

int main (int argc, char* argv[])
{
  strcpy(fortySP, "                                        ");

  initialiseDisplay (&header);
  clearDisplay (&header);
  moveCursor (&header, CURSOR_HOME);
  cursorControl (&header, 0);
  cursorBlink (&header, 0);

  while (1)
    {

      time (&rawtime);
      timeinfo = localtime (&rawtime);

      strftime (time_of_day, 16, "%T %b,%d\n", timeinfo);

      clearDisplay (&header);
      moveCursor (&header, CURSOR_HOME);
      printString (&header, time_of_day);
      printString (&header, "\n");
      sleep (2);
    }

  return 0;
}
Microprocessor, Raspberry Pi & Arduino Hacker
Mainframe database troubleshooter
MQTT Evangelist
Twitter: @DougieLawson

2012-18: 1B*5, 2B*2, B+, A+, Z, ZW, 3Bs*3, 3B+

Any DMs sent on Twitter will be answered next month.

Return to “C/C++”

Who is online

Users browsing this forum: No registered users and 4 guests