1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

The use of an LCD on port B, together with an analog output RB0 (AN12)

Discussion in 'Oshonsoft' started by Winch, Jan 21, 2017.

  1. Winch

    Winch New Member

    Joined:
    Sep 5, 2014
    Messages:
    24
    Likes:
    0
    Hello,
    On port B of a 16F883 I connected a LCD. Now I want to use the analog output of RB0 (AN12).
    I do not get the correct digital result on my screen? See below the code I use.
    With ANSELH and TRISB I first make the right zettings, then I read Adcin 12 and write this to AN12.
    However, the result is a too high digital number?
    It must be possible to use together a display and an analog input? Or not?
    Has anyone done this before?

    Code (text):
    While startbutton = 3
        Gosub timer
        ADCON0 = %01110011  'Channel 02 (AN0/AN3) as a/d selected (CHS2:CHS0), ADCS1&ADCS0 bit are selected as Fosc/8
        Adcin 4, an4  'read AN4 and write value to AN4
     
        If timer1 = 5 Then
        timer1 = 0
            ANSELH = %00010000
            TRISB = %00000001
            Adcin 12, an12  'read AN12 and write value to AN12
            ANSELH = %00000000
            TRISB = %00000000
        Endif
     
        Lcdcmdout LcdLine1Pos(1)  'write from first position
        Lcdout "C      v"  'write the word "Colt" and "volt" on the screen!
        Lcdcmdout LcdLine1Pos(5)  'write from position 5
        Lcdout #an4  'just to see on the screen what the digital number is!

        Lcdcmdout LcdLine2Pos(1)  'write from first position
        Lcdout "W      v"  'write the word "Warm" and "volt" on the screen!
        Lcdcmdout LcdLine2Pos(5)  'write from position 5
        Lcdout #an12  'just to see on the screen what the digital number is!

        While select_sw2 = 0
            startbutton = 0
            timer1 = 0
            Lcdcmdout LcdClear
            selectbutton = 4
            Gosub selectbutton4
        Wend

    WaitMs 100
    Wend
     
    Last edited: Jan 21, 2017
  2. Dr_Doggy

    Dr_Doggy Well-Known Member

    Joined:
    Aug 11, 2007
    Messages:
    1,715
    Likes:
    37
    Hi,
    does the lcd code work, does it display c&v ?
    a quick glance suggests that you are all over the place with the analog pins, also i think you have confused what ANSELH and ADCON0 do.
    Not sure how the %operator works ther nor have i ever heard of Adcin, but that may just be me!


    Here is function that reads analog pins nicely:

    Code (text):

    unsigned int read_analog(unsigned char chnl)
    {
        unsigned int ret= 0;
        ADCON0bits.ADON = 1;    //Turns on ADC module
        ADCON0bits.CHS = chnl; //Selects channel  
        ADCON0bits.GO = 1;   //Starts ADC conversion
        while (ADCON0bits.nDONE) continue;   //wait till ADC conversion is over  
        ret=((ADRESH<<8) + ADRESL); //Merging the MSB and LSB  
        ADCON0bits.ADON = 0;  
        return ret;
    }

     
    dont forget to set it up , here is example but you will want to modify it properly to your own settings:
    Code (text):

         // set pin direction
        TRISA = 0b11111111;    PORTA = 0b00000000;
        TRISB = 0b11111111;    PORTB = 0b00000000;
        TRISC = 0b11111111;    PORTC = 0b00000000;

        ANSEL = 0b11111111;       // select all analog pins to read
        CMCON0= 0b00000000;  // comparitors off
        ADCON1bits.ADCS  = 6;   //Selecting the clk division factor = FOSC/
        ADCON0bits.ADFM = 1;    //Result right justified
        ADCON0bits.VCFG = 0;  

     
     
  3. sagor1

    sagor1 Member

    Joined:
    Dec 11, 2014
    Messages:
    52
    Likes:
    2
    Silly question, but are AN4 and AN12 defined as words? If defined as bytes, you will get strange values from a 10 bit A/D reading.
    You don't show that part of the code. Also, one would assume RB0 is dedicated to reading analog input, so why switch it on and off over and over again? Just define it at the start of the code.
    If trying to use it as digital then analog at times, external circuits may cause unpredictable readings - not a wise idea.
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Winch

    Winch New Member

    Joined:
    Sep 5, 2014
    Messages:
    24
    Likes:
    0

    This is the code I use by declaring the variable. As you see I want to use 6 analog inputs.
    But the AN12 is the RB0 which is also used for the LCD.
    The fact that one time the ANSELH and TRISB is zet as input and later as an output is with the thought that I can read the analog input and write the value to "DIM an12 as Word".

    I'm actually assume that you could measure the analog input in a snapshot, and show the result on the LCD!
    P.S. AN1 up to AN4 are "port A" related in the 16F883.

    Code (text):
    Dim an0 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN0)
    Dim an1 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN1)
    Dim an2 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN2)
    Dim an3 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN3)
    Dim an4 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN4)
    Dim an12 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN12)
     
     
    Last edited: Jan 21, 2017
  6. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,011
    Likes:
    317
    Location:
    Brisbane Australia
    Your code looks fine but you may be getting spurious results due to the extra capacitance caused by the LCD. Try making the acquisition time longer.

    Mike.
     
  7. Winch

    Winch New Member

    Joined:
    Sep 5, 2014
    Messages:
    24
    Likes:
    0
    Thanks for your comments!

    Today, I first removed all the extra ballast out of the code.
    This gives a better overview!
    I try to make the acquisition time longer but it does not improve! I tried that with a simple 500 milliseconds! (see below)
    I am still convinced that it should be able to work, But just do not know where to look for the right answer?

    Both anaolg inputs have an equal height of DC voltage in the test, but the result will give an uneven number.
    AN4 behaves correctly, at 0 volt is the digital number also 0 and when the voltage rises, then the digital number also.
    AN12 starts with a high number it starts at 0 volts with the number 856 when the voltage rises, then the digital number rises also but not in the same ratio!

    In other words, it works but not in the correct proportions!

    Does anyone have a suggestion?

    Code (text):

    'DEVICE PIC16F883

    Define CONFIG1 = 0x23e4
    Define CONFIG2 = 0x3eff
    Define CLOCK_FREQUENCY = 8

    OSCCON = %01110101  'Oscillator control (datasheet page 66)

    Define LCD_BITS = 4
    Define LCD_DREG = PORTB
    Define LCD_DBIT = 0
    Define LCD_RSREG = PORTB
    Define LCD_RSBIT = 4
    Define LCD_EREG = PORTB
    Define LCD_EBIT = 5
    Define LCD_RWREG = PORTB
    Define LCD_RWBIT = 0

    AllDigital  'alle ports digital

    'port names
    Symbol led1 = PORTA.4  'control LED for microcontroller
    Symbol select_sw2 = PORTC.2  'pushbutton for function "Select"
    Symbol start_sw3 = PORTC.1  'pushbutton for function "Start"

    'declaring variable
    Dim an0 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN0)
    Dim an1 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN1)
    Dim an2 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN2)
    Dim an3 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN3)
    Dim an4 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN4)
    Dim an12 As Word  'voltage as variable "word (0 to 65535)"(here the measured analog value on input AN12)

    'declaring variable for the TIMER
    Dim var_timer As Byte  'variable "TIMER" value "As Byte"
    Dim timer_limite As Word  '"TIMER" limite "As Byte"
    Dim timer1 As Byte  'variable timer1 setting "As byte 0 to 255"

    OPTION_REG.7 = 0  'RBPU must be cleared for individual pull-up 'PORTB' pull-ups
    OPTION_REG.INTEDG = 0  'Interrupt on falling edge of GP2/INT pin
    OPTION_REG.T0CS = 0  'Internal instruction cycle clock (CLKOUT)
    OPTION_REG.T0SE = 0  'Increment on low-to-high transition on GP2/T0CKI pin
    OPTION_REG.PSA = 0  'Prescaler is assigned to the TIMER0 module
    OPTION_REG.PS2 = 1  'Set the prescaler
    OPTION_REG.PS1 = 1  'to increment TMR0
    OPTION_REG.PS0 = 0  'every 128th instruction cycle

    'A gate set to the desired value
    '76543210
    PORTA = %00000000  'make all ports "PORTA" low
    TRISA = %11101111  '1 = set for input RA5,RA3,RA2,RA1,RA0. 0 = set for output RA4,!
    ANSEL = %00011111  '1 = Analog input. AN0,AN1,AN2,AN3,AN4 are assigned as analog input.

    'B gate set to the desired value
    '76543210
    PORTB = %00000000  'make all ports "PORTB" low
    TRISB = %00000000  '0 = set for output / all ports are set for output!

    'C gate set To the desired value
    '76543210
    PORTC = %00000000  'make all ports "PORTC" low
    TRISC = %11111111  'port RC1 & RC2 (CCP1 & CCP2) are set for output

    'converts the analog input to the desired value
    '76543210
    ADCON0 = %01001011  'Channel 02 (AN0/AN3) as a/d selected (CHS2:CHS0), ADCS1&ADCS0 bit are selected as Fosc/8
    ADCON1 = %00000000  'configured as analog inputs (see datasheet page 103)

    'The INTCON register is a readable and writable register, which contains the various Enable And flag bits For TMR0 register overflow,
    'GPIO port change And external GP2 / int pin interrupts.
    INTCON.GIE = 1  'Enables all unmasked interrupts
    INTCON.T0IE = 1  'Enables the TMR0 interrupt (TMR0 Overflow Interrupt Enable bit)
    INTCON.T0IF = 1  'TMR0 register has overflowed (must be cleared in software)
    TMR0 = 0  'Clear TMR0 initially, (reset de timer0 module register)

    Lcdinit 0  'no cursor
    WaitMs 250

    led1 = 0  'PCB control LED green
    an0 = 0
    an1 = 0
    an2 = 0
    an3 = 0
    an4 = 0
    an12 = 0

    timer1 = 0  'set timer1 to 0

    var_timer = 0  'variable waarde van de timer is 0
    timer_limite = 12  'intern klok 8mhz/4 = 2mhz (2mhz/(128*128)) = 122 Hz pulse every 1 second

    main:  'endless loop

        Adcin 4, an4  'read AN4 from port-A and write value to "DIM AN4 AS WORD"
       
            ANSELH = %00010000  'Setting the ANSELH bit high wil make an analog input
            TRISB = %00000001  'Setting the TRISB high wil make it set as a analog input
            WaitMs 500
            Adcin 12, an12  'read AN12 from port-B and write value to "DIM AN12 AS WORD"
            ANSELH = %00000000  'setting the ANSELH bit low so it will be an digital I/O
            TRISB = %00000000  'Setting the TRISB bit low so it will be an output
           
        Lcdcmdout LcdLine1Pos(5)  'write from position 5
        Lcdout #an4  'just to see on the screen what the digital number is!

        Lcdcmdout LcdLine2Pos(5)  'write from position 5
        Lcdout #an12  'just to see on the screen what the digital number is!

    WaitMs 100

    Goto main
    End  'end program                                

    On Interrupt  'Interrupt timer
        Save System  'Save
            TMR0 = 128  'set "TMR0" on 0 (start counting from 128 to 255)
            var_timer = var_timer + 1  'increment var_timer
        INTCON.T0IF = 0  'clear Interrupt flag
    Resume  'jump back where it started              

    '*************************************************
    '* subroutin TIMER will increase the timer every second!
    '*************************************************
    timer:
    If var_timer > timer_limite Then  'when var_timer is greater than timer_limite (122) then....
            var_timer = 0  'set "var_timer" back to 0
            timer1 = timer1 + 1  'increase "timer1" by 1
    Endif

    Return                                            
     
     
  8. Dr_Doggy

    Dr_Doggy Well-Known Member

    Joined:
    Aug 11, 2007
    Messages:
    1,715
    Likes:
    37
    it sounds to me that maybe the additional circuitry on pin is pulling things up a bit ... maybe bad ground? .. r u using scope or meter? are you grounding meter at the pic? .. do you get same issues on adc12 if extra circuitry is removed?

    I used a equation like this to convert dynamic solar intensity from different panels to percent value for additional factoring(color shading specifically for me):
    float percent = (((float)(value - Min))/((float)(Max-Min)));
    RED = (unsigned char)((float)R * percent)
     
    Last edited: Jan 22, 2017
  9. Winch

    Winch New Member

    Joined:
    Sep 5, 2014
    Messages:
    24
    Likes:
    0
    It is an ordinary voltage divider at the input of the AN12. The intention is to read a 1-10 volt control!
     
  10. Dr_Doggy

    Dr_Doggy Well-Known Member

    Joined:
    Aug 11, 2007
    Messages:
    1,715
    Likes:
    37
    sry, it will work for you too, just define what your ADC MAX and MIN ranges are, value-- should be your adc value

    since your output range is 1-10, just change this line to:
    OutputRange = (unsigned char)((float)10 * percent)
     
  11. Winch

    Winch New Member

    Joined:
    Sep 5, 2014
    Messages:
    24
    Likes:
    0
    I'm afraid I can not follow your answer? Maybe I need more explanation?

    I'm trying to measure a 1-10 volt at the input AN12 which is also used for the LCD!
    Because in the PIC 16F883 is the analog AN12 also the digital I/O RB0.
    And I get the feeling that this is just not going to work together with that voltage divider!
     
  12. Dr_Doggy

    Dr_Doggy Well-Known Member

    Joined:
    Aug 11, 2007
    Messages:
    1,715
    Likes:
    37
    for the expression: float percent = (((float)(value - Min))/((float)(Max-Min)));
    calculation for percent is: % = value/max
    where value is a number between max and min
    max is the number to divide by and when min=max we get 100% or 1
    min is the true value for 0...
    but because the min value is >0 we need to subtract in our percent equation, but if we do that to numerator, then math rule is we need to do it to denominator hence:
    value -Min
    and
    max - min


    instead of using algebra expression , and to simplify description, you could also do it like this:
    if ((value> 100)& value < 200){OutputRange = 1;}
    if ((value> 200)& value < 300){OutputRange = 2;}
    if ((value> 300)& value < 400){OutputRange = 3;}
    if ((value> 400)& value < 500){OutputRange = 4;}
    ...
     
    Last edited: Jan 22, 2017
  13. sagor1

    sagor1 Member

    Joined:
    Dec 11, 2014
    Messages:
    52
    Likes:
    2
    Using the same pin for Digital out and Analog in can be set up according to the data sheet, but results can be unpredictable if the digital out is set high (5V). To quote the datasheet: (3.4.1)

    "The state of the ANSELH bits has no affect on digital
    output functions. A pin with TRIS clear and ANSELH
    set will still operate as a digital output, but the Input
    mode will be analog. This can cause unexpected
    behavior when executing read-modify-write
    instructions on the affected port."

    Also, perhaps check the weak pullups, turn them off. Finally, having a voltage divider on a digital out, which is then read as analog may cause some other issue with the digital out not working properly if the voltage divider is set high. If using high resistive values (100k), this may not be too big an issue. But, if using something like 5k resistors or less, it may be impacting other things. Hard to isolate digital out on a pin with a voltage input from another circuit unless you can switch them in and out.
    Maybe try with less TRIS changes, just set it as digital out, and use ANSELH to set it as analog input without changing TRIS, see what happens.

    As I see it, if digital out RB0 is high, the A/D will read the 5 volts if it overrides the input voltage divider network (sources up to 25mA). If digital out is low, it will sink the incoming voltage source down to a transistor junction level, about 0.6 to 0.8 volts, which will be read by the A/D input. Switching to input mode may give that chance for it to become high impedance, allowing you to read the actual voltage. Not sure what the transition time is for all the circuits connected to that pin.

    I don't think you have to keep changing ANSELH, leave it as Analog input - digital out will still work when TRIS is "0". Look at figure 3-9 in datasheet, you can see the A/D input is not impacted by other settings, the pin is fed directly to the A/D converter. Only impact would be a digital "output". Good luck...
     
    Last edited: Jan 22, 2017
  14. mauried

    mauried New Member

    Joined:
    Nov 16, 2016
    Messages:
    3
    Likes:
    1
    Theres nothing wrong with your code, but the idea wont work.
    When a pin is defined as analog in , it becomes very hi impedance, so that it can measure whatever voltage there is that you are feeding in.
    If you have a LCD connected to the analog in pin, then the voltage on that pin will become undefined, as the LCD will try and sink current into that pin as the LCD is looking for an output pin which typically
    consists of a totem pole output which either will pull up the pin to VCC or pull it down to gnd.
    You need to physically disconnect the LCD from RB0 when you have it configured as an input.
     
  15. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,011
    Likes:
    317
    Location:
    Brisbane Australia
    I see you have the week pullups turned on. This will skew your results towards a higher number. Try turning them off whilst reading. OPTION_REG.7 = 1

    Edit, the warning in the datasheet refers to analogue pins always reading 0 when read as digital. This is not your problem.

    Mike.
     
  16. sagor1

    sagor1 Member

    Joined:
    Dec 11, 2014
    Messages:
    52
    Likes:
    2
    Mauried is basically correct. There is a slim chance the input to the LCD "could" be high impedance as well (CMOS input maybe) or maybe not, but that still complicates things. Also, if there is any other circuits externally or internally with the LCD display itself (such as pullups or pulldowns), that would affect the voltage on the RB0 line. Without a total circuit diagram and LCD specs, hard to say how much error there would be. You will not get reliable readings unless you can ensure the data line to the LCD is not affecting the voltage on the RB0 line (measure it with a good digital voltmeter and see, without the voltage divider for A/D connected)
     
  17. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,011
    Likes:
    317
    Location:
    Brisbane Australia
    From experience, I have never had an LCD with inputs that are not very high impedance. The problem (as stated above) is most likely the week pullups. These are typically 20k and so, if the resistive divider is not much lower impedance then the input (B0) will be skewed towards 5V.

    Mike.
     
  18. spec

    spec Well-Known Member Most Helpful Member

    Joined:
    Oct 27, 2015
    Messages:
    5,828
    Likes:
    709
    Location:
    Somerset UK GMT
    You may be suffering from two problems as described above;
    (1) pull ups enabled
    (2) input to display affecting the MCU pin.

    (1) is easy to fix as already stated- just disable active pull ups in the MCU configuration data base.
    (2) connect a CMOS logic (4000 series) gate between the MCU I/O pin and and the input pin on the display. If the I/O pin of the MCU will ever be open circuit, connect a 1M Ohm resistor from the MCU I/O pin to 0V (ground).

    spec
     

Share This Page