Adapting Assembly Code for 16f917

Thread Starter

JML89

Joined Dec 7, 2012
9
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
 

Markd77

Joined Sep 7, 2009
2,806
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.
 

atferrari

Joined Jan 6, 2004
4,764
Since you say "adapting", is it code written for a different micro or what?

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

takao21203

Joined Apr 28, 2012
3,702
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:

Thread Starter

JML89

Joined Dec 7, 2012
9
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
 

takao21203

Joined Apr 28, 2012
3,702
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.
 

Markd77

Joined Sep 7, 2009
2,806
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.
 

Thread Starter

JML89

Joined Dec 7, 2012
9
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?
 

Thread Starter

JML89

Joined Dec 7, 2012
9
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
 

Markd77

Joined Sep 7, 2009
2,806
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>
 

Thread Starter

JML89

Joined Dec 7, 2012
9
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:

Markd77

Joined Sep 7, 2009
2,806
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.
 

Thread Starter

JML89

Joined Dec 7, 2012
9
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!
 

Thread Starter

JML89

Joined Dec 7, 2012
9
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
 
Top