Debugging your assembly code with Velleman K8076/VM134 PIC-programmer
When writing C# programs with Visual Studio you have a very nice debugger at hand. When writing assembly/C/C++ code for microchip's micro-controllers, you can use MPLAB Integrated Development Environment. If you have a programmer with debug support you can debug in-circuit. If you don't have such a board but a simple board like Velleman's K8076/VM134, you still can use MLAB because it has a good simulator feature. But if you don't have MPLAB or for whatever reason you need to 'manually' debug your program you can use the approach described in this blog. N.B.: If your device is part of a complex system with lots of high frequency input, then I would advice you to buy a programmer with debugging support. For more simple systems like the LCD-driver I wrote, you can use 'print-statements'. You can read the data and display it on one of the micro-controller ports connected to leds. See schema below for an example. Port B of the PIC16F628A is used for displaying debug information.
PIC debugging
PIC debugging

Scenario: I suspect that the data that is used in set_position (see previous blog) is not what it should be.
I added the part ';begin section for debugging purposes' till ';end section for debugging purposes'

set_position: call init_write_mode ;Set DDRAM Address 0 ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 1 0 AC5 AC4 AC3 AC2 AC1 AC0 movf LCD_TMP, 0 ;write LCD_TMP to W andlw b11110000 ;get high nibble and move result in W movwf LCD_BUF_00 ;write high nible to LCD_BUF movlw b10000000 ;set DB7 to 1 IORWF LCD_BUF_00, 1 ;write back to LCD_TMP ;begin section for debugging purposes movf LCD_TMP, 0 ;What's in LCD_TMP? Write content to W movwf PORTB mydebug: nop goto mydebug ;end section for debugging purposes

The added section reads the value LCD_TMP into register W and puts the result on port B (RB7...RB0) and then starts an endless loop.
I also change the interrupt handler for timer 0 overflows. Because this handler changes the value of port B, it would ruin my captured LCD_TMP state, so I just let it return immediately.

timer0_overflow: return ;for debugging purposes, just return
PIC debugger at work
PIC debugger at work

In order to show more than one byte of information (e.g. 32-bits value) you can show the information in 4 groups of 8-bits. To indicate which byte is shown, all 8 leds blink the n-times, where n = byte number. In the function below, the number of blinks is stored in DLY_VAR.

flash_n_times: movlw b11111111 ;all leds on movwf PORTB movlw 0xff ;wait 255 msec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_msec ; movlw b00000000 ;all leds off movwf PORTB movlw 0xff ;wait 255 msec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_msec ; DECFSZ CNT_VAR, 1 ;decrement CNT_VAR and write back in CNT_VAR, skip if zero goto flash_n_times return

In the method 'debug_show_x' I'm showing the contents of 32-bit variable MATH_RES (the result of a calculation).
  • Blink/flash all leds 4 times. Show byte B4
  • Blink/flash all leds 3 times. Show byte B3
  • blink/flash all leds 2 times. Show byte B2
  • Blink/flash all leds 1 time. Show byte B1

debug_show_x: movlw 0x04 ;flash 4 times movwf CNT_VAR call flash_n_times movf MATH_RES3, 0 ;the register you want to see movwf PORTB movlw 0x03 ;wait 3 sec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_sec ; movlw 0x03 ;flash 3 times movwf CNT_VAR call flash_n_times movf MATH_RES2, 0 ;the register you want to see movwf PORTB movlw 0x03 ;wait 3 sec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_sec ; movlw 0x02 ;flash 2 times movwf CNT_VAR call flash_n_times movf MATH_RES1, 0 ;the register you want to see movwf PORTB movlw 0x03 ;wait 3 sec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_sec ; movlw 0x01 ;flash 1 time movwf CNT_VAR call flash_n_times movf MATH_RES0, 0 ;the register you want to see movwf PORTB movlw 0x03 ;wait 3 sec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_sec ; goto debug_show_x end

I'm aware that it is a poor man's solution. But it did help me in finding some bugs in my program that counts from 2147483648...0 and displays the value on an LCD-module. It uses 32-bits calculations: a divided by b, a times b and a minus b.

#include <E:\Elec\PicProg2009\Include\P16F628A.INC> __CONFIG(_HS_OSC & _WDT_OFF & _MCLRE_OFF & _BOREN_OFF & _LVP_OFF & _DATA_CP_OFF & _CP_OFF); org 0x0000 goto MAIN_INIT org 0x0004 goto MY_INTERRUPT_HANDLER ;N.B. all sub routines must return with BANK 0 selected ;N.B. lower and higher nibbles are LCD nibbles, but they are stored in two bytes because bytes also contain status of LCD_E and LCD_RS ;--- MY_BITS --- #define LCDE 0 ;LCD Enable bit #define WRT 1 ;Ready for writing bit #define SKF 2 ;Skip frame bit #define U4B 3 ;Write upper four bits (high nibble) #define OVERFLOW 4 ;Math overflow #define DIV0 5 ;Division by zero ;PORTB wiring #define RB0 0 ;RB0 => RS is wired to RB0 #define RB1 1 ;RB1 => E is wired to RB1 #define RB3 3 ;RB3 => LED is wired to RB3 ;binary constants #define b00000000 0x00 #define b00000001 0x01 #define b00000011 0x03 #define b00000101 0x05 #define b00001010 0x0A #define b00001111 0x0f #define b00010000 0x10 #define b00011000 0x18 #define b00011111 0x1F #define b00100000 0x20 #define b00100111 0x27 #define b00111011 0x3B #define b01000000 0x40 #define b01000010 0x42 #define b01010101 0x55 #define b01100000 0x60 #define b01100100 0x64 #define b01110000 0x70 #define b10000000 0x80 #define b10000110 0x86 #define b10010110 0x96 #define b10011000 0x98 #define b10011010 0x9A #define b10100000 0xA0 #define b10101010 0xAA #define b11001010 0xCA #define b11000000 0xC0 #define b11100001 0xE1 #define b11101000 0xE8 #define b11110000 0xF0 #define b11110101 0xF5 #define b11111111 0xFF ;Timer constants #define TMR_DELTA 0xF0 ;start at: 255 - x, overflow on 255+1 ;RAM data variables bank 0 cblock 0x20 MY_BITS W_TEMP STATUS_TEMP LCD_BUF_00 LCD_BUF_01 LCD_BUF_02 LCD_BUF_03 LCD_BUF_04 LCD_BUF_05 LCD_BUF_06 LCD_BUF_07 CNT_VAR DLY_VAR CNT0 CNT1 CNT2 CNT3 CNT_RW ;number of items in LCD_BUF LCD_TMP ;buffer for tmp lcd data MATH_A3 ;MATH_A3...0 32 bits unsigned int 'A' MATH_A2 MATH_A1 MATH_A0 MATH_B3 ;MATH_B3...0 32 bits unsigned int 'B' MATH_B2 MATH_B1 MATH_B0 MATH_TMP3 ;MATH_TMP3...0 32 bits unsigned int 'TMP' MATH_TMP2 MATH_TMP1 MATH_TMP0 MATH_RES3 ;MATH_R3...0 32 bits unsigned int 'RESULT' MATH_RES2 MATH_RES1 MATH_RES0 MATH_REM3 ;MATH_REM3...0 32 bits unsigned int 'MATH_REM' MATH_REM2 MATH_REM1 MATH_REM0 CAP_MES3 ;CAP_MES3...0 32 bits unsigned int 'CAP_MES3' CAP_MES2 CAP_MES1 CAP_MES0 LCD_DIV3 ;LCD_DIV3..0 32 bits unsigned int 'LCD_DIV' LCD_DIV2 LCD_DIV1 LCD_DIV0 endc; MAIN_INIT: ;--- select bank 0 --- bcf STATUS, RP0; bcf STATUS, RP1; clrf PORTA; clrf PORTB; clrf MY_BITS clrf W_TEMP clrf STATUS_TEMP clrf CNT_RW clrf LCD_BUF_00 clrf LCD_BUF_01 clrf LCD_BUF_02 clrf LCD_BUF_03 clrf LCD_BUF_04 clrf LCD_BUF_05 clrf LCD_BUF_06 clrf LCD_BUF_07 clrf LCD_TMP clrf DLY_VAR clrf CNT0 clrf CNT1 clrf CNT2 clrf CNT3 ;--- select bank 1 --- bsf STATUS, RP0 ;disable all interrupts clrf INTCON ;GIE PEIE T0IE INTE RBIE T0IF INTF RBIF clrf PIE1 ;EEIE CMIE RCIE TXIE xxx CCP1IE TMR2IE TMR1IE movlw b11000000 ;RA0...RA5 as outputs movwf TRISA ;TRISA, bank 1 movlw b00000000 ;RB0...RB7 as outputs movwf TRISB ;TRISB, bank 1 ;--- select bank 0 --- bcf STATUS, RP0 ; clrf PIR1 ;EEIF CMIF RCIF TXIF xxx CCP1IF TMR2IF TMR1IF call start_lcd_timer ;RS => is wired to RB0 ;E => is wired to RB1 ;Wait for more than 30ms ;after VDD rises to 4.5v movlw 0x80 ;wait > 30 msec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_msec ; ;N: 0 = 1-line mode , 1 = 2-line mode ;F: 0 = 5 x 7 dots, 1 = 5 x 10 dots ; ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 0 0 1 0 X X X X ;0 0 0 0 1 0 X X X X ;0 0 N F X X X X X X call init_write_mode; movlw b00100000 ; movwf LCD_BUF_00 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b00100000 ; movwf LCD_BUF_01 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b01000000 ; movwf LCD_BUF_02 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b01000000 ; movwf LCD_BUF_03 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x80 ;wait >100 msec movwf DLY_VAR ;DLY_VAR bank 0 call delay_msec ; ;D: 0 display off, 1 display on ;C: 0 cursor off, 1 cursor on ;B: 0 blink off, 1 blink on ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 0 0 0 0 X X X X ;0 0 1 D C B X X X X call init_write_mode; movlw b00000000 ; movwf LCD_BUF_00 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b11000000 ; movwf LCD_BUF_01 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x80 ;wait >50 msec movwf DLY_VAR ;move w to DLY_VAR bank 0 call delay_msec; ;Clear Display ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 0 0 0 0 X X X X ;0 0 0 0 0 1 X X X X call init_write_mode; movlw b00000000 ; movwf LCD_BUF_00 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b00010000 ; movwf LCD_BUF_01 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x80 ;wait >50 msec movwf DLY_VAR ;move w to DLY_VAR bank 0 call delay_msec ; ;I/D: 0 decrement mode, 1 increment mode ;SH: 0 entire shift off, 1 entire shift on ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 0 0 0 0 X X X X ;0 0 0 1 I/D SH X X X X call init_write_mode; movlw b00000000 ; movwf LCD_BUF_00 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movlw b01100000 ; movwf LCD_BUF_01 ;move w to LCD_BUFxx bank 0 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x80 ;wait >100 msec movwf DLY_VAR ;move w to DLY_VAR bank 0 call delay_msec; MAIN_LOOP: ;original measurement ;2147483648 = 0x80000000 = b10000000000000000000000000000000 = 2^32 / 2 movlw b10000000 movwf CAP_MES3 movlw b00000000 movwf CAP_MES2 movlw b00000000 movwf CAP_MES1 movlw b00000000 movwf CAP_MES0 MAIN_COUNT_DOWN: movlw 0x00 ;set LCD position to 0 movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_position movf CAP_MES3, 0 ;copy 'CAP_MES' to 'MATH_REM' movwf MATH_REM3 movf CAP_MES2, 0; movwf MATH_REM2 movf CAP_MES1, 0; movwf MATH_REM1 movf CAP_MES0, 0; movwf MATH_REM0 ;1000000000 = 0x3B9ACA00 = b00111011100110101100101000000000 = 10^9 movlw b00111011 movwf LCD_DIV3 movlw b10011010 movwf LCD_DIV2 movlw b11001010 movwf LCD_DIV1 movlw b00000000 movwf LCD_DIV0 call calc_char_n ;100000000 = 0x5F5E100 = b00000101 11110101 11100001 00000000 = 10^8 movlw b00000101 movwf LCD_DIV3 movlw b11110101 movwf LCD_DIV2 movlw b11100001 movwf LCD_DIV1 movlw b00000000 movwf LCD_DIV0 call calc_char_n ;100000000 = 0x989680 = b00000000 10011000 10010110 10000000 = 10^7 movlw b00000000 movwf LCD_DIV3 movlw b10011000 movwf LCD_DIV2 movlw b10010110 movwf LCD_DIV1 movlw b10000000 movwf LCD_DIV0 call calc_char_n ;1000000 = 0xF4240 = b00000000 00001111 01000010 01000000 = 10^6 movlw b00000000 movwf LCD_DIV3 movlw b00001111 movwf LCD_DIV2 movlw b01000010 movwf LCD_DIV1 movlw b01000000 movwf LCD_DIV0 call calc_char_n ;call debug_show_x ;100000 = 186A0 = b00000001 10000110 10100000 = 10^5 movlw b00000000 movwf LCD_DIV3 movlw b00000001 movwf LCD_DIV2 movlw b10000110 movwf LCD_DIV1 movlw b10100000 movwf LCD_DIV0 call calc_char_n ;10000 = 0x2710 = b00000000 00000000 00100111 00010000 = 10^4 movlw b00000000 movwf LCD_DIV3 movlw b00000000 movwf LCD_DIV2 movlw b00100111 movwf LCD_DIV1 movlw b00010000 movwf LCD_DIV0 call calc_char_n ;1000 = 0x3E8 = b00000000 00000000 00000011 11101000 = 10^3 movlw b00000000 movwf LCD_DIV3 movlw b00000000 movwf LCD_DIV2 movlw b00000011 movwf LCD_DIV1 movlw b11101000 movwf LCD_DIV0 call calc_char_n ;100 = 0x64 = b00000000 00000000 00000000 01100100 = 10^2 movlw b00000000 movwf LCD_DIV3 movlw b00000000 movwf LCD_DIV2 movlw b00000000 movwf LCD_DIV1 movlw b01100100 movwf LCD_DIV0 call calc_char_n ;10 = 0x0a = b00000000 00000000 00000000 00001010 = 10^1 movlw b00000000 movwf LCD_DIV3 movlw b00000000 movwf LCD_DIV2 movlw b00000000 movwf LCD_DIV1 movlw b00001010 movwf LCD_DIV0 call calc_char_n ;1 = 0x01 = b00000000 00000000 00000000 00000001 = 10^0 movlw b00000000 movwf LCD_DIV3 movlw b00000000 movwf LCD_DIV2 movlw b00000000 movwf LCD_DIV1 movlw b00000001 movwf LCD_DIV0 call calc_char_n movf CAP_MES3, 0 ;copy 'CAP_MES' to 'MATH_A' movwf MATH_A3 movf CAP_MES2, 0; movwf MATH_A2 movf CAP_MES1, 0; movwf MATH_A1 movf CAP_MES0, 0; movwf MATH_A0 movlw b00000000 movwf MATH_B3 movlw b00000000 movwf MATH_B2 movlw b00000000 movwf MATH_B1 movlw b00000001 movwf MATH_B0 call calc_a_minus_b movf MATH_RES3, 0 ;copy 'MATH_RES' to 'CAP_MES' movwf CAP_MES3 movf MATH_RES2, 0; movwf CAP_MES2 movf MATH_RES1, 0; movwf CAP_MES1 movf MATH_RES0, 0; movwf CAP_MES0 goto MAIN_COUNT_DOWN ;--- end MAIN_LOOP --- ;--- copy 'A' to 'TMP' and clear result copy_a_to_tmp_and_clear_result: movf MATH_A3, 0 ;copy 'A' to 'TMP' movwf MATH_TMP3 movf MATH_A2, 0 movwf MATH_TMP2 movf MATH_A1, 0 movwf MATH_TMP1 movf MATH_A0, 0 movwf MATH_TMP0 movlw b00000000 movwf MATH_RES0 ;clear 'RES' movwf MATH_RES1 movwf MATH_RES2 movwf MATH_RES3 return ;--- endd copy 'A' to 'TMP' and clear result ;--- calc_a_minus_b --- calc_a_minus_b: call copy_a_to_tmp_and_clear_result calc_a_minus_b_b0: movf MATH_B0, 0 ;move MATH_B0 to W subwf MATH_TMP0, 1 ;subtract W from TMP0 and store result in TMP0 ;If result is negative then C=0, Z=0 ;If result is positive then C=1, Z=0 ;If result is zero then C=1, Z=1 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_minus_b_b1 movlw 0x01 ;decrement TMP1 subwf MATH_TMP1, 1 ;subtract W from TMP1 and store result in TMP1 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_minus_b_b1; movlw 0x01 ;decrement TMP2 subwf MATH_TMP2, 1 ;subtract W from TMP2 and store result in TMP2 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_minus_b_b1; movlw 0x01 ;decrement TMP2 subwf MATH_TMP3, 1 ;subtract W from TMP3 and store result in TMP3 btfss STATUS, C ;If result is negative, then Carry = 0 goto calc_a_minus_b_end; calc_a_minus_b_b1: movf MATH_B1, 0 ;move MATH_B1 to W subwf MATH_TMP1, 1 ;subtract W from TMP1 and store result in TMP1 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_minus_b_b2 movlw 0x01 ;decrement TMP2 subwf MATH_TMP2, 1 ;subtract W from TMP2 and store result in TMP2 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_minus_b_b2; movlw 0x01 ;decrement TMP2 subwf MATH_TMP3, 1 ;subtract W from TMP3 and store result in TMP3 btfss STATUS, C ;If result is negative, then Carry = 0 goto calc_a_minus_b_end; calc_a_minus_b_b2: movf MATH_B2, 0 ;move MATH_B2 to W subwf MATH_TMP2, 1 ;subtract W from TMP2 and store result in TMP2 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_minus_b_b3 movlw 0x01 ;decrement TMP3 subwf MATH_TMP3, 1 ;subtract W from TMP3 and store result in TMP3 btfss STATUS, C ;If result is negative, then Carry = 0 goto calc_a_minus_b_end; calc_a_minus_b_b3: movf MATH_B3, 0 ;move MATH_B3 to W subwf MATH_TMP3, 1 ;subtract W from TMP3 and store result in TMP3 btfss STATUS, C ;If result is negative, then Carry = 0 goto calc_a_minus_b_end; movf MATH_TMP3, 0 movwf MATH_RES3 movf MATH_TMP2, 0 movwf MATH_RES2 movf MATH_TMP1, 0 movwf MATH_RES1 movf MATH_TMP0, 0 movwf MATH_RES0 calc_a_minus_b_end: return ;--- end calc_a_minus_b --- ;--- calc_a_divided_by_b --- calc_a_divided_by_b: call copy_a_to_tmp_and_clear_result calc_a_divided_by_b_b0: movf MATH_B0, 0 ;move MATH_B0 to W subwf MATH_TMP0, 1 ;subtract W from TMP0 and store result in TMP0 ;If result is negative then C=0, Z=0 ;If result is positive then C=1, Z=0 ;If result is zero then C=1, Z=1 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_divided_by_b_b1 movlw 0x01 ;decrement TMP1 subwf MATH_TMP1, 1 ;subtract W from TMP1 and store result in TMP1 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_divided_by_b_b1; movlw 0x01 ;decrement TMP2 subwf MATH_TMP2, 1 ;subtract W from TMP2 and store result in TMP2 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_divided_by_b_b1; movlw 0x01 ;decrement TMP2 subwf MATH_TMP3, 1 ;subtract W from TMP3 and store result in TMP3 btfss STATUS, C ;If result is negative, then Carry = 0 goto calc_a_divided_by_b_end; calc_a_divided_by_b_b1: movf MATH_B1, 0 ;move MATH_B1 to W subwf MATH_TMP1, 1 ;subtract W from TMP1 and store result in TMP1 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_divided_by_b_b2 movlw 0x01 ;decrement TMP2 subwf MATH_TMP2, 1 ;subtract W from TMP2 and store result in TMP2 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_divided_by_b_b2; movlw 0x01 ;decrement TMP2 subwf MATH_TMP3, 1 ;subtract W from TMP3 and store result in TMP3 btfss STATUS, C ;If result is negative, then Carry = 0 goto calc_a_divided_by_b_end; calc_a_divided_by_b_b2: movf MATH_B2, 0 ;move MATH_B2 to W subwf MATH_TMP2, 1 ;subtract W from TMP2 and store result in TMP2 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_divided_by_b_b3 movlw 0x01 ;decrement TMP3 subwf MATH_TMP3, 1 ;subtract W from TMP3 and store result in TMP3 btfss STATUS, C ;If result is negative, then Carry = 0 goto calc_a_divided_by_b_end; calc_a_divided_by_b_b3: movf MATH_B3, 0 ;move MATH_B3 to W subwf MATH_TMP3, 1 ;subtract W from TMP3 and store result in TMP3 btfss STATUS, C ;If result is negative, then Carry = 0 goto calc_a_divided_by_b_end; incf MATH_RES0, 1 ;increment MATH_RES0 btfss STATUS, Z ;on overflow, Z=1 goto calc_a_divided_by_b_b0 ;try another subtraction incf MATH_RES1, 1 ;increment MATH_RES1 btfss STATUS, Z ;on overflow, Z=1 goto calc_a_divided_by_b_b0 ;try another subtraction incf MATH_RES2, 1 ;increment MATH_RES2 btfss STATUS, Z ;on overflow, Z=1 goto calc_a_divided_by_b_b0 ;try another subtraction incf MATH_RES3, 1 ;increment MATH_RES3 btfss STATUS, Z ;on overflow, Z=1 goto calc_a_divided_by_b_b0 ;try another subtraction bsf MY_BITS, OVERFLOW ;set overflow flag calc_a_divided_by_b_end: return ;--- calc_a_divided_by_b --- ;--- calc_a_times_b --- ;TMP0 contains current number of runs calc_a_times_b: call copy_a_to_tmp_and_clear_result calc_a_times_b_run: ;decrement, if < 0 then stop adding movlw 0x01 ;decrement TMP0 subwf MATH_TMP0, 1 ;subtract W from TMP0 and store result in TMP0 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_times_b_b0; movlw 0x01 ;decrement TMP1 subwf MATH_TMP1, 1 ;subtract W from TMP1 and store result in TMP1 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_times_b_b0; movlw 0x01 ;decrement TMP2 subwf MATH_TMP2, 1 ;subtract W from TMP2 and store result in TMP2 btfsc STATUS, C ;If result is negative, then Carry = 0 goto calc_a_times_b_b0; movlw 0x01 ;decrement TMP3 subwf MATH_TMP3, 1 ;subtract W from TMP3 and store result in TMP3 btfss STATUS, C ;If result is negative, then Carry = 0 goto calc_a_times_b_end; ;add B to RES and store result in RES calc_a_times_b_b0: movf MATH_B0, 0 ;move MATH_B0 to W addwf MATH_RES0, 1 ;add W to MATH_RES0 and store result in MATH_RES0 btfss STATUS, C ;If result overflows, then Carry = 1 goto calc_a_times_b_b1 incf MATH_RES1, 1 ;increment RES1 btfss STATUS, Z ;If result overflows, then Z = 1 goto calc_a_times_b_b1; incf MATH_RES2, 1 ;increment RES2 btfss STATUS, Z ;If result overflows, then Z = 1 goto calc_a_times_b_b1; incf MATH_RES3, 1 ;increment RES3 btfss STATUS, Z ;If result overflows, then Z = 1 goto calc_a_times_b_b1 ; bsf MY_BITS, OVERFLOW ;set overflow flag goto calc_a_times_b_end calc_a_times_b_b1: movf MATH_B1, 0 ;move MATH_B0 to W addwf MATH_RES1, 1 ;add W to MATH_RES1 and store result in MATH_RES1 btfss STATUS, C ;If result overflows, then Carry = 1 goto calc_a_times_b_b2 incf MATH_RES2, 1 ;increment RES2 btfss STATUS, Z ;If result overflows, then Z = 1 goto calc_a_times_b_b2; incf MATH_RES3, 1 ;increment RES3 btfss STATUS, Z ;If result overflows, then Z = 1 goto calc_a_times_b_b2 ; bsf MY_BITS, OVERFLOW ;set overflow flag goto calc_a_times_b_end calc_a_times_b_b2: movf MATH_B2, 0 ;move MATH_B2 to W addwf MATH_RES2, 1 ;add W to MATH_RES2 and store result in MATH_RES2 btfss STATUS, C ;If result overflows, then Carry = 1 goto calc_a_times_b_b3; incf MATH_RES3, 1 ;increment RES3 btfss STATUS, Z ;If result overflows, then Carry = 1 goto calc_a_times_b_b3; bsf MY_BITS, OVERFLOW ;set overflow flag goto calc_a_times_b_end calc_a_times_b_b3: movf MATH_B3, 0 ;move MATH_B3 to W addwf MATH_RES3, 1 ;add W to MATH_RES3 and store result in MATH_RES3 btfss STATUS, C ;If result overflows, then Carry = 1 goto calc_a_times_b_run bsf MY_BITS, OVERFLOW ;set overflow flag calc_a_times_b_end: return ;--- calc_a_times_b --- init_write_mode: bcf MY_BITS, WRT ;not ready for writing data to LCD movlw 0x00 movwf CNT_RW ; bsf MY_BITS, U4B ;upper four bits return set_char: call init_write_mode movf LCD_TMP, 0 ;write LCD_TMP to W andlw b11110000 ;get high nibble and move result in W movwf LCD_BUF_00 ;write high nible to LCD_BUF movlw b00000001 ;or with 1 in order to set LCD_RS iorwf LCD_BUF_00, 1 ;Inclusive OR and write back to LCD_BUF_00 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movf LCD_TMP, 0 ; andlw b00001111 ;get lower nibble and move result in W movwf LCD_BUF_01 bcf STATUS, C ;clear carry rlf LCD_BUF_01,1 ;shift left and store result in LCD_BUF rlf LCD_BUF_01,1 rlf LCD_BUF_01,1 rlf LCD_BUF_01,1 movlw b00000001 ;or with 1 in order to set LCD_RS iorwf LCD_BUF_01, 1 ;Inclusive OR and write back to LCD_BUF_00 incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x50 ; movwf DLY_VAR ;move w to DLY_VAR bank 0 call delay_usec; return set_position: call init_write_mode ;Set DDRAM Address 0 ;RS RW DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 ;0 0 1 0 AC5 AC4 AC3 AC2 AC1 AC0 movf LCD_TMP, 0 ;write LCD_TMP to W andlw b11110000 ;get high nibble and move result in W movwf LCD_BUF_00 ;write high nible to LCD_BUF movlw b10000000 ;set DB7 to 1 IORWF LCD_BUF_00, 1 ;write back to LCD_TMP incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW movf LCD_TMP, 0 ;write LCD_TMP to W andlw b00001111 ;get lower nibble and move result in W movwf LCD_BUF_01 ; bcf STATUS, C ;clear carry rlf LCD_BUF_01, 1 ;shift left and store result in LCD_BUF rlf LCD_BUF_01, 1 rlf LCD_BUF_01, 1 rlf LCD_BUF_01, 1 ;movlw b10000000 ;set DB7 to 1 ;IORWF LCD_BUF_01, 1 ;write back to LCD_TMP incf CNT_RW, 1 ;RW index bank 0, write result back in CNT_RW bsf MY_BITS, WRT ;ready for writing data bank 0 movlw 0x05 ; movwf DLY_VAR ;move w to DLY_VAR bank 0 call delay_msec; return delay_sec: ;20 Mhz movf DLY_VAR, 0 ;1 cycle, move content of DLY_VAR to W movwf CNT0 ;1 cycle delay_sec_cnt0: movlw 0x60 ;1 cycle 96 movwf CNT1 ;1 cycle delay_sec_cnt1: movlw 0x45 ;1 cycle 69 movwf CNT2 ;1 cycle delay_sec_cnt2: movlw 0xFA ;1 cycle 250 movwf CNT3 ;1 cycle delay_sec_cnt3: decfsz CNT3 ;1 cycle goto delay_sec_cnt3 ;2 cycles decfsz CNT2 ;1 cycle goto delay_sec_cnt2 ;2 cycles decfsz CNT1 ;1 cycle goto delay_sec_cnt1 ;2 cycles decfsz CNT0 ;2 cycles goto delay_sec_cnt0 ;1 cycle return delay_msec: ;20 Mhz movf DLY_VAR, 0 ;1 cycle, move content of DLY_VAR to W movwf CNT0 ;1 cycle delay_msec_cnt0: movlw 0x28 ;1 cycle 40 movwf CNT1 ;1 cycle delay_msec_cnt1: movlw 0x28 ;1 cycle 40 movwf CNT2 ;1 cycle delay_msec_cnt2: decfsz CNT2 ;1 cycle goto delay_msec_cnt2 ;2 cycles decfsz CNT1 ;1 cycle goto delay_msec_cnt1 ;2 cycles decfsz CNT0 ;2 cycles goto delay_msec_cnt0 ;1 cycle return delay_usec: ;20 Mhz movf DLY_VAR, 0 ;1 cycle, move content of DLY_VAR to W movwf CNT0 ;1 cycle delay_usec_cnt0: nop ;1 cycle nop ;1 cycle decfsz CNT0 ;2 cycles goto delay_usec_cnt0 ;1 cycle return start_lcd_timer: ;--- BANK 1 --- bsf STATUS, RP0 ;select bank 1 ;disable all interrupts clrf INTCON ;GIE PEIE T0IE INTE RBIE T0IF INTF RBIF clrf PIE1 ;EEIE CMIE RCIE TXIE xxx CCP1IE TMR2IE TMR1IE bsf PCON, OSCF ;4 Mhz movlw b00011111 ; movwf TRISA ;TRISA, bank 1 movlw b00000000 ;RB0...RB7 as outputs movwf TRISB ;TRISB, bank 1 ;bit 7 RBPU: PORTB Pull-up Enable bit ; 1 = PORTB pull-ups are disabled ; 0 = PORTB pull-ups are enabled by individual port latch values ;bit 6 INTEDG: Interrupt Edge Select bit ; 1 = Interrupt on rising edge of RB0/INT pin ; 0 = Interrupt on falling edge of RB0/INT pin ;bit 5 T0CS: TMR0 Clock Source Select bit ; 1 = Transition on RA4/T0CKI/CMP2 pin ; 0 = Internal instruction cycle clock (CLKOUT) ;bit 4 T0SE: TMR0 Source Edge Select bit ; 1 = Increment on high-to-low transition on RA4/T0CKI/CMP2 pin ; 0 = Increment on low-to-high transition on RA4/T0CKI/CMP2 pin ;bit 3 PSA: Prescaler Assignment bit ; 1 = Prescaler is assigned to the WDT ; 0 = Prescaler is assigned to the Timer0 module ;bit 2-0 PS<2:0>: Prescaler Rate Select bits ; 0 = nPBPU INTEDG T0CS T0SE PSA PS<2:0>: Prescaler Rate Select bits movlw b00011000 ;pull-ups, internal oscillator, WDT prescalar movwf OPTION_REG ;OPTION_REG, bank 1 ;--- BANK 0 --- bcf STATUS, RP0 ;select bank 0 movlw U4B; movwf MY_BITS; movlw TMR_DELTA ;set initial value movwf TMR0; ;TMR0, bank 0 clrf PORTA ;PORTA, bank 0 clrf PORTB ;PORTB, bank 0 bsf INTCON, T0IE ;INTCON enable timer 0 overflow bsf INTCON, GIE ;enable interrupts return timer0_overflow: ;--- BANK 0 --- bcf STATUS, RP0 bcf STATUS, RP1 t0if_set_data: ;--- BANK 0 --- bcf STATUS, RP0 ;select bank 0 bcf STATUS, RP1 ;select bank 0 btfss MY_BITS, SKF ;Bit test flag, skip if set 'Skip frame' goto t0if_nSKF ;SKF is not set, normal mode bcf MY_BITS, SKF ;clear SKF-flag and go to toggle LCD_E goto t0if_toggle_lcd_e t0if_nSKF: btfss MY_BITS, LCDE ;Bit test flag, skip if set LCD_E == LCD enable bit is set goto t0if_reset_lcd_e ;go to reset lcde btfss MY_BITS, WRT ;Bit test flag, skip if set WRT == ready to write data to LCD goto t0if_reset_lcd_e ;go to reset lcde bcf STATUS, C ;clear carry bcf STATUS, Z ;clear carry movf CNT_RW, 0 ;check if CNT_RW is 0 addlw b11111111 btfss STATUS, C ;if CNT_RW not is 0, then Carry flag will be set goto t0if_no_more_data ;go to toggle LCD_E movf LCD_BUF_00, 0 ;Move content of LCD_BUF_00 to W movwf PORTB ;Move content of W to PORTB movf LCD_BUF_01, 0 ;Move LCD_BUF one down, this could probably be optimized movwf LCD_BUF_00 movf LCD_BUF_02, 0 movwf LCD_BUF_01 movf LCD_BUF_03, 0 movwf LCD_BUF_02 movf LCD_BUF_04, 0 movwf LCD_BUF_03 movf LCD_BUF_05, 0 movwf LCD_BUF_04 movf LCD_BUF_06, 0 movwf LCD_BUF_05 movf LCD_BUF_07, 0 movwf LCD_BUF_06 clrf LCD_BUF_07 decf CNT_RW, 1 ;Decrement CNT_RW and store result in CNT_RW btfsc MY_BITS, U4B ;Bit test flag, skip if clear goto t0if_lower_nibble bsf MY_BITS, SKF ;After writing lower nibble, set skip frames flag. We don't wair for LCD is busy, have build in delay bsf MY_BITS, U4B ;Next write will be upper nibble of next frame goto t0if_toggle_lcd_e ;go to toggle LCD_E t0if_lower_nibble: bcf MY_BITS, U4B ;Next write will be lower nibble of current frame. goto t0if_toggle_lcd_e ;go to toggle LCD_E t0if_no_more_data: bcf MY_BITS, LCDE ;clear 'LCD Enable' bcf PORTB, 1; goto t0if_toggle_lcd_e t0if_reset_lcd_e: bcf PORTB, 1 ;clear PORTB RB1, bank 0 bcf MY_BITS, LCDE ;clear LCDE t0if_toggle_lcd_e: btfss MY_BITS, LCDE ;if LCDE is set, set RB1 and clear LCDE goto t0if_set_lcd_e; ;else clear RB1 and set LCDE bsf PORTB, 1 ;set PORTB RB1, bank 0 bcf MY_BITS, LCDE ;clear LCDE t0if_set_lcd_e: bcf PORTB, 1 ;set PORTB RB1, bank 0 bsf MY_BITS, LCDE ;clear LCDE movlw TMR_DELTA ;set initial value movwf TMR0; ;TMR0, bank 0 bcf INTCON, T0IF ;reset interrupt T0IF return calc_char_n: bcf INTCON, T0IE ;INTCON disable timer 0 overflow movf MATH_REM3, 0 ;copy 'MATH_REM' to 'A' movwf MATH_A3 movf MATH_REM2, 0 movwf MATH_A2 movf MATH_REM1, 0 movwf MATH_A1 movf MATH_REM0, 0 movwf MATH_A0 movf LCD_DIV3, 0 ;copy 'LCD_DIV' to 'B' movwf MATH_B3 movf LCD_DIV2, 0 movwf MATH_B2 movf LCD_DIV1, 0 movwf MATH_B1 movf LCD_DIV0, 0 movwf MATH_B0 call calc_a_divided_by_b movlw TMR_DELTA ;set initial value movwf TMR0; ;TMR0, bank 0 bsf INTCON, T0IE ;INTCON enable timer 0 overflow movlw 0x30 ;'0' ADDWF MATH_RES0, 0 ;add w and RES3 store result in W movwf LCD_TMP ;move w to LCD_TMP bank 0 call set_char bcf INTCON, T0IE ;INTCON disable timer 0 overflow movf MATH_RES3, 0 movwf MATH_A3 movf MATH_RES2, 0 movwf MATH_A2 movf MATH_RES1, 0 movwf MATH_A1 movf MATH_RES0, 0 ;copy 'RES' to 'A' movwf MATH_A0 call calc_a_times_b movf MATH_REM3, 0 ;copy 'MATH_REM' to 'A' movwf MATH_A3 movf MATH_REM2, 0 movwf MATH_A2 movf MATH_REM1, 0 movwf MATH_A1 movf MATH_REM0, 0 movwf MATH_A0 movf MATH_RES0, 0 ;copy 'RES' to 'B' movwf MATH_B0 movf MATH_RES1, 0 movwf MATH_B1 movf MATH_RES2, 0 movwf MATH_B2 movf MATH_RES3, 0 movwf MATH_B3 call calc_a_minus_b movf MATH_RES3, 0 ;copy 'RES' to 'MATH_REM' movwf MATH_REM3 movf MATH_RES2, 0 movwf MATH_REM2 movf MATH_RES1, 0 movwf MATH_REM1 movf MATH_RES0, 0 movwf MATH_REM0 movlw TMR_DELTA ;set initial value movwf TMR0; ;TMR0, bank 0 bsf INTCON, T0IE ;INTCON enable timer 0 overflow return MY_INTERRUPT_HANDLER: ;SAVING THE STATUS AND W REGISTERS IN RAM movwf W_TEMP ;copy W to temp register, could be in any bank swapf STATUS,W ;swap status to be saved into W bcf STATUS,RP0 ;change to bank 0 regardless of current bank movwf STATUS_TEMP ;save status to bank 0 register ;--- ISR --- bsf STATUS, RP0 ;select bank 1 btfsc INTCON, T0IF ;timer0 overflow? skip if clear call timer0_overflow ; ;--- end ISR --- swapf STATUS_TEMP,W ;swap STATUS_TEMP register into W, sets bank to original state movwf STATUS ;move W into STATUS register swapf W_TEMP,F ;swap W_TEMP swapf W_TEMP,W ;swap W_TEMP into W retfie ;return from interrupt flash_n_times: movlw b11111111 ;all leds on movwf PORTB movlw 0xff ;wait 255 msec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_msec ; movlw b00000000 ;all leds off movwf PORTB movlw 0xff ;wait 255 msec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_msec ; DECFSZ CNT_VAR, 1 ;decrement CNT_VAR and write back in CNT_VAR, skip if zero goto flash_n_times return debug_show_x: movlw 0x04 ;flash 4 times movwf CNT_VAR call flash_n_times movf MATH_RES3, 0 ;the register you want to see movwf PORTB movlw 0x03 ;wait 3 sec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_sec ; movlw 0x03 ;flash 3 times movwf CNT_VAR call flash_n_times movf MATH_RES2, 0 ;the register you want to see movwf PORTB movlw 0x03 ;wait 3 sec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_sec ; movlw 0x02 ;flash 2 times movwf CNT_VAR call flash_n_times movf MATH_RES1, 0 ;the register you want to see movwf PORTB movlw 0x03 ;wait 3 sec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_sec ; movlw 0x01 ;flash 1 time movwf CNT_VAR call flash_n_times movf MATH_RES0, 0 ;the register you want to see movwf PORTB movlw 0x03 ;wait 3 sec; movwf DLY_VAR ;DLY_VAR bank 0 call delay_sec ; goto debug_show_x end

Back to List

All form fields are required.
A confirmation mail for the comments will be send to you.