Using a arduino to reduce the number of pins needed for a LCD

Hi I have one 8 wire LCD screen and I have plenty of arduino's lying around. As I have a project needing a LCD (and I don't have 8 pins free) I'd like to use an Arduino to control the LCD and talk to it via a 2 wire protocol. I would prefer to run a sketch on the slave Arduino that makes it behave as a 2 wire LCD. I googled for a sketch to do this but I didn't find anything. Anyone has any leads? Best regards Jantje

I2C slave should do it I'll have a look

this is a nice tutorial - http://dsscircuits.com/articles/arduino-i2c-slave-guide.html -

this is the basics - http://arduino.cc/en/Tutorial/MasterReader - eh

this is what you really need - http://arduino.cc/en/Tutorial/MasterWriter -

X-mas gift, a starter for the sketch

//
//    FILE: I2C2LCD.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: demo 
//    DATE: 2013-12-21
//     URL:
//
// Released to the public domain
//


#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

#include <Wire.h>

void setup()
{
  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  lcd.setCursor(0, 1);

  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
}

void loop()
{
}

void receiveEvent(int howMany)
{
  while(Wire.available()) 
  {
    char c = Wire.read();
    lcd.print(c); 
  }
}

Not tested,
you might need to put the received chars in a buffer and print them slowly in loop()

nice christmas gift :-) I'll need to read up and come back :-) Jantje

be aware I did not test it in any way :)

It should be possible to let it work with standard I2C LCD library from fmalpartida (good stuff) - https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home -

Hi! Here is a version that is available in Cosa. It implements the LCD interface over TWI. Both master and slave code. https://github.com/mikaelpatel/Cosa/blob/master/cores/cosa/Cosa/LCD/Driver/VLCD.hh https://github.com/mikaelpatel/Cosa/blob/master/cores/cosa/Cosa/LCD/Driver/VLCD.cpp https://github.com/mikaelpatel/Cosa/blob/master/examples/LCD/CosaLCDslave/CosaLCDslave.ino

There are some benchmarking number in this blog: http://cosa-arduino.blogspot.se/2013/07/object-oriented-lcd-management.html

It is possible to get at least an X2 performance increase compared to standard TWI.

Cheers!

@kowalski Looks closer to what I need. I will need to do some more reading. Best regards Jantje

@kowalski It comes to me that the Cosa library is not yet 1.5.x compatible. I ask because I need 1.5.x as I want to run on a yun. Best regards Jantje

Jantje: It comes to me that the Cosa library is not yet 1.5.x compatible. I ask because I need 1.5.x as I want to run on a yun.

@jantje

Yes - that is true. Cosa is Arduino 1.0.5 for now but the transition to 1.5.X is not that difficult as it basically requires adjusting the platform, board and programmer configuration files. I have not yet figured out how to allow support for both tracks in the same repository. JohnMod's fork attempts to add the necessary changes. See his commits; https://github.com/JohnMod/Cosa/commits/master

Anyway, the slave LCD Arduino should be able to run the Cosa VLCD slave code. What you can do is simply port the proxy VLCD class to Arduino 1.5.X. At most an hours effort.

Cheers & Merry Christmas!

I didn't really get the whole cosa thing so I made an ordinary arduino library. And got it to working. Don't know why I need to add delays between sending of the commands over twi but the rest works nicely. Will probably share the lib tomorrow. Jantje

how long are the delay’s you need to add??

robtillaart: how long are the delay's you need to add??

I tried 1 and that didn't help 10 does. I didn't go into more detail for now. Jantje

delay(1) seems to do the trick anyways (well I did change from inline to normal functions)
As master use one of the LiquidCrystal examples but with my lib

this is the slave

#include "Arduino.h"
#include "Wire.h"
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
#define redPin 11
#define greenPin 10
#define bluePin 9


void receiveEvent(int howMany);

void setup()
{
	Serial.begin(115200 );
	Serial.println("LCDSlave");
	// set up the LCD's number of columns and rows:
	lcd.begin(16, 2);
	lcd.setCursor(0, 1);
	lcd.println(F("listening for twi"));

	Wire.begin(0x38);                // join i2c bus with address 0x38
	Wire.onReceive(receiveEvent); // register event
	pinMode( redPin ,OUTPUT);
	pinMode( greenPin ,OUTPUT);
	pinMode( bluePin ,OUTPUT);
	analogWrite(redPin,255);
	analogWrite(greenPin,255);
	analogWrite(bluePin,255);

}
#define BUFFERSIZE 50
char commandBuffer[BUFFERSIZE + 1];
byte bufferPos = 0;
void processTWIReceivedData();
void loop()
{
	if (Wire.available())
	{
		char c = Wire.read();
		//lcd.print(c);
		Serial.print(c);
		if (c == '\n') c = 0;
		if (c == '\r') c = 0;
		if (bufferPos < BUFFERSIZE)
		{
			commandBuffer[bufferPos++] = c; //Put the value in the buffer
			commandBuffer[bufferPos] = 0; //terminate with 0 so all C/C++ string functions work
		} else
		{
			Serial.println();
			Serial.println("ERROR: buffer overflow");
			bufferPos = 0;
		}
		if (c == 0)
		{
			if (bufferPos > 2)
			{
				processTWIReceivedData();
			}
			bufferPos = 0;
			commandBuffer[bufferPos] = 0;
		}

	}

}

void processTWIReceivedData()
{
	if (strcmp_P(commandBuffer, (const char *) F( "clear")) ==0)
	{
		lcd.clear();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "home")) ==0)
	{
		lcd.home();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "noDisplay;")) ==0)
	{
		lcd.noDisplay();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "display")) ==0)
	{
		lcd.display();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "noBlink")) ==0)
	{
		lcd.noBlink();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "blink")) ==0)
	{
		lcd.blink();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "noCursor")) ==0)
	{
		lcd.noCursor();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "cursor")) ==0)
	{
		lcd.cursor();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "scrollDisplayLeft")) ==0)
	{
		lcd.scrollDisplayLeft();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "scrollDisplayRight")) ==0)
	{
		lcd.scrollDisplayRight();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "leftToRight")) ==0)
	{
		lcd.leftToRight();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "rightToLeft")) ==0)
	{
		lcd.rightToLeft();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "autoscroll")) ==0)
	{
		lcd.autoscroll();
		return;
	}
	if (strcmp_P(commandBuffer,(const char *) F( "noAutoscroll")) ==0)
	{
		lcd.noAutoscroll();
		return;
	}
	if (strncmp_P(commandBuffer,(const char *)F("print;"),6)==0)
	{
		char * dataPointer=commandBuffer+6;
		lcd.print(dataPointer);
		return;
	}
	if (strncmp_P(commandBuffer,(const char *)F("println;"),8)==0)
	{
		char * dataPointer=commandBuffer+8;
		lcd.print(dataPointer);
		return;
	}
	if (strncmp_P(commandBuffer,(const char *)F("setCursor;"),10)==0)
	{
		char * dataPointer=commandBuffer+10;
		char * sep= strchr(dataPointer,';');
		if (sep==0)
		{
			Serial.print(F("ERROR: Incomplete command "));
			return;
		}
		*sep=0;
		uint8_t col = (uint8_t) atoi(dataPointer);
		uint8_t row = (uint8_t) atoi(++sep);
		lcd.setCursor(col,row);
		return;
	}
	if (strncmp_P(commandBuffer,(const char *)F("setBackground;"),14)==0)
	{
		char * dataPointer=commandBuffer+14;
		char * sep1= strchr(dataPointer,';');
		if (sep1==0)
		{
			Serial.print(F("ERROR: Incomplete command 1"));
			return;
		}
		char * sep2= strchr(sep1+1,';');
		if (sep2==0)
		{
			Serial.print(F("ERROR: Incomplete command 2"));
			return;
		}
		*sep2=0;
		uint8_t red = (uint8_t) atoi(dataPointer);
		uint8_t green = (uint8_t) atoi(++sep1);
		uint8_t blue = (uint8_t) atoi(++sep2);
		Serial.print("setBackground (");
		Serial.print(red);
		Serial.print(" , ");
		Serial.print(green);
		Serial.print(" , ");
		Serial.print(blue);
		Serial.println(" )");

		analogWrite(redPin,red);
		analogWrite(greenPin,green);
		analogWrite(bluePin,blue);
		return;
	}

	Serial.print(F("Unknown command. : "));
}

void receiveEvent(int howMany)
{

}

If anyone has a clue why I need the delay or how I can get rid of it in a good way…I’m listening
Jantje

PS had to cut down on code due to maximum allowed length

what happens if you leave out the delay(1), does it fail everytime?

When I leave out the delay(1) the next message is not received. It looks as if the new send comes to soon. I have uploaded the library and slave and master examples to my github repository. You can find them here. https://github.com/jantje/libraries/tree/master/I2CLiquidCrystal Best regards Jantje

Ik zie geen directe verklaring voor de delay(1), maar wellicht dat de interne buffer nog niet leeg is. De Wire.endTransmission() doet het versturen en dat gebeurt synchroon dus als die call terugkeert, dan zit het ook allemaal in de buffer. Een 2e call kan wachten tot de buffer leeg is.

Wat je kan proberen is de I2C snelheid verhogen. Voeg aan beide kanten NA Wire.begin() toe TWBR=2 I2C -> 800KHz of TWBR=12 I2C -> 400KHz vermoedelijk staat ie nu op 100 KHz. (waarde van TWBR =72, is een byte, kan je printen)


Volgende stap is - een toetsenbord erbij, die via I2C uit te lezen is.... - multi "monitor" opstelling => 1 master 3 slave LCD's

robtillaart: Volgende stap is - een toetsenbord erbij, die via I2C uit te lezen is.... - multi "monitor" opstelling => 1 master 3 slave LCD's

Neen, neen :-) volgende stap is de lcd gebruiken waar ik hem voor wou gebruiken.

Voor wat betreft de delay. Het zou kunnen zijn dat het komt omdat ik het lezen van de wire event naar de loop heb verhuisd. Jantje

Jantje: Voor wat betreft de delay. Het zou kunnen zijn dat het komt omdat ik het lezen van de wire event naar de loop heb verhuisd. Jantje

Ik heb de proef op de som genomen en inderdaad nadat alle code naar de event was verhuisd werkte het goed. Maar ook een stuk trager :-( Ik had eerst alles in een buffer geschreven die dan gecopieerd en dan de LCD aangestuurd vanaf de copie. Maar dat werkte ook niet zo goed. Blijkbaar werd de buffer al weer overschreven terwijl de LCD nog bezig was. Blijkbaar zit de master te wachten tot alles in de event is verwerkt.

Met vriendelijke groet. Jantje

PS ik moet de nieuwe versie van de slave nog uploaden.

Jantje: @kowalski It comes to me that the Cosa library is not yet 1.5.x compatible. I ask because I need 1.5.x as I want to run on a yun.

@Jantje

Need to ask you a question about 1.5.X. Do you think it is stable enough to start adding support for this? It isn't that much as I understand; new boards/platform file and build support. There is also a somewhat different directory structure with support for multiple architectures.

Also do you know if it is possible for a core to support both 1.0.5 and 1.5.X?

Cheers!