Multiplexing switches using a PIC ADC

Discussion in 'Embedded Systems and Microcontrollers' started by bance, Feb 19, 2013.

  1. bance

    Thread Starter Member

    Aug 11, 2012
    Hi all,

    I'm trying to multiplex 3 switches onto a single pin using an ADC on a PIC16F684.

    I have the switches arranged on a resistor divider network, providing a unique voltage to the analogue input, for each switch.

    As far as I can tell the ADC is configured correctly, and since I have a useful timebase already configured, everything runs inside the ISR.

    There are 4 outputs, green LED, amber LED, red LED and white LED (the white LED flashes at 1Hz.)

    The scenario I'm trying to achieve is this:-
    The coloured LEDs are off, until a switch is made, at which point the corresponding LED is turned on (but not latched) upon release the LED is extinguished, and the white LED continues flashing the whole time, at 1Hz.

    The scenario I am realising is this:-
    As soon as the programme runs, the green LED is lit, and making button 3 (the corresponding button) does nothing. However making either of the other buttons, extinguishes the green LED and illuminates the correct LED (amber or red.) The white LED continues to flash at 1 HZ.

    Since I don't require 10 bit accuracy, and it simplifies the code, I am only using the 8 MSB. Then 0-5V equates to 0-255, full-scale, in the conversion.

    This is where I think the error lies:-
    Code ( (Unknown Language)):
    1.         banksel ADRESH
    2. ;        movlw   .0
    3. ;        xorwf   ADRESH
    4.         movlw   .1
    5.         subwf   ADRESH,w
    6.         btfss   STATUS,C        ; see if adresh contains anything
    7.         goto    INTX            ; if not exit,otherwise...
    8.         movlw   .100
    9.         subwf   ADRESH,w        ; is result >100? (switch3)
    10.         btfss   STATUS,C
    11.         goto    GRN
    12.         movlw   .150
    13.         subwf   ADRESH,w        ; is result >150? (switch1)
    14.         btfss   STATUS,C
    15.         goto    RED
    16.         bsf     PORTC,4         ; else (switch2) turn on amber LED
    17.         clrf    ADRESH
    18.         goto    INTX
    I have included a flow-chart depicting my rationale, a schematic for the circuit and the complete code.

    Point me in the right direction please!!!!

    The .txt file is code. the pdf is a flow-chart of rationale.
  2. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    Add a test for >10 otherwise the pulldown will be the "else".
    bance likes this.
  3. bance

    Thread Starter Member

    Aug 11, 2012
    Thanks thatoneguy,

    OK, so I added a zero to the first test and now the code works....

    But I'm curious as to why it doesn't work with just subtracting 1, ADRESH can only be in two states at the start of the routine:-
    1. zero
    2. something
    If I subtract 1 from 0 there's a borrow and a rollover and the result in W should be 255, with STATUS bit C cleared. (0 - 1 = 255, C=0)

    If I subtract 1 from X there's no borrow and the result in W should be X-1, with STATUS bit C set. (X - 1 = (X-1), C=1)

    Is it because I'm discarding the 2 LSB's?
  4. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    Use the PICKit Debugging function to see what the ADC is actually reading, but it does fluctuate a bit. Your code was only testing for >150, without a test for near ground, which isn't always 0, if that makes sense.
  5. bance

    Thread Starter Member

    Aug 11, 2012

    I was just wondering if discarding the LSB's had a gotcha....

    I have to admit I struggled debugging this because putting an analogue input in stimulus seem's a bit daunting. I think I have to use register injection or something and the timing factor confused me!!!

    Anyway thanks for the help,

  6. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
  7. Markd77

    Senior Member

    Sep 7, 2009
    If you are using MPLAB simulator then for simple testing I would just put a breakpoint the line after moving the ADRES into W, then change W.