PDA

View Full Version : Some ASM Help Please



mpgmike
- 13th May 2018, 15:26
I am trying to use an all new PIC16F18426 for a personal project. I built a bench power supply, but the resolution on the LCD readout for Volts & Amps needed more resolution. The PIC16F18426 offers 12-bit ADC. However, since PBP3 cannot yet work with this new PIC, I'm trying my hand at ASM with MPLABX.


The challenge I'm facing in the software is converting the ADC values to decimal and isolating the digits to print to the LCD. The Basic code works like a charm on a PIC16F1824:




Get_Ch1: ;Get Channel 1 Values
ADCON0 = 000011 ;AN0, Volt1
DO
LOOP WHILE ADCON0.1 = 1
V1.HIGHBYTE = ADRESH
V1.LOWBYTE = ADRESL
ADCON0 = 000111 ;AN1, Amp1
DO
LOOP WHILE ADCON0.1 = 1
A1.HIGHBYTE = ADRESH
A1.LOWBYTE = ADRESL
IF (V1 = V1p) AND (A1 = A1p) THEN
RETURN
ENDIF
Volt1 = ((V1 + V1p) * 10) / 53
GOSUB Print_V1
V1p = V1
IF (A1 + A1p) > (V1 + V1p) THEN
Amp1 = (A1 + A1p) - (V1 + V1p)
ELSE
Amp1 = 0
ENDIF
GOSUB Print_A1
A1p = A1
RETURN


Print_A1: ;Amp1 Changed, Send to LCD, Line 2
RS = 0
LCD = $C0
GOSUB Send
RS = 1
pause 1
for b0 = 0 to 7
lookup b0, ["1-Amps: "], b1
LCD = b1
gosub Send
next b0
ARRAYWRITE Amp1a, [#Amp1]
IF Amp1 < 100 THEN
Amp1a[2] = Amp1a[1]
Amp1a[1] = Amp1a[0]
Amp1a[0] = " "
ENDIF
IF Amp1 < 10 THEN
Amp1a[2] = Amp1a[1]
Amp1a[1] = " "
Amp1a[0] = " "
ENDIF
FOR b0 = 0 TO 2
LCD = Amp1a[b0]
GOSUB Send
NEXT b0
FOR b0 = 0 TO 3
LOOKUP b0, [" mA "], b1
LCD = b1
GOSUB Send
NEXT b0
RETURN



The Assembly Code generated for Print_A1 is as follows:




Print_A1: ;Amp1 Changed, Send to LCD, Line 2
LABEL?L _Print_A1
MOVE?CT 000h, _RS ;RS = 0
MOVE?CB 0C0h, _LCD ;LCD = $C0
GOSUB?L _Send ;GOSUB Send
MOVE?CT 001h, _RS ;RS = 1
PAUSE?C 001h ;pause 1
MOVE?CB 000h, _b0 ;for b0 = 0 to 7
LABEL?L L00031
CMPGT?BCL _b0, 007h, L00032
LOOKUP?BCLB _b0, 008h, L00001, _b1 ;lookup b0, ["1-Amps: "], b1
LURET?C 031h
LURET?C 02Dh
LURET?C 041h
LURET?C 06Dh
LURET?C 070h
LURET?C 073h
LURET?C 03Ah
LURET?C 020h


LABEL?L L00001
MOVE?BB _b1, _LCD ;LCD = b1
GOSUB?L _Send ;gosub Send
NEXT?BCL _b0, 001h, L00031 ;next b0
LABEL?L L00032
ARRAYWRITENAME?B _Amp1a ;ARRAYWRITE Amp1a, [#Amp1]
ARRAYWRITECOUNT?C 000h
ARRAYWRITENUM?W _Amp1
ARRAYWRITEDEC?
CMPGE?WCL _Amp1, 064h, L00033 ;IF Amp1 < 100 THEN
MOVE?BB _Amp1a + 00001h, _Amp1a + 00002h ;Amp1a[2] = Amp1a[1]
MOVE?BB _Amp1a, _Amp1a + 00001h ;Amp1a[1] = Amp1a[0]
MOVE?CB 020h, _Amp1a ;Amp1a[0] = " "
LABEL?L L00033 ;ENDIF
CMPGE?WCL _Amp1, 00Ah, L00035 ;IF Amp1 < 10 THEN
MOVE?BB _Amp1a + 00001h, _Amp1a + 00002h Amp1a[2] = Amp1a[1]
MOVE?CB 020h, _Amp1a + 00001h ;Amp1a[1] = " "
MOVE?CB 020h, _Amp1a ;Amp1a[0] = " "
LABEL?L L00035 ;ENDIF
MOVE?CB 000h, _b0 ;FOR b0 = 0 TO 2
LABEL?L L00037
CMPGT?BCL _b0, 002h, L00038
AOUT?BBB _Amp1a, _b0, _LCD ;LCD = Amp1a[b0]
GOSUB?L _Send ;GOSUB Send
NEXT?BCL _b0, 001h, L00037 ;NEXT b0
LABEL?L L00038 ;FOR b0 = 0 TO 3
MOVE?CB 000h, _b0
LABEL?L L00039
CMPGT?BCL _b0, 003h, L00040
LOOKUP?BCLB _b0, 004h, L00002, _b1 ;LOOKUP b0, [" mA "], b1
LURET?C 020h
LURET?C 06Dh
LURET?C 041h
LURET?C 020h


LABEL?L L00002
MOVE?BB _b1, _LCD ;LCD = b1
GOSUB?L _Send ;GOSUB Send
NEXT?BCL _b0, 001h, L00039 ;NEXT b0
LABEL?L L00040
RETURN? ;RETURN



I tried copy/pasting the above code into MPLABX & pretty much all of it generated errors. I've tried numerous approaches but none have worked. Any ideas how to isolate decimal digits (1000s, 100s, 10s, 1s) from a larger value?

mpgmike
- 13th May 2018, 15:33
Oh, the PIC16F18426 uses the mid-range instruction set, so there are no DAW or CMPFSEQ type commands.

pedja089
- 13th May 2018, 16:25
That isn't ASM instruction. It is ASM macro, from PBP library.
Alos arraywrite, etc... All instruction with ? are from PBP lib's.

mpgmike
- 13th May 2018, 16:54
Something to go on.

pedja089
- 13th May 2018, 18:38
You must dig little dipper in PBP librarys. Look for PBPPICxx.mac and PBPPICxx.LIB files for macro definition.
If I was in your place, I would start from controlling PIN, then LCD basic communication, to display char, then to math involved in digit extraction...
EDIT:
PBP libs are great resource for learning ASM.... Lot of work and testing are organized and described in one place....
I learned ASM from PBP lib, and PIC datasheet. Now all interrupts my are written in ASM.

mpgmike
- 13th May 2018, 23:34
Thanks, predja089. Spent the day fighting with it, but I have something that works. I tried typing it into PBP3 & looking at the ASM, but that didn't get me there. Now I'm able to take an ADC-12 read (0 >> 4095) and convert it into 4 decimal digits:



MOVF ADRESH,W
MOVWF b0
MOVF ADRESL,W
MOVF b1
CALL DoMath
MOVLW 0x30
ADDWF Dig1,W
MOVWF Volts11
MOVLW 0x30
ADDWF Dig2,W
MOVWF Volts12
MOVLW 0x30
ADDWF Dig3,W
MOVWF Volts13
MOVLW 0x30
ADDWF Dig4,W
MOVWF Volts14
CALL Display
RETURN

DoMath:
BANKSEL Dig1
CLRF Dig1
CLRF Dig2
CLRF Dig3
CLRF Dig4
BCF STATUS, C
BCF STATUS, DC
Math2: ;Find the 1000,s Digit
MOVLW 0x03
SUBWF b1, W
BTFSS STATUS,C
BRA Math3
MOVLW 0xE8
SUBWF b0, W
BTFSS STATUS,C
BRA Math2a
MOVLW 0x03
SUBWF b1, F
MOVLW 0xE8
SUBWF b0, F
INCF Dig1
BRA Math2
Math2a:
MOVLW 0x04
SUBWF b1,W
BTFSS STATUS,C
GOTO Math3
MOVLW 0x04
SUBWF b1,F
MOVLW 0x18
ADDWF b0
INCF Dig1
BRA Math2
Math3: ;Find the 100,s Digit
MOVLW 0x64
SUBWF b0, W
BTFSS STATUS,C
BRA Math4
MOVLW 0x64
SUBWF b0, F
INCF Dig2
BRA Math3
Math4: ;Account for V1H Carry/Borrow
DECF b1, W
BTFSS STATUS,Z
GOTO Math5
DECF b1,F
MOVLW 0x9C
ADDWF b0
INCF Dig2
BRA Math3
Math5: ;Find the 10,s Digit
MOVLW 0x0A
SUBWF b0, W
BTFSS STATUS,C
BRA Math6
MOVLW 0x0A
SUBWF b0, F
INCF Dig3
BRA Math5
Math6:
MOVF b0,W
MOVWF Dig4
RETURN