Adapting Assembly Code for 16f917

Discussion in 'Homework Help' started by JML89, Dec 7, 2012.

  1. JML89

    Thread Starter New Member

    Dec 7, 2012
    9
    0
    Hey, I'm really new to this programming stuff and I have been asked to adapt the code below. It currently takes potentiometer values and counts up in binary with the LEDs between 0 and 5V over all 8 LEDs. However, I would like it to just count up sequentially with the LEDs using the first 5 LEDs. so for 1 volt, 1 LED is on, 2 volts 2 LEDs etc.

    This is used in conjunction with a PIC demo Board.

    Can anyone help please?

    This is what I have:

    list p=16f917 ; list directive to define processor
    #include <p16f917.inc> ; processor specific variable definitions

    ;------------------------------------------------------------------------------
    ;
    ; CONFIGURATION WORD SETUP
    ;
    ; The 'CONFIG' directive is used to embed the configuration word within the
    ; .asm file. The lables following the directive are located in the respective
    ; .inc file. See the data sheet for additional information on configuration
    ; word settings.
    ;
    ;------------------------------------------------------------------------------

    __CONFIG _FCMEN_ON & _IESO_ON & _CP_OFF & _WDT_OFF & _BOD_OFF & _MCLRE_ON & _PWRTE_ON & _INTRC_OSC_NOCLKOUT

    ;------------------------------------------------------------------------------
    ; VARIABLE DEFINITIONS
    ;
    ; Available Data Memory divided into Bank 0,1,2, and 3. Each Bank contains
    ; Special Function Registers, General Purpose Registers, and Access RAM
    ;
    ;------------------------------------------------------------------------------

    CBLOCK 0x20 ; Define GPR variable register locations
    MYVAR1 ; User variables allocated contiguously
    MYVAR2 ;
    MYVAR3 ;
    RESULTHI;
    RESULTLO;
    ENDC

    W_TEMP EQU 0x7D ; w register for context saving (ACCESS)
    STATUS_TEMP EQU 0x7E ; status used for context saving (ACCESS)
    PCLATH_TEMP EQU 0x7F ; context saving of PC (ACCESS)

    ;------------------------------------------------------------------------------
    ; EEPROM INITIALIZATION
    ;
    ; The 16F917 has 256 bytes of non-volatile EEPROM, starting at address 0x2100
    ;
    ;------------------------------------------------------------------------------

    DATAEE ORG 0x2100
    DE "MCHP" ; Place 'M' 'C' 'H' 'P' at address 0,1,2,3

    ;------------------------------------------------------------------------------
    ; RESET VECTOR
    ;------------------------------------------------------------------------------

    ORG 0x0000 ; processor reset vector
    PAGESEL START
    GOTO START ; When using debug header, first inst.
    ; may be passed over by ICD2.

    ;------------------------------------------------------------------------------
    ; INTERRUPT SERVICE ROUTINE
    ;------------------------------------------------------------------------------

    ORG 0x0004
    ; Interrupt context saving
    MOVWF W_TEMP ; save off current W register contents
    MOVF STATUS,W ; move status register into W register
    MOVWF STATUS_TEMP ; save off contents of STATUS register
    MOVF PCLATH,W ; move pclath register into w register
    MOVWF PCLATH_TEMP ; save off contents of PCLATH register

    ;------------------------------------------------------------------------------
    ; USER INTERRUPT SERVICE ROUTINE GOES HERE
    ;------------------------------------------------------------------------------

    ; Interrupt context restoring
    MOVF PCLATH_TEMP,W ; retrieve copy of PCLATH register
    MOVWF PCLATH ; restore pre-isr PCLATH register contents
    MOVF STATUS_TEMP,W ; retrieve copy of STATUS register
    MOVWF STATUS ; restore pre-isr STATUS register contents
    SWAPF W_TEMP,F
    SWAPF W_TEMP,W ; restore pre-isr W register contents
    RETFIE ; return from interrupt

    ;------------------------------------------------------------------------------
    ; MAIN PROGRAM
    ;------------------------------------------------------------------------------


    ;**************************************************************************************************
    ;Connect a potentiometer to RA0, convert the analogue signal into digital value, and send it to PORTB,
    ;by adjusting potentiometer, LEDs that are driven by the digital value should flash.
    ;**************************************************************************************************

    START

    bsf STATUS, RP0 ;select bank 1
    movlw 0xf0 ;set PortB <7:4> 4 inputs, <3:0> 4 outputs. 11110000--> w--> TRISB
    movwf TRISB

    bcf STATUS, RP0 ;select bank 0
    clrf PORTB ;set all outputs low

    ;********PORTA, A/D****************
    bsf STATUS, RP0 ;choose bank1
    bcf STATUS, RP1

    movlw 0x07 ;PORTA Comparator off
    movwf CMCON0

    movlw 0x50 ;A/D clock Fosc/16
    movwf ADCON1
    bsf TRISA, 0 ;Set RA0 to input
    bsf ANSEL, 0 ;Set RA0 to analog

    bcf STATUS, RP0 ;Bank 0
    movlw 0x01 ;result left shifted, Vdd Vref, AN0
    movwf ADCON0
    ;

    Loop

    ;----------check A/D results------------------
    banksel ADCON0
    bsf ADCON0, GO ;Start conversion
    btfsc ADCON0, GO ;Is conversion done?
    goto $-1 ;No, test again
    movf ADRESH, W ;Read upper 2 bits
    movwf RESULTHI
    movwf PORTB ;send A/D result high 8 bits to PORTB (LEDs change with analogue signal)

    bsf STATUS,RP0 ;Bank 1
    movf ADRESL,W ;Read lower 8 bits
    movwf RESULTLO

    goto Loop

    end
     
  2. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    An easy way would be to subtract 51 (256/5) from the result. If there is a carry then the result was 0-1V. Repeat as necessary.
    It might be better to have the range 0-0.5V give the result 0, 0.5-1.5V give the result 1, etc.
    If you want to do that, just subtract 26 as the first step.
     
  3. atferrari

    AAC Fanatic!

    Jan 6, 2004
    2,648
    763
    Since you say "adapting", is it code written for a different micro or what?

    If it is for another micro, please say which one.
     
  4. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    Get the 16F5x datasheet, it is only 50 pages to read.

    The chip you have here has some minor differences, but the basics are all included in the 16F5x sheet.

    Myself I found it difficult to learn PIC RISC and at first I was shocked about how primitive the instruction set is. Then I used assembler for a few years, but recently moved away from that.

    If you find it easy to learn the PIC RISC assembler, do it, otherwise don't spend time with it, and use C language.
     
    Last edited: Dec 7, 2012
  5. JML89

    Thread Starter New Member

    Dec 7, 2012
    9
    0
    Unfortunately the parameters of the assignment insist upon the use of this particular chip and the use of assembly.
    I have to learn some C for another project but that's a different story.

    By adapting I just meant changing it to do a slightly different job sorry for not being clear.

    I think I will try to do use the subtraction method as that makes sense to me. I'm afraid though that I don't really know what you mean by the carry. Do you mean that when the value goes negative it will simply not light any LEDs?
    So as I need to check this step by step, instead of taking it to PORT B, I should keep the value in the working folder and subtract the fixed value and then send the results to PORT B.

    Cheers for the help guys
     
  6. takao21203

    Distinguished Member

    Apr 28, 2012
    3,577
    463
    What I have often done in PIC RISC to avoid arithmetic was to use decoding tables.

    Make one table from 0 to 0xff and use a stepping 0xff divided to the number of LEDs you have.

    Then you increment the index from the first entry, and each time subtract the table result from your AD result. If it becomes larger (called GT in 8086 assembler), then you break the loop. In PIC RISC you have to test the right flag from the status register.

    You use the obtained index value for another table, which you build from the LED patters you want.

    It is some kind of sequential evalution, but it only takes a milisecond or so. For just 5 values to skip through it should not be a problem at all.

    I hope you can follow my explanation. I could write the assembler code, but have not used assembler for a while.

    You also somehow have to normalize the AD result to 8bit. If you want to use 10bit resolution, your assembler code will increase a lot in size.

    I also don't know maybe you have to subtract 1 from the LED pattern index, you'd have to test that.
     
  7. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    There is bit in the STATUS register called Carry. If the result of a subtraction is positive, this bit is 1.
    I'd suggest:
    subtract 51 from RESULTHI
    if Carry is 0 then light 1 LED and skip the rest of the tests

    subtract 51 from RESULTHI
    if Carry is 0 then light 2 LEDs and skip the rest of the tests

    subtract 51 from RESULTHI
    if Carry is 0 then light 3 LEDs and skip the rest of the tests

    subtract 51 from RESULTHI
    if Carry is 0 then light 4 LEDs

    otherwise light 5 LEDs

    This method wouldn't be great for a large number of states but for just a few it is about as good as any other method.
    In your code the comments
    ;Read upper 2 bits
    and
    ;Read lower 8 bits
    are wrong if the ADC result is left justified. Also there is not much point reading ADRESL if you aren't going to use it.
     
  8. JML89

    Thread Starter New Member

    Dec 7, 2012
    9
    0
    Thanks for the heads up on the removed parts. I will give the Code a go and come back to you for feedback if that's ok? Am I right in thinking I can do this all within that one loop?
     
  9. JML89

    Thread Starter New Member

    Dec 7, 2012
    9
    0
    I have this in the Loop now, is it along the right lines? I'm puzzled over making it skip conditionally having (I think) got it to light the LEDs conditionally.

    Loop

    ;----------check A/D results------------------
    banksel ADCON0
    bsf ADCON0, GO ;Start conversion
    btfsc ADCON0, GO ;Is conversion done?
    goto $-1 ;No, test again
    movf ADRESH, W
    movwf RESULTHI

    movlw d"51"
    subwf RESULTHI ;take 51 from RESULTHI
    btfss STATUS, 1 ; Check STATUS bit 1
    movlw b "00000001"
    movwf PORTB ;light 1 LED


    movlw d"102"
    subwf RESULTHI
    btfss STATUS, 2 ;Check STATUS bit 2
    movlw b "00000011"
    movwf PORTB ;light 2 LEDs


    movlw d"153"
    subwf RESULTHI
    btfss STATUS, 3 ;Check STATUS bit 3
    movlw b "00000111"
    movwf PORTB ;light 3 LEDs


    movlw d"204"
    subwf RESULTHI
    btfss STATUS, 4 ;Check STATUS bit 4
    movlw b "00001111"
    movwf PORTB ;light 4 LEDs


    movlw d"255"
    subwf RESULTHI
    btfss STATUS, 5 ;Check STATUS bit 5
    goto Loop
    movlw b "00011111"
    movwf PORTB ;light 5 LEDs


    goto Loop

    end
     
  10. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    You are going to have to reread the instructions section of the datasheet.
    The subwf instruction is usually followed by the register, then destination, eg subwf RESULTHI, W or subwf RESULTHI, F. If you don't include the destination the default is F.
    btfsc or btfss only skips one instruction, so is often followed by a goto so think about the program flow. One way would be to put a goto to the next test. After a condition is met and you have set the port bits it's not a good idea to do the rest of the tests.
    Also the last test is not required and won't work properly anyway. If the previous test hasn't got a result then you know the ADC value is higher than 204 so you can light 5 leds.

    <ed> Also it's STATUS, C not what you have put </ed>
     
  11. JML89

    Thread Starter New Member

    Dec 7, 2012
    9
    0
    OK so I think I have got it sorted with the order and the gotos assuming that sending it back to the loop after the LED has been lit will be OK, the speed it goes through the code should result in it being constantly on to the naked eye I hope?
    I didn't understand but not I see that it's C for Carry

    I need to change it so PORTB is all outputs have I done this correctly? It's just under the start below

    ;************************************************* *************************************************
    ;Connect a potentiometer to RA0, convert the analogue signal into digital value, and send it to PORTB,
    ;by adjusting potentiometer, LEDs from 1 to 5 should Light with voltage increase
    ;************************************************* *************************************************

    START

    bsf STATUS, RP0 ;select bank 1
    movlw b"00000000" ;set PortB outputs. 00000000--> w--> TRISB
    movwf TRISB

    bcf STATUS, RP0 ;select bank 0
    clrf PORTB ;set all outputs low

    ;********PORTA, A/D****************
    bsf STATUS, RP0 ;choose bank1
    bcf STATUS, RP1

    movlw 0x07 ;PORTA Comparator off
    movwf CMCON0

    movlw 0x50 ;A/D clock Fosc/16
    movwf ADCON1
    bsf TRISA, 0 ;Set RA0 to input
    bsf ANSEL, 0 ;Set RA0 to analog

    bcf STATUS, RP0 ;Bank 0
    movlw 0x01 ;result left shifted, Vdd Vref, AN0
    movwf ADCON0
    ;

    Loop

    ;----------check A/D results------------------
    banksel ADCON0
    bsf ADCON0, GO ;Start conversion
    btfsc ADCON0, GO ;Is conversion done?
    goto $-1 ;No, test again
    movf ADRESH, W
    movwf RESULTHI ; store ADC value

    movlw d"51"
    subwf RESULTHI, w ;take 51 from RESULTHI
    btfsc STATUS, C ; Check STATUS Carry, if clear skip next
    goto A
    movlw b "00000001"
    movwf PORTB ;light 1 LED

    goto Loop

    A
    movlw d"102"
    subwf RESULTHI, w
    btfsc STATUS, C ;Check STATUS Carry, if clear skip next
    goto B
    movlw b "00000011"
    movwf PORTB ;light 2 LEDs

    goto Loop

    B
    movlw d"153"
    subwf RESULTHI, w
    btfsc STATUS, C ;Check STATUS Carry, if clear skip next
    goto C
    movlw b "00000111"
    movwf PORTB ;light 3 LEDs

    goto Loop

    C
    movlw d"204"
    subwf RESULTHI, w
    btfsc STATUS, C ;Check STATUS Carry, if clear skip next
    goto D
    movlw b "00001111"
    movwf PORTB ;light 4 LEDs

    goto Loop

    D
    movlw b "00011111"
    movwf PORTB ;light 5 LEDs


    goto Loop

    end
     
    Last edited: Dec 10, 2012
  12. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    That's looking pretty good, time to give it a test.
    There's nothing to clear PORTB so whichever LEDs you turn on will stay on until next time it goes through the loop. The only time you should see flickering would be where the voltage is at a point very close to the edge of a range. Then any electrical noise will make one of the LEDs flicker a bit, it will probably just look slightly dim.
     
  13. JML89

    Thread Starter New Member

    Dec 7, 2012
    9
    0
    Thanks I will test it tomorrow first thing and let you know how it went as you have helped so much it seems fair! :D Thank you!
     
  14. JML89

    Thread Starter New Member

    Dec 7, 2012
    9
    0
    Thanks for all the help after a little jiggling it works great and I have a good deal more understanding of how the PIC works!
    Much Appreciated! :D :D
     
Loading...