Detect presence of LCD?

Status
Not open for further replies.

Experimentalist

Well-known member
Hi

I have 2 current hardware versions of a project I am building, both use Teensy 3.0. One uses a tri-colour LED for indication the other a 16 character LCD. I was wondering if anyone has any idea how I can detect if the LCD is connected and so disable the redundant code based on this.

If possible I want to do this without wasting any pins. I realise I could connect a digital pin and use this but it would be nicer if I could detect the LCD.

My code inits the LCD as follows, using 7 pins and the LiquidCrystalFast library.

// LiquidCrystalFast lcd(RS, RW, Enable, D4, D5, D6, D7)
LiquidCrystalFast lcd(22, 23, 6, 7, 8, 9, 10);

Anyone got any ideas?

Ta
Ex.
 
Last edited:
try this:

Drive (either the LED or the LCD Enable) pin with a pin configured as weak pull-down; then:
Drive a '1' on the output. wait 1 microsecond -- the pin should actually be high
drive a weak '0' on the output;
(configure the pin as an input) -- not sure if this necessary
asm("nop"); {not sure about the syntax here; repeat as necessary)
read the state of the pin

-- do all these 'quickly'. Basically, the capacitance of the element connected to the pin (guess 10 pF) will delay the weak pulldown by about 33k*10p = 0.3 us. Without input filtering, this is enough to have the delay be observed by reading the pin.

-- the 'raw' pins will have about 10 pF, so the LCD may add another 10 pF -- you'll have to experiment with the delays/nops to get a distinction.
 
Sorry, I assumed you were using a Teensy 3.0. The Teensyduino may not work as well without additional components. Here are some further hints:

1) You can invert the signals -- drive strongly to a '0' and expect the weak pullup to weakly drive a '1'; or use a strong pullup, and instead of switching from outputting a logic '1' to a weak '0', switch from a strong '1' --pinMode(xx, OUPUT) to an input -- pinMode(xx, INPUT).

If the Teensyduino is too slow, you might have to add additional capacitance on the Enable pin of the LCD. 100 pF should have no perfomance impact on the circuit, but should be distinguishable.
 
Hi

I am using the Teensy 3.0 but using the Arduino developement environment (http://arduino.cc/en/) using the Teensyduino additions (http://www.pjrc.com/teensy/teensyduino.html), rather than pure C. This was a choice to get going quicker as I had little experience with C or C++ when I first got the Teensy hardware. I realise now it is a relatively small jump but still have not made that jump.

However, I am using Visual Micro (http://www.visualmicro.com/) so as to be able to use the MS Visual Studio IDE as I am familiar with this as I use C# in my day job and at home as a hobbyist.

So, can you post some example code for the Teensy 3.0, I still do not see how to configure the pin for "weak pullup" or "strong pullup" with code alone?

Thanks for your time
Ex.
 
Last edited:
Sure -- I want to confirm myself that it will work; however it may be this weekend beore I get a chance to do it.

To explain more clearly what I am suggesting:
Assume the LCD EN pin has some observable additional capacitance when connected to the T3. If not, you could add ~ 100 pF on the LCD board between the EN pin and GND

a: Then have the T3 drive that pin strongly LOW-- it will happen in ~ 50 ns
b: Then have the T3 drive the pin weakly high -- this means it doesn't strongly force the pin high, rather uses an internal ~ 30 kohm resistance to pull the pin high (Edit -- on Arduino you can only do this as an INPUT)
c: The 30k will have to charge the 100 pF -- this takes a time of t=R*C = 30k*100p = 3 us
d: While this is happening, continuously read the state of the pin (I checked the K20 manual, this should work even if the pin is configured as an output). Basically for the first 1-2 us, you will still read the 'old' '0' value, then you will begin to see the new '1' value. The time this requires depends on the capacitance on the pin. T3 alone might be about 10 pF (i.e. 0.3 us == 16 clock cycles @ 48 MHz -- you might not be able to observe this), but connecting the LCD (especially if you add a cap) should significantly increase this.
 
Ok, this was bugging me, so I tested it.
Code:
#define LCDPin 12 // convenient
#define LEDPin 13


int readArray[20]; // increase to suit

void setup() {
  pinMode(LCDPin, OUTPUT);
  while (!Serial) { 
    digitalWrite(LEDPin, HIGH); delay(50); digitalWrite(LEDPin, LOW);
    delay(100); }   // Wait for Arduino Serial Monitor to open
}

void loop() {
pinMode(LCDPin, OUTPUT);
digitalWrite(LCDPin, LOW);
delayMicroseconds(10); // Be sure it is low
pinMode(LCDPin, INPUT_PULLUP);
for (int i=0; i < (sizeof(readArray)/sizeof(int)); i++) readArray[i] = digitalRead(LCDPin);
for (int i=0; i < (sizeof(readArray)/sizeof(int)); i++) Serial.write(readArray[i]+'0');
Serial.println();

delay(200);
}

With nothing connected, I get rows of '1': 11111111111111111111

With 91 pF, I get 4 '0', then '1' : 00001111111111111111

With my fingers + 91 pF, I get: 00000000000011111111


Hope it works for you.
 
You can become more sensitive by replacing the read with:
for (int i=0; i < (sizeof(readArray)/sizeof(int)); i++) readArray = digitalReadFast(LCDPin);


Gives 00000000000011111111 with 91 pF -- you might be able to work without adding any capacitor to the LCD !!

Ultimately this is similar to the Touch Sensor interface that is on the MCU, but I haven't tried to use that.

Edit -- unrolling the loop allows you to detect 5 pF:

Code:
#define LCDPin 12 // convenient
#define LEDPin 13


int readArray[20]; // increase to suit

void setup() {
  pinMode(LCDPin, OUTPUT);
  while (!Serial) { 
    digitalWrite(LEDPin, HIGH); delay(50); digitalWrite(LEDPin, LOW);
    delay(100); }   // Wait for Arduino Serial Monitor to open
}

void loop() {
pinMode(LCDPin, OUTPUT);
digitalWrite(LCDPin, LOW);
delayMicroseconds(10); // Be sure it is low
pinMode(LCDPin, INPUT_PULLUP);
//for (int i=0; i < (sizeof(readArray)/sizeof(int)); i++) readArray[i] = digitalReadFast(LCDPin);
readArray[0] = digitalReadFast(LCDPin);
readArray[1] = digitalReadFast(LCDPin);
readArray[2] = digitalReadFast(LCDPin);
readArray[3] = digitalReadFast(LCDPin);
readArray[4] = digitalReadFast(LCDPin);
readArray[5] = digitalReadFast(LCDPin);
readArray[6] = digitalReadFast(LCDPin);
readArray[7] = digitalReadFast(LCDPin);
readArray[8] = digitalReadFast(LCDPin);
readArray[9] = digitalReadFast(LCDPin);
readArray[10] = digitalReadFast(LCDPin);
readArray[11] = digitalReadFast(LCDPin);
readArray[12] = digitalReadFast(LCDPin);
readArray[13] = digitalReadFast(LCDPin);
readArray[14] = digitalReadFast(LCDPin);
readArray[15] = digitalReadFast(LCDPin);
readArray[16] = digitalReadFast(LCDPin);
readArray[17] = digitalReadFast(LCDPin);
readArray[18] = digitalReadFast(LCDPin);
readArray[19] = digitalReadFast(LCDPin);
for (int i=0; i < (sizeof(readArray)/sizeof(int)); i++) Serial.write(readArray[i]+'0');
Serial.println();

delay(200);
}
 
Last edited:
You're welcome; I learned too.

I tried to make the detection faster, while preserving Teensyduino compatibility. Here is my 'fastest' version (i.e. most sensitive to small capacitances). Basically, I extracted the variable portions from Paul's Teensy macros, and also abused the gcc ## macro preprocessing capability -- perhaps this isn't the most robust, but it works for now. Note that if LCDPin is a variable (not a #defined macro), it won't work.

Also, turning off interrupts during the measurement gives a more consistent result (it can still dither between two adjacent integers).

Code:
// 5 counts = 20 pF

#define LCDPin 12 // convenient
#define LEDPin 13

#define digitalReadFasterMacro(pin) CORE_PIN ## pin ## _PINREG
#define digitalReadFaster(pin) digitalReadFasterMacro(pin)

#define digitalReadFasterMaskMacro(pin) CORE_PIN ## pin ## _BITMASK
#define digitalReadFasterMask(pin) digitalReadFasterMaskMacro(pin)

uint32_t readArray[20]; // increase to suit
int iLoop = 0;

void setup() {
  pinMode(LCDPin, OUTPUT);
  pinMode(LEDPin, OUTPUT);
  Serial.begin(115200);
  while (!Serial) { 
    digitalWrite(LEDPin, HIGH); delay(50); digitalWrite(LEDPin, LOW);
    delay(100); }   // Wait for Arduino Serial Monitor to open
}

void loop() {
int iMeasure = 0; 
int j=0;
pinMode(LCDPin, OUTPUT);
digitalWrite(LCDPin, LOW);
delayMicroseconds(10); // Be sure it is low
*portConfigRegister(LCDPin) = PORT_PCR_MUX(1) | PORT_PCR_PE | PORT_PCR_PS;
noInterrupts();
// pinMode(LCDPin, INPUT_PULLUP);
*portModeRegister(LCDPin) = 0; // Actually switch
// for (int i=0; i < (sizeof(readArray)/sizeof(uint32_t)); i++) readArray[i] = GPIOC_PDIR; // too slow
// This compiles to the same as readArray[constant] = ...
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
readArray[j++] = digitalReadFaster(LCDPin);
interrupts();
for (int i=0; i < (sizeof(readArray)/sizeof(uint32_t)); i++) if(!(readArray[i] & digitalReadFasterMask(LCDPin))) iMeasure=i;
Serial.print(iLoop++); Serial.write(' '); Serial.println(iMeasure);

delay(100);
}
 
Last edited:
For future reference, could this be simplified by using the Teensy 3's built-in capacitance sensing?

The touchRead() function measures the capacitance of a pin. It is sensitive enough to distinguish between a few inches of wire attached to a pin or not. I think all that's needed is a little experimentation to measure the difference between one external configuration and the other.
 
Status
Not open for further replies.
Back
Top