Continue to Site

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.

  • 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.

Question Regarding PIC16F88 ADC Data Manipulation in Assembly Language

Status
Not open for further replies.

Steve311

Member
Hi All; I'm writing code in assembly language working with a PIC16F88 and its ADC. I have two analog inputs which are stored in working registers once the ADC acquisition is complete. What is the best approach to determine if these values are within a specified range? This would be equivalent to an IF ELSE statement in C. For Example, I have two variables X and Y, and if I wanted to check to see if 1V < X < 2V and if 2 < Y < 3V, and if both statements are true, then output a logic 1. And if either of the two statements are false, then output a logic 0.

---That is the overall goal I have in mind. I feel that with assembly, doing conditional statements like this is difficult, but not impossible and it will just take many loops of bit testing and such....

If anyone has any ideas that they think could be helpful to me any suggestions would be greatly appreciated! Thanks in Advance....Steve
 
This should help you I wrote it about two year ago for a 16f648a
Code:
    ;;;;;By be80be ;;;;;;;;;;;;;;;
    list      p=16f684      ; list directive to define processor
       #include   <P16F684.inc>      ; processor specific variable definitions
       errorlevel -302 ; Turn off banking message
                                ; known tested (good) code

       __CONFIG    _CP_OFF & _CPD_OFF & _BOD_OFF & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _FCMEN_OFF &

    _IESO_OFF
       


       CBLOCK       0x020
       endc
       #define _1VOLT 0x33
       #define _2VOLT 0x66
       #define _2_5VOLT 0x7F
       #define _3VOLT 0x99
       #define _4VOLT 0xCC
       #define _5VOLT 0xff




       ORG         0x000      ; processor reset vector
         goto      init      ; go to beginning of program


       ORG         0x004       ; interrupt vector location

    init:
         bsf       STATUS,RP0     ; select Register Page 1
         movlw     0xFF
         movwf     TRISA          ; Make PortA all input
         clrf      TRISC          ; Make PortC all output
         movlw     0x10           ; A2D Clock Fosc/8
         movwf     ADCON1
         bcf       STATUS,RP0     ; back to Register Page 0

         bcf       STATUS,RP0     ; address Register Page 2
         bsf       STATUS,RP1     
         movlw     0xFF           ; we want all Port A pins Analog
         movwf     ANSEL
         bcf       STATUS,RP0     ; address Register Page 0
         bcf       STATUS,RP1
         clrf      ADCON0
         movlw     0x01
         movwf     ADCON0         ; configure A2D for Channel 0
    MainLoop:
         call   adcdelay        ;delay to charge cap
         bsf       ADCON0,GO      ; start conversion
         btfss     ADCON0,GO      ; this bit will change to zero when the conversion is complete
         goto      $-1
       
        movf     ADRESH,w       ; Copy the display to the LEDs
        movlw    _1VOLT
        subwf    ADRESH, w
       BNC    LessThan1V                ; Branch if less than 1V


        movlw    _2VOLT
        subwf    ADRESH, w
       BNC    LessThan2V                ; Branch if Between 1V and 2V
       

        movlw    _2_5VOLT
        subwf    ADRESH, w
       BNC    LessThan2_5V             ; Branch if Between 2V and 2.5V


        movlw    _3VOLT
        subwf    ADRESH, w
       BNC    LessThan3V                ; Branch if Between 2.5V and  3V


        movlw    _4VOLT
        subwf    ADRESH, w
       BNC    LessThan4V                ; Branch if Between 3V and 4V


        movlw    _5VOLT
        subwf    ADRESH, w
       BNC    LessThan5V                ; Branch if Between 3V and 4V
        goto      MainLoop
    LessThan1V:
       movlw   b'00000001'
       movwf   PORTC
       goto   MainLoop

    LessThan2V
       movlw   b'00000010'
       movwf   PORTC
       goto   MainLoop

    LessThan2_5V
       movlw   b'00000100'
       movwf   PORTC
       goto   MainLoop

    LessThan3V
        movlw   b'00001000'
       movwf   PORTC
       goto   MainLoop

    LessThan4V
       movlw   b'00010000'
       movwf   PORTC
       goto   MainLoop

    LessThan5V
       movlw   b'00100000'
       movwf   PORTC
       goto   MainLoop

    adcdelay:
        nop                 ;1 cycle

        return                 ;4 cycles (including call)
       
         end

And you may want to use some of this it's the same code but Mike McLaren added code that give a mean value so it could be used as led volt meter
Code:
;
    ;  be80be's example ADC program for 16F684
    ;
    ;
            list    p=16f684        ; list directive to define processor
            #include <P16F684.inc>
            errorlevel -302         ; Turn off banking message
            radix   dec

            __CONFIG _BOD_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF


            CBLOCK  0x020
    shadow
    newadc
    oldadc
            endc

    v5.0    equ     50000/196       ; adc value for 5.0v
    v4.0    equ     40000/196       ; adc value for 4.0v
    v3.0    equ     30000/196       ; adc value for 3.0v
    v2.5    equ     25000/196       ; adc value for 2.5v
    v2.0    equ     20000/196       ; adc value for 2.0v
    v1.0    equ     10000/196       ; adc value for 1.0v

            org     0x000           ; reset vector
    init
            bsf     STATUS,RP0      ; select Register Page 1
            movlw   0xFF            ;
            movwf   TRISA           ; Make PortA all input
            clrf    TRISC           ; Make PortC all output
            movlw   0x10            ; A2D Clock Fosc/8
            movwf   ADCON1          ;
            bcf     STATUS,RP0      ; back to Register Page 0
            bsf     STATUS,RP1      ; select Register Page 2
            movlw   0xFF            ; we want all Port A pins Analog
            movwf   ANSEL           ;
            bcf     STATUS,RP1      ; back to Register Page 0
            clrf    ADCON0          ;
            movlw   0x01            ;
            movwf   ADCON0          ; configure A2D for Channel 0
    loop
            call    adcdelay        ; delay to charge cap
            bsf     ADCON0,GO       ; start adc conversion
            btfss   ADCON0,GO       ; complete? yes, skip, else
            goto    $-1             ; branch (wait for complete)
            movf    ADRESH,W        ; new adc reading, 0..255
    ;
    ;  get absolute "delta" between 'new' and 'old' ADC readings
    ;
            movwf   newadc          ; W = new reading, 0..255
            subwf   oldadc,W        ; subtract from 'oldadc'
            skpc                    ; borrow? no, skip, else
            sublw   0               ; twos complement WREG
    ;
    ;  use 'newadc' if ∆ adc >= 2 points, else use 'oldadc'
    ;
            sublw   2               ; C=0 if ∆ adc >= 2 points
            movf    oldadc,W        ; use 'oldadc' if C=1
            skpc                    ; C=1? yes, skip, else
            movf    newadc,W        ; use 'newadc' if C=0
            movwf   oldadc          ; update 'oldadc' var
    ;
    ;  adc 'window' compare code
    ;
            clrf    shadow          ; clear LED shadow reg'
            addlw   -v5.0           ; C = adcval >= 255 (5.0v)
            rlf     shadow,F        ; move C into 'shadow'
            btfss   shadow,0        ; borrow? no, skip, else
            addlw   v5.0            ; undo the subtract

            addlw   -v4.0           ; C = adcval >= 204 (4.0v)
            rlf     shadow,F        ; move C into 'shadow'
            btfss   shadow,0        ; borrow? no, skip, else
            addlw   v4.0            ; undo the subtract

            addlw   -v3.0           ; C = adcval >= 153 (3.0v)
            rlf     shadow,F        ; move C into 'shadow'
            btfss   shadow,0        ; borrow? no, skip, else
            addlw   v3.0            ; undo the subtract

            addlw   -v2.5           ; C = adcval >= 127 (2.5v)
            rlf     shadow,F        ; move C into 'shadow'
            btfss   shadow,0        ; borrow? no, skip, else
            addlw   v2.5            ; undo the subtract

            addlw   -v2.0           ; C = adcval >= 102 (2.0v)
            rlf     shadow,F        ; move C into 'shadow'
            btfss   shadow,0        ; borrow? no, skip, else
            addlw   v2.0            ; undo the subtract

            addlw   -v1.0           ; C = adcval >= 51  (1.0v)
            rlf     shadow,W        ;
            movwf   PORTC           ; update LED display
            goto    loop            ; loop

    adcdelay
            nop                     ; 1 cycle
            return                  ; 5 cycles (including call)

            end
 
Last edited:
hi Steve,
This 16F88 program uses AN0/1/2 input levels to control 3 LED's on PORTB.0/1/2

It should help with 'compare' problem.
 

Attachments

  • AAesp02.gif
    AAesp02.gif
    40.1 KB · Views: 399
  • ADC_lite_darkV2a.asm
    3.1 KB · Views: 210
HI be80b Thanks alot for your response. I see the logic within your code and I like your method. Regarding your code, what is the precise function of "bnc"....i understand its a branch but I am unaware of where to find documentation on this?
Thanks once again, Steve
 
I can't take all the gory ericgibbs showed me that about two years ago

bnc-jpg.46229
 

Attachments

  • BNC.JPG
    BNC.JPG
    24.5 KB · Views: 693
Thanks alot for the help Burt. I was able to successfully read 1 analog input and determine if it fell within the range of 0 < X < 1 < X < 2 < X < 3 < X < 4 < X < 5.

However now that I want to incorporate a second ADC input with its own values....something yet again went wrong with my code and no I cant get it to work. I put another post on this morning with a new version of my code if you're interested. Thanks again for the help so far!! I really appreciate it.

Regards,
Steve
 
Hi Eric; Thanks for your help. I was able to input one analog value and determine if it was within a specified range, then have a corresponding output. Now, I am trying to incorporate a second analog input. And for example if 2 < X < 3 and 4 < Y < 4.5 then the output pin (rb1) should have a logic high sent to it for a short duration (long enough to measure with a DMM). And if either of the above statements are false, then the output pin (rb1) should toggle between logic high and logic low.

I made a new thread this morning with a new version of my codeattached . I cant seem to get it to work. I get 0 errors using MPLAB sim and it seems to run fine. ANy suggestions if you don't mind taking a look for me? Thanks again in advance, Steve
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top