Voltage Measurement with PIC16F883

Discussion in 'Embedded Systems and Microcontrollers' started by Nomel, May 5, 2010.

  1. Nomel

    Thread Starter New Member

    May 5, 2010
    2
    0
    Hello everyone,

    I am currently working on a little project here, and it's becoming rather frustrating at the moment. The project is an adjustable power supply with an LCD showing the Voltage.
    After preparing the parts for the power supply and the supply for the PIC+Display, i started to work on the measurements. I'm using a PIC16F883 together with a 10 Character LC-Display. I worked my way through the datasheet and started to experiment with the PIC's ADC. I started out small - measuring 0..5 V and displaying it with 10 LED's - and worked my way up from there. I got it to function with the LCD after that.
    Currently I set up a Voltage divider, so that I can measure up to 40 V.
    This is where it get's problematic. The LCD shows everything just fine, except the ten's digit. I'm measuring 15 Volts from a Laptop power supply and the reading is 05,xxx. I also measured a lead-acid Battery with 11.1xx V and the display is showing 01,1. Same thing with 24 V: 04,xxx. When i hook up a little rechargeable battery with 1.29 V, it reads 01,250 V. (With another ac-adapter (3.3V) I'm getting 03,2xx).

    A short review about my code-logic:
    First the ADC result is multiplied with 40 (*5*8, because of the scaling)
    then the binary number in mV is converted to BCD-code by
    -first subtracting 10000 from the result as often as possible (then I count the subtractions and that's my first digit)
    -same thing with 1000 for the rest..
    -ame thing with 100 for the rest..
    -same thing with 10 for the rest..
    -and the rest is the last digit
    -afterwards, the value 30h is added to each digit and then sent to the LCD

    Here's my code: (I'm using MPLAB btw)

    Code ( (Unknown Language)):
    1.  
    2. ; Display for Voltage Measurements
    3.  
    4. ;-------------------------------------------
    5. ;   PORTC:  0----E
    6. ;           1----R/W
    7. ;           2----R/S
    8. ;   PORTB:  RB0-RB7 ---- D0-D7
    9. ;   PORTA   1--ADC
    10. ;--------------------------------------------
    11.  
    12. list        p=16f883
    13.             #include    <P16F883.INC>
    14.  
    15.             __CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_ON & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO
    16.             __CONFIG    _CONFIG2, _WRT_OFF & _BOR21V
    17.  
    18.             org     0x00
    19.  
    20.             loops   equ 0x2C
    21.             loops2  equ 0x2D
    22.             loops3  equ 0x2E
    23.  
    24.             xw0     equ 0x22    ;
    25.             xw1     equ 0x23    ;
    26.             f0      equ 0x24    ;
    27.             f1      equ 0x25    ;
    28.             counter equ 0x26    ;
    29.             Fehler  equ 0x27    ;
    30.             SZT     equ 0x2C    ;
    31.             ST      equ 0x28    ;
    32.             SZ      equ 0x29    ;
    33.             SH      equ 0x2A    ;
    34.             SE      equ 0x2B    ;
    35. [...]
    36.  
    37.  
    38. ; right justify
    39.             BANKSEL ADCON1
    40.             bsf     ADCON1, 7
    41.             bcf     ADCON1, 5
    42.             bcf     ADCON1, 4
    43.             bcf     STATUS, 5
    44.  
    45.             BANKSEL ANSEL
    46.             BSF     ANSEL, 1        ;Set RA0 to analog
    47. ; Select Channel AN1
    48.             BANKSEL ADCON0             
    49.             bcf     ADCON0, 5       ; ADCHS3=0
    50.             bcf     ADCON0, 4       ; ADCHS2=0
    51.             bcf     ADCON0, 3       ; ADCHS1=0     
    52.             bsf     ADCON0, 2       ; ADCHS0=0 
    53. ; ADC Frequency, turn on ADC
    54.             bsf     ADCON0, 7
    55.             bcf     ADCON0, 6
    56.             bsf     ADCON0, 0       ; ADC on
    57.            
    58. ; start a conversion
    59. Main
    60.             clrf    f0
    61.             clrf    f1
    62.             clrf    xw0
    63.             clrf    xw1
    64.  
    65.             BANKSEL ADCON0
    66.             bsf     ADCON0, 1   ; start
    67.            
    68.             movlw   D'10'       ; wait a bit
    69.             movwf   loops  
    70.             call    WAIT
    71. cl
    72.             btfsc   ADCON0, 1   ; done?
    73.             goto    cl          ; no, go back
    74.            
    75.             BANKSEL ADRESH
    76.             movfw   ADRESH
    77.             bcf     STATUS, 5
    78.             movwf   f1
    79.  
    80.             BANKSEL ADRESL
    81.             movfw   ADRESL
    82.             bcf     STATUS, 5
    83.             movwf   f0
    84.  
    85.             ;call   x8          ; result x 8
    86.             call    mV          ;
    87.             call    B2D         ;
    88.             call    output     
    89.  
    90.             goto    Main
    91. [...]
    92.  
    93. ;*********************************************************************
    94. ;16 bit Addition,
    95. Add16                           ; 16-bit add: f := f + xw
    96.          movf    xw0,W           ; xw0 nach W
    97.          addwf   f0,F            ; f0 := f0 + xw0
    98.  
    99.          movf    xw1,W           ; xw1 nach W
    100.          btfsc   STATUS,C        ; fall ein Überlauf auftrat:
    101.          incfsz  xw1,W           ;   xw1+1 nach W
    102.          addwf   f1,F            ; f1 := f1 + xw1
    103.  
    104.          return                  ; fertig
    105.  
    106.  
    107. ;*****************************************************
    108. ; 16 Bit Subtraction,
    109. Sub16                           ; 16 bit f:=f-xw
    110.          clrf    Fehler          ; extraflags löschen
    111.  
    112.          movf    xw0, w          ; f0:=f0-xw0
    113.          subwf   f0, f
    114.  
    115.          btfsc   STATUS,C
    116.          goto    Sub16a
    117.          movlw   0x01            ; borgen von f1
    118.          subwf   f1, f
    119.  
    120.          btfss   STATUS,C
    121.          bsf     Fehler, C       ; Unterlauf
    122.  
    123. Sub16a
    124.          movf    xw1,w           ; f1:=f1-xw1
    125.          subwf   f1    ,f
    126.  
    127.          btfss   STATUS,C
    128.          bsf     Fehler, C       ; Unterlauf
    129.  
    130.          bcf     STATUS, C       ; C-Flag invertieren
    131.          btfsc   Fehler, C
    132.          bsf     STATUS, C
    133.          return
    134.  
    135.  
    136. ;*****************************************************
    137. ; Division durch 2 wird w-mal ausgeführt
    138. ; die zu dividierende Zahl steht in xw
    139. Div2
    140.          movwf   counter         ; Anzahl der Divisionen speichern
    141. Div2a                           ; 16 bit xw:=xw/2
    142.          bcf     STATUS, C       ; carry löschen
    143.          rrf     xw1, f
    144.          rrf     xw0, f
    145.  
    146.          decfsz  counter, f         ; fertig?
    147.          goto    Div2a           ; nein: noch mal
    148.  return
    149. ;*****************************************************
    150. ; Wandlung des ADC-Wert in Millivolt (binär)
    151. ; Der ADC-Wert steht in f1,f0
    152. ; Ergebnis steht in f1,f0
    153. mV
    154.     ;Multiply the result with 8 (Voltage Divider)
    155.     movfw   f0
    156.     movwf   xw0
    157.     movfw   f1
    158.     movwf   xw1
    159.     call    Add16       ; f := 2xADC
    160.     call    Add16       ; f := 3xADC
    161.     call    Add16       ; f := 4xADC
    162.     call    Add16       ; f := 5xADC
    163.     call    Add16       ; f := 6xADC
    164.     call    Add16       ; f := 7xADC
    165.     call    Add16       ; f := 8xADC
    166.  
    167.     ; multiplication with 5
    168.     movfw   f0
    169.     movwf   xw0
    170.     movfw   f1
    171.     movwf   xw1
    172.     call    Add16       ; f := 2xADC
    173.     call    Add16       ; f := 3xADC
    174.     call    Add16       ; f := 4xADC
    175.     call    Add16       ; f := 5xADC
    176.  
    177.     ; ADC * 5 to xw
    178.     movfw   f0
    179.     movwf   xw0
    180.     movfw   f1
    181.     movwf   xw1     ; xw := 5xADC
    182.  
    183.     ; xw durch 64 dividieren (6 mal durch 2)
    184.     ; dann ist xw = 5xADC/64
    185.     movlw   6
    186.     call    Div2
    187.     call    Sub16       ; f := 5xADC - 5xADC/64
    188.  
    189.     ; xw auf 5xADC/128 verringern
    190.     movlw   1
    191.     call    Div2
    192.     call    Sub16       ; f := 5xADC - 5xADC/64 - 5xADC/128
    193.     return          ; fertig
    194.  
    195.  
    196. ;*****************************************************
    197. ;Converting the Binary to BCD: STZ, St, SH, ST, SZ, SE
    198. B2D
    199.     ; Test auf Zehntausender 10000d = 0x2710
    200.     movlw   27h
    201.     movwf   xw1
    202.     movlw   10h
    203.     movwf   xw0
    204.     call    B2Da
    205.     movwf   SZT
    206.     ; Test auf tausender 1000d = 0x03E8
    207.     movlw   0x03
    208.     movwf   xw1
    209.     movlw   0xE8
    210.     movwf   xw0
    211.     call    B2Da
    212.     movwf   ST
    213.     ; Test auf hunderter 100d = 0x0064
    214.     clrf    xw1
    215.     movlw   0x64
    216.     movwf   xw0
    217.     call    B2Da
    218.     movwf   SH
    219.     ; Test auf zehner 10d = 0x000A
    220.     clrf    xw1
    221.     movlw   0x0A
    222.     movwf   xw0
    223.     call    B2Da
    224.     movwf   SZ
    225.     movfw   f0
    226.     movwf   SE
    227.     return
    228.  
    229. B2Da
    230.     clrf    counter
    231. B2Sb   
    232.     incf    counter, f  ; wie oft abgezogen?
    233.     call    Sub16       ; f:=f-xw  
    234.     btfss   STATUS, C   ; zu oft abgezogen?
    235.     goto    B2Sb        ; nein: noch einmal
    236.     call    Add16       ; f:=f+xw
    237.     decf    counter, w  ; weil immer 1 zuviel gezählt wird
    238. return
    239.  
    240. [...]
    241.  
    242.  
    Obviously I didn't include all of the code, I tried to narrow it down to the important parts (sorry if some comments are in German)

    I can't seem to find my mistake, I've been at this for quite some time now, and I just don't see where I'm going wrong. So any help would be truly appreciated.

    Thank you in advance for taking a look at this.

    If more code/schematics/information is needed, I will gladly provide it.

    Thomas
     
  2. rjenkins

    AAC Fanatic!

    Nov 6, 2005
    1,015
    69
    I'd work through it by substituting fixed values for the ADC output and stepping through the code in MPLab.

    You can also set breakponts so you don't have to step through every instruction.

    You can check the memory locations and see if the results match what you expect for various input values.
     
    Nomel likes this.
  3. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    There is a 16bit to 5 digit BCD converter in AN526 from the microchip site if that helps.
     
  4. Nomel

    Thread Starter New Member

    May 5, 2010
    2
    0
    Well, I finally figured out how to use the Simulator in MPLAB ( at least a little) and after stepping through the code for hours I noticed that the first digit is overwritten before it is sent to the display..
    So I glanced at my variable declarations.. and voila
    there was the problem:

    Code ( (Unknown Language)):
    1.  
    2. ; Display for Voltage Measurements
    3.  
    4. ;-------------------------------------------
    5. ;   PORTC:  0----E
    6. ;           1----R/W
    7. ;           2----R/S
    8. ;   PORTB:  RB0-RB7 ---- D0-D7
    9. ;   PORTA   1--ADC
    10. ;--------------------------------------------
    11.  
    12. list        p=16f883
    13.             #include    <P16F883.INC>
    14.  
    15.             __CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_ON & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO
    16.             __CONFIG    _CONFIG2, _WRT_OFF & _BOR21V
    17.  
    18.             org     0x00
    19.  
    20.             [COLOR="Red"]loops  equ 0x2C[/COLOR]
    21.             loops2  equ 0x2D
    22.             loops3  equ 0x2E
    23.  
    24.             xw0     equ 0x22    ;
    25.             xw1     equ 0x23    ;
    26.             f0      equ 0x24    ;
    27.             f1      equ 0x25    ;
    28.             counter equ 0x26    ;
    29.             Fehler  equ 0x27    ;
    30.             [COLOR="red"]SZT        equ 0x2C[/COLOR]    ;
    31.             ST      equ 0x28    ;
    32.             SZ      equ 0x29    ;
    33.             SH      equ 0x2A    ;
    34.             SE      equ 0x2B    ;
    35. [...]
    36.  
    Soo thanks, worked like a charm.. the Simulator is really powerful. I should've started using it earlier

    @Markd77:
    I checked out microchip's site and found some things about the AN256. That's pretty neat resource ( but too much for me to go through for today :D )
     
  5. rjenkins

    AAC Fanatic!

    Nov 6, 2005
    1,015
    69
    Hi,

    happy to hear you got it going!
     
Loading...