Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 13 of 13

Thread: Detect presence of LCD?

  1. #1
    Senior Member
    Join Date
    Nov 2012
    Location
    Chipping Norton, UK
    Posts
    221

    Detect presence of LCD?

    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 by Experimentalist; 02-11-2013 at 03:38 PM. Reason: Typo

  2. #2
    Senior Member Jp3141's Avatar
    Join Date
    Nov 2012
    Posts
    458
    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.

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Location
    Chipping Norton, UK
    Posts
    221
    Thanks for the reply. I must admit it is a little over my head. One thing I did not point out is I am using Teensyduino. I have had a look at the following and can see an option to use INPUT_PULLUP:

    http://www.pjrc.com/teensy/td_digital.html

    However, I am not sure what you mean by
    Quote Originally Posted by Jp3141 View Post
    weak pull-down
    . Is this a C programming function? Can you send me a link to some reading material or some example code?

    Thanks

  4. #4
    Senior Member
    Join Date
    Nov 2012
    Location
    Chipping Norton, UK
    Posts
    221
    Hi

    So reading some more are you referring to me providing the
    Quote Originally Posted by Jp3141 View Post
    weak pull-down
    by adding an external resistor (10K ?) between the enable pin and ground to create the
    Quote Originally Posted by Jp3141 View Post
    weak pull-down
    ?

  5. #5
    Senior Member Jp3141's Avatar
    Join Date
    Nov 2012
    Posts
    458
    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.

  6. #6
    Senior Member
    Join Date
    Nov 2012
    Location
    Chipping Norton, UK
    Posts
    221
    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 by Experimentalist; 02-12-2013 at 02:55 PM. Reason: Typo

  7. #7
    Senior Member Jp3141's Avatar
    Join Date
    Nov 2012
    Posts
    458
    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.

  8. #8
    Senior Member Jp3141's Avatar
    Join Date
    Nov 2012
    Posts
    458
    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.

  9. #9
    Senior Member Jp3141's Avatar
    Join Date
    Nov 2012
    Posts
    458
    You can become more sensitive by replacing the read with:
    for (int i=0; i < (sizeof(readArray)/sizeof(int)); i++) readArray[i] = 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 by Jp3141; 02-12-2013 at 05:57 PM.

  10. #10
    Senior Member
    Join Date
    Nov 2012
    Location
    Chipping Norton, UK
    Posts
    221
    Quote Originally Posted by Jp3141 View Post
    Ok, this was bugging me
    Hi

    I really appreciate the time you have taken to spell this out.

    Going to try it now, will report right back . . .

  11. #11
    Senior Member
    Join Date
    Nov 2012
    Location
    Chipping Norton, UK
    Posts
    221
    Thanks !!!

    Working for me on the bread board

    I really appreciate your time

  12. #12
    Senior Member Jp3141's Avatar
    Join Date
    Nov 2012
    Posts
    458
    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 by Jp3141; 02-13-2013 at 01:36 PM. Reason: int iMeasure = 0;

  13. #13
    Senior Member pictographer's Avatar
    Join Date
    May 2013
    Location
    San Jose, CA
    Posts
    664
    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.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •