Archive

Archive for May, 2014

pic18f4620 xc8 compiler bundle

May 22, 2014 Leave a comment

Here’s a small (5.2 MB) bundle that I use to compile and program c code on my pic18f4620 using a pickit2 on my PC. I’ve only tested this on XP.

It doesn’t have all the features of a full blown IDE like MPLABX (no stepping through code I’m afraid) but is a nice concise package that encourages the use of command line scripting.

Getting Started

  • Download the zip file on to your PC or, preferably, a USB key
  • Extract the files to a folder on your PC or USB key

The extracted folder contains the xc8 compiler files (modified to work with the pic18f4620 only), the pk2cmd software tool which is used to communicate with the PICkit2, and Notepad++, which can be used to write and modify code.

To create a new project do the following:

        1. First create a new folder inside the “robosumo_files” folder and copy the build.bat file into that folder.
        2.  Run the Notepad++  editor and paste the example code (flashing LED) given below. Save the code in the new folder as a file called “main.c” (don’t include quotes in the filename).
        3. Make sure the PICkit2 programmer is correctly connected to the PIC18f4620 and finally double click the build.bat file.
        4. If there are no errors in the code and the hardware is set up correctly then the PIC18f4620 will be programmed.

robosumo_build_result

Example Code – Flashing LED

This is a pared back example program for the PIC18F4620. It blinks an LED connected to pin 19 (RD0). See this circuit

//
// PIC18F4620 example program
// Written by Ted Burke (ted.burke@dit.ie)
// Last update 28-2-2013
//

#include <xc.h>

#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF,BOREN=OFF

int main(void)
{
	// Make RD0 a digital output
	TRISD = 0b11111110;

	while(1)
	{
		LATDbits.LATD0 = 1; // Set pin RD0 high
		_delay(125000);     // 0.5 second delay
		LATDbits.LATD0 = 0; // Set pin RD0 low
		_delay(125000);     // 0.5 second delay
	}
}
Categories: pic18f, Uncategorized

pic18f4620 assembly bundle

May 22, 2014 Leave a comment

Here’s a small (3.6 MB) bundle that I use to program my pic18f4620 using a pickit2 with assembly code on my PC. I’ve only tested this on XP.

It doesn’t have all the features of a full blown IDE like MPLABX (no stepping through code I’m afraid) but is a nice concise package that encourages the use of command line scripting.

The bundle also includes some example code.

Getting Started

Download the bundle from here and extract the files.

pic18fassemby_extracted_files

The extracted folder contains the mpasmx assembler files, the pk2cmd software tool which is used to communicate with the PICkit2, and Notepad++ text editor, which can be used to write and modify code.

The bundle includes 6 example projects.

To create a new project do the following:

  1. First create a new folder inside the “pic18f4620_asm” folder and copy the build.bat file into that folder.
  2. Run the Notepad++ editor and paste the example code (flashing LED) given below. Save the code in the new folder as a file called “main.asm” (don’t include quotes in the filename).
  3. Make sure the PICkit2 programmer is correctly connected to the PIC18f4620 and finally double click the build.bat file.
  4. If there are no errors in the code and the hardware is set up correctly then the PIC18f4620 will be programmed.

asm_output

Example Code to work with this circuit
This code will flash the LED connected to pin 19 (RD0)

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset
 
;--------------------------------------------------------------------------
; Main Program
;--------------------------------------------------------------------------

    org 0x0100 
Main
    clrf TRISD ; All PORT D IO pins are configured as outputs

    ; Set up timer 0 so it can be used to control flash rate
    bcf T0CON, T0CS; use internal instruction cycle clock
    bcf T0CON, T08BIT; use 16 bit mode
    bcf INTCON, TMR0IF; reset timer overflow flag
    bsf T0CON, TMR0ON; turn on timer 0    
        
loop  
    ; check if the timer0 overflow flag has been set
    btfss INTCON, TMR0IF
    goto loop
    bcf INTCON, TMR0IF; reset timer overflow flag

    ;invert LATD0
    movlw 0x1
    XORWF LATD,F
    
    goto loop   
    END
    
Categories: pic18f, Uncategorized

Heartrate (BPM) Example Matlab Code

May 22, 2014 Leave a comment

This is the code I used in my youtube video at http://youtu.be/3tdumuwHgxc

% program to determine the BPM of an ECG signal


% count the dominant peaks in the signal (these correspond to heart beats)
% - peaks are defined to be sampels greater than their two nearest neighbours and greater than 1

beat_count = 0;
for k = 2 : length(sig)-1
    if(sig(k) &gt; sig(k-1) &amp; sig(k) &gt; sig(k+1) &amp; sig(k) &gt; 1)
        %k
        %disp('Prominant peak found');
        beat_count = beat_count + 1;
    end
end

% Divide the beats counted by the signal duration (in minutes)
fs = 100;
N = length(sig);
duration_in_seconds = N/fs;
duration_in_minutes = duration_in_seconds/60;
BPM_avg = beat_count/duration_in_minutes;

pic18f assembly example 6 – discrete filter implementation

May 20, 2014 Leave a comment
;-----------------------------------------------------------------------------------------------------------------------------
; This assembly code sets up a timer interrupt to be triggered every millisecond on the pic18f4620.
; When the interrupt service routine is called an ADC on channel 0 is performed and this value  is used as an
;    input to the discrete system given by the difference equation y[n] = x[n]-0.3x[n-1]+0.3y[n-1]-0.75y[n-1]
;    The output of the discrete system is then sent to a  DAC (MCP4921) via the SPI protocol.
;
; Test cicruit used is same as at http://eleceng.dit.ie/daq_lite/build.html
;
; This code is just an educational example and no attempt has been made to optimise it in any way. Use it whatever way you want but I don't accept any responsibility for any problems this code might cause you.
;
; NOTE 1: Only the most significant 8 bits of the 10-bit ADC are used. Therefore the
;    the ADC values used are in the range of 0-255.
; NOTE 2: When implementing the discrete system the ADC values are interpreted as a signed signal which varies between 0.9922 (=127/128) and -1.
;    An ADC value of 255 is interpreted as a signal value of 0.9922; an ADC value of 0 is interpreted as a signal value of -1 ;
;    an ADC value of 128 is interpreted as a signal value of 0; An ADC value of 127 is interpreted as a signal value of -0.0078 (1/128)
; NOTE 3: The pic18f does not have a floating point unit and signed decimal values are represented in and 8-bit, fixed point, 2's complement format.
;    A signal value of 0.9922 is stored as a binary value of '01111111' in memory 
;    A signal value of -1 is stored as a binary value of '10000000'  in memory
;    A signal value of 0.5 is stored as binary value of '01000000' in memory 
;    A signal value of -0.5 is stored as binary value of '11000000' in memory 
;    A signal value of 0.75 is stored as binary value of '01100000' in memory 
;    A signal value of -0.75 is stored as binary value of '10100000' in memory 
;    A signal value of 0.0078 is stored as binary value of '00000001' in memory
;    A signal value of -0.0078 is stored as binary value of '11111111' in memory 
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;-----------------------------------------------------------------------------------------------------------------------------
 

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset

 ;NOTE: When an interrupt is triggered the micro jumps to 0x0008 for high priority and 0x0018 for low priority.
    org 0x0008
    goto hi_isr ;once a high priority interrupt is triggered jump to hi_isr
    org 0x0018
    goto low_isr ;once a low priority interrupt is triggered jump to low_isr

;--------------------------------------------------------------------------
; Main Program -------------------------------------------------------------
;--------------------------------------------------------------------------
    org 0x0100 ; the following code is placed at address 0x0100 in program memory (Flash memory)
Main
    ; store the filter variables in a contiguous block in RAM starting at address 0x000
    cblock 0x000
    ; y_1 = y[n-1]; y_2 = y[n-2]; x_1 = x[n-1]; x_2 = x[n-2]
    x, y,a1,a2,b0,b1,b2, var1,var2, x_1, y_1, x_2, y_2
    endc

    ; set up b and a coefficients of the discrete system (y[n] = x[n]-0.3x[n-1]+0.3y[n-1]-0.75y[n-1])
    movlw .127
 	movwf b0 ; approx = 1 (exact value is 0.9922)
    movlw B'11011010'
 	movwf b1 ; approx = -0.3 (exact value is -0.3047) 
    movlw B'00000000'
 	movwf b2 ; = 0
    movlw B'00100110'
 	movwf a1 ; = approx 0.3 (exact value is 0.3047)
    movlw B'10100000'
 	movwf a2 ; = -0.75

    ; intialise the 'past value' variables to zero
    clrf y_1
    clrf y_2
    clrf x_1
    clrf x_2

    call micro_config ; configure pins,timers, ADC etc.

main_loop
    nop ; Just wait for a timer interrupt to be triggered
    goto main_loop

    
    ;----------------------------------------------------------------------------------------------------------
    ;-------multiply accumulate - multiply var1 by var2 and accumulate result in y   --------------------------
    ;------   this routine is used a lot to filter the signal -------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
mac
    ; pic18f only has 8X8 unsigned multiply - the following code analyses the result of an 8X8 unsigned multiply to produce a signed result
    movf var1, W
    mulwf var2 ; var1 * var2 -> PRODH:PRODL (var1 and var interpreted as     btfsc var2, 7 ; Test Sign Bit (NOTE: if var2 is negative (2's complement representation) then its unsigned interpretation is 256-var2 and then the result stored in PROD is var1*(256-var2) = var1*256-var1*var2
    btfsc var2, 7 ; Test Sign Bit
    subwf PRODH, F ; PRODH = PRODH - var1 (equivalent to PROD = PROD - var1*256)
    movf var2, W
    btfsc var1, 7 ;Test Sign Bit
    subwf PRODH, F ; PRODH = PRODH - var2

    ; The two most significant bits of PROD are sign bits so shift PRODH to the left and grab the most significant bit of PRODL to get the 8 most significant useful bits.
    rlncf PRODH,0 ; W contains PRODH shifted to the left by one
    movwf var2 ; using var2 as it is available (not for any other reason)
    bsf var2, 0
    BTFSS PRODL,7 ; set the most significant bit of PRODL as the least signifcant in W
    bcf var2, 0
    movf var2,W

    addwf y,f ; accumulate the result of multiplication in y. Note not handling overflow. Would also be better to accumulate those 7 bits discarded after the multiplication and round afterwards for a more accurate result

    return

    
    ;----------------------------------------------------------------------------------------------------------
    ;-----High Priority Interrupt Service Routine -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
    org 0x0200
hi_isr
    btfss INTCON, TMR0IF
    goto end_int
    bcf INTCON, TMR0IF; reset interrupt
     ;An interrupt has been set up to be generated whenever TMR0 goes from FFFFh to 0000h i.e. on overflow.
    ;Would like the timer overflow flag triggered every 1ms so will set timer to 0xffff - 1000 = 0xFC17
    movlw 0x17
    movwf TMR0L
    movlw 0xFC
    movwf TMR0H

	bsf ADCON0,GO; start ADC conversion

    ; wait for hardware to reset GO bit - indicating ADRES SFR is ready to read
adc_not_ready
	btfsc ADCON0, GO
    goto adc_not_ready

    clrf y

    movf y,W

    movf ADRESH,W
    addlw -128 ; account for dc offset. The input values from ADRESH will be in range 0-255. These values represent a signal that varies betwen 1 and -1: the ADC value of 255 is mapped to 1 and ADC value of 0 is mapped to -1; ADC value of 128 is mapped to 0.

    movwf x
    movwf var1
    movff b0,var2
    call mac ; multiply var1 by var2 and accumulate the result in y (mac - multiply accumulate)

    movff x_1, var1
    movff b1, var2
    call mac;

    movff x_2, var1
    movff b2, var2
    call mac;

    movff y_1, var1
    movff a1, var2
    call mac;

    movff y_2, var1
    movff a2, var2
    call mac

    ; update past values of the inputs and outputs to use on next iteration of the discrete system
    movff y_1, y_2
    movff y, y_1
    movff x_1, x_2
    movff x, x_1

    movf y,W
    addlw .128 ; account for dc offset
    movwf y
    goto spi_write ;write contents of y to SPI device
end_int
    retfie ;return and reset interrupts

    
    
    ;----------------------------------------------------------------------------------------------------------
    ;-------configure pins, ADC,timers and interrupts on the pic18f4620    -----------------------------------
    ;----------------------------------------------------------------------------------------------------------
micro_config
     ; configure LATD0-LATD3 as outputs and RD4-RD7 as inputs
    movlw 0xf0
    movwf TRISD
    clrf LATD ; turn off all LATD output pins

    ; SPI configuration ------------------------------------------------------------
    clrf TRISC
    ;bcf TRISC,3 ; pin 3 on PORTC used as SPI clock and should be configured as an output to operate in master mode
    ;bcf TRISC,5 ; pin 5 on PORTC used for SPI serial data out (SDO) and should be configured as an output
    movlw B'10110000' ; set up SPI control register see pg 163 for details
    movwf SSPCON1;
    bsf SSPSTAT,CKE; data transmitted on rising edge
    ; END SPI config ----------------------------------------------------------


    ; Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    ; Set Fosc = 8MHz, which gives Tcy = 0.5us
    movlw B'01110000'
    movwf OSCCON

    ; all channels set up for ADC - no particular reason why
    movlw B'00000001'
 	movwf ADCON1

    ; set tad so that capacitor on ADC can fully charge - see pg129
    movlw B'00100010'
 	movwf ADCON2

    clrf ADCON0; select analog channel 0;
    bsf ADCON0,ADON; //enable ADC

    bcf INTCON, GIE ;Disable global interrupts
    bcf T0CON, TMR0ON; turn off timer 0
    bsf INTCON, TMR0IE; Enable TIMER0 interupt

    ;set up 1:2 prescaler so that TMR0 SFR is incremented every 2 Tcy  i.e. 1us
    bcf T0CON,0
    bcf T0CON,1
    bcf T0CON,2

    bcf T0CON, T0CS; use internal instruction cycle clock
    bcf T0CON, T08BIT; use 16 bit mode
    bcf T0CON, PSA; turn on prescaler

    ; setup so that timer0 overflow is triggered quickly initially
    ; after the first trigger then set it up so that it is triggered at the rate you want in the high_isr routine
    movlw 0xFF
    movwf TMR0L
    movlw 0xFF
    movwf TMR0H

    bsf INTCON2, TMR0IP; ; Set the timer0 interrupt up as high priority
    bsf INTCON, GIE ;Enable global interrupts
    bsf T0CON, TMR0ON; turn on timer 0
    return

    ;----------------------------------------------------------------------------------------------------------
    ;-----WRITE contents in y to DAC (MCP4921) using SPI ------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
spi_write
    ;two bytes of data sent to spi daq (a 12-bit dac). First nibble of first byte is dac config settings; second nibble is
    ; the most significant 4 bits of 12bit numerical value. The second byte contains the 8 least signifcant bits of the 12-bit value

	bcf LATD, LATD1; // Select SPI DAC chip

    movf SSPBUF, W ;WREG reg = contents of SSPBUF (this clears BF) which will be set again after the data is transmitted
    ; load SSPBUFF with spi dac config data to be sent to SPI device
    ; First nibble of first byte sent to dac is dac config settings; second nibble is
    ; the most significant 4 bits of 12bit numerical value
    swapf y, f
    movlw 0x0f
    andwf y, W ; W no holds 4 most signicant bits in lower nibble

    iorlw 0x70 ; these are configuration bits for spi dac
    movwf SSPBUF

spi_wait1
    btfss SSPSTAT, BF ;Has data been received (transmit complete)?
    goto spi_wait1 ;No

    movf SSPBUF, W ;WREG reg = contents of SSPBUF (this clears BF) which will be set again after the data is transmitted
    ; load SSPBUFF with y data to be sent to SPI device

    movlw 0xf0
    andwf y, W ;
    movwf SSPBUF

spi_wait2
    btfss SSPSTAT, BF ;Has data been received (transmit complete)?
    goto spi_wait2 ;No

	bsf LATD, LATD1; // Select SPI DAC chip
    goto end_int


    ;----------------------------------------------------------------------------------------------------------
    ;-----Low Priority Interrupt Service Routine -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
    org 0x0300
low_isr
    nop ; put whatever you would like to do on low priority interrupt here
    retfie ;return and reset interrupts

    end ; End of ASM code
Categories: pic18f, Uncategorized

pic18f assembly example 5 – Sample ADC and pass through to DAC

May 20, 2014 Leave a comment
;-----------------------------------------------------------------------------------------------------------------------------
; This assembly code sets up a timer interrupt to be triggered every millisecond on the pic18f4620.
; When the interrupt service routine is called an ADC on channel 0 is performed and this value is sent a DAC (MCP4921) via a SPI protocol.
;
; Test cicruit used is same as at http://eleceng.dit.ie/daq_lite/build.html
;
; In the main part of the code the value associated with analog channel 0 is monitored in a continuous loop. If the value
;   is high then LATD2 is set high otherwise LATD2 is set low
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;-----------------------------------------------------------------------------------------------------------------------------
 
;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset

 ;NOTE: When an interrupt is triggered the micro jumps to 0x0008 for high priority and 0x0018 for low priority.
    org 0x0008
    goto hi_isr ;once a high priority interrupt is triggered jump to hi_isr
    org 0x0018
    goto low_isr ;once a low priority interrupt is triggered jump to low_isr

;--------------------------------------------------------------------------
; Main Program -------------------------------------------------------------
;--------------------------------------------------------------------------
    org 0x0100 ; the following code is placed at address 0x0100 in program memory (Flash memory)
Main

y  equ  0x20 ; y refers to a register at address 0x20
    call micro_config ; configure pins,timers, ADC etc.

main_loop
    nop ; Just wait for a timer interrupt to be triggered
    goto main_loop

    ;----------------------------------------------------------------------------------------------------------
    ;-----High Priority Interrupt Service Routine -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
    org 0x0200
hi_isr
    btfss INTCON, TMR0IF
    goto end_int
    bcf INTCON, TMR0IF; reset interrupt
     ;An interrupt has been set up to be generated whenever TMR0 goes from FFFFh to 0000h i.e. on overflow.
    ;Would like the timer overflow flag triggered every 1ms so will set timer to 0xffff - 1000 = 0xFC17
    movlw 0x17
    movwf TMR0L
    movlw 0xFC
    movwf TMR0H

	bsf ADCON0,GO; start ADC conversion

    ; wait for hardware to reset GO bit - indicating ADRES SFR is ready to read
adc_not_ready
	btfsc ADCON0, GO
    goto adc_not_ready

    movff ADRESH, y
    goto spi_write ;write contents of y to SPI device
end_int
    retfie ;return and reset interrupts

    
    
    ;----------------------------------------------------------------------------------------------------------
    ;-------configure pins, ADC,timers and interrupts on the pic18f4620    -----------------------------------
    ;----------------------------------------------------------------------------------------------------------
micro_config
     ; configure LATD0-LATD3 as outputs and RD4-RD7 as inputs
    movlw 0xf0
    movwf TRISD
    clrf LATD ; turn off all LATD output pins

    ; SPI configuration ------------------------------------------------------------
    clrf TRISC
    ;bcf TRISC,3 ; pin 3 on PORTC used as SPI clock and should be configured as an output to operate in master mode
    ;bcf TRISC,5 ; pin 5 on PORTC used for SPI serial data out (SDO) and should be configured as an output
    movlw B'10110000' ; set up SPI control register see pg 163 for details
    movwf SSPCON1;
    bsf SSPSTAT,CKE; data transmitted on rising edge
    ; END SPI config ----------------------------------------------------------


    ; Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    ; Set Fosc = 8MHz, which gives Tcy = 0.5us
    movlw B'01110000'
    movwf OSCCON

    ; all channels set up for ADC - no particular reason why
    movlw B'00000001'
 	movwf ADCON1

    ; set tad so that capacitor on ADC can fully charge - see pg129
    movlw B'00100010'
 	movwf ADCON2

    clrf ADCON0; select analog channel 0;
    bsf ADCON0,ADON; //enable ADC

    bcf INTCON, GIE ;Disable global interrupts
    bcf T0CON, TMR0ON; turn off timer 0
    bsf INTCON, TMR0IE; Enable TIMER0 interupt

    ;set up 1:2 prescaler so that TMR0 SFR is incremented every 2 Tcy  i.e. 1us
    bcf T0CON,0
    bcf T0CON,1
    bcf T0CON,2

    bcf T0CON, T0CS; use internal instruction cycle clock
    bcf T0CON, T08BIT; use 16 bit mode
    bcf T0CON, PSA; turn on prescaler

    ; setup so that timer0 overflow is triggered quickly initially
    ; after the first trigger then set it up so that it is triggered at the rate you want in the high_isr routine
    movlw 0xFF
    movwf TMR0L
    movlw 0xFF
    movwf TMR0H

    bsf INTCON2, TMR0IP; ; Set the timer0 interrupt up as high priority
    bsf INTCON, GIE ;Enable global interrupts
    bsf T0CON, TMR0ON; turn on timer 0
    return

    ;----------------------------------------------------------------------------------------------------------
    ;-----WRITE contents in y to DAC (MCP4921) using SPI ------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
spi_write
    ;two bytes of data sent to spi daq (a 12-bit dac). First nibble of first byte is dac config settings; second nibble is
    ; the most significant 4 bits of 12bit numerical value. The second byte contains the 8 least signifcant bits of the 12-bit value

	bcf LATD, LATD1; // Select SPI DAC chip

    movf SSPBUF, W ;WREG reg = contents of SSPBUF (this clears BF) which will be set again after the data is transmitted
    ; load SSPBUFF with spi dac config data to be sent to SPI device
    ; First nibble of first byte sent to dac is dac config settings; second nibble is
    ; the most significant 4 bits of 12bit numerical value
    swapf y, f
    movlw 0x0f
    andwf y, W ; W no holds 4 most signicant bits in lower nibble

    iorlw 0x70 ; these are configuration bits for spi dac
    movwf SSPBUF

spi_wait1
    btfss SSPSTAT, BF ;Has data been received (transmit complete)?
    goto spi_wait1 ;No

    movf SSPBUF, W ;WREG reg = contents of SSPBUF (this clears BF) which will be set again after the data is transmitted
    ; load SSPBUFF with y data to be sent to SPI device

    movlw 0xf0
    andwf y, W ;
    movwf SSPBUF

spi_wait2
    btfss SSPSTAT, BF ;Has data been received (transmit complete)?
    goto spi_wait2 ;No

	bsf LATD, LATD1; // Select SPI DAC chip
    goto end_int


    ;----------------------------------------------------------------------------------------------------------
    ;-----Low Priority Interrupt Service Routine -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
    org 0x0300
low_isr
    nop ; put whatever you would like to do on low priority interrupt here
    retfie ;return and reset interrupts

    end ; End of ASM code
Categories: pic18f, Uncategorized

pic18f assembly example 4 – sample Analog Channel on timer interrupt

May 20, 2014 Leave a comment
;------------------------------------------------------------------------------------------------------------------------------; This assembly code sets up a timer interrupt to be triggered every millisecond on the pic18f4620.
; This assembly code uses a timer interrupt to read an analog channel every 1ms.
; When the interrupt service routine is called an ADC on channel 0 is performed.
; In the main part of the code the value associated with analog channel 0 is monitored in a continuous loop. If the value
;   is high then LATD2 is set high otherwise LATD2 is set low
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;------------------------------------------------------------------------------------------------------------------------------

; TRY TO DO THE FOLLOWING IN ORDER TO DEVELOP YOUR PROGRAMMING SKILLS:
;    1. Change the sampling rate from 1kHz to 1Hz

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. The micro jumps to 0x0000 on a reset
    goto Main ;Jump to Main immediately after a reset
 
 ;NOTE: When an interrupt is triggered the micro jumps to 0x0008 for high priority and 0x0018 for low priority. 
    org 0x0008
    goto hi_isr ;once an high priority interrupt is triggered jump to hi_isr
    org 0x0018
    goto low_isr ;once an low priority interrupt is triggered jump to low_isr
    

;--------------------------------------------------------------------------
; Main Program -------------------------------------------------------------
;--------------------------------------------------------------------------
    org 0x0100 
Main
    goto pin_config ; configure the timers, ADC, IO pins, interrupts etc. 
    
main_loop   ; This loop runs forever waiting for interrupts to be triggered
    ; if the analog input is greater than Vss/2 then turn on LATD2 else turn it off
    BTFSC ADRESH, 7 ; ADRESH stores the 8 most significant bits after a 10 bit ADC conversion. Just check the most significant bit to see if the value is 'large' or 'small'
    goto set_LATD2
    goto reset_LATD2
set_LATD2
    BSF LATD, 2
    goto main_loop
reset_LATD2
    BCF LATD, 2
    goto main_loop   

    ;----------------------------------------------------------------------------------------------------------
    ;-------configure pins, ADC,timers and interrupts on the pic18f4620    -----------------------------------
    ;----------------------------------------------------------------------------------------------------------
pin_config
    ; configure LATD0-LATD3 as outputs and RD4-RD7 as inputs

    movlw 0xf0
    movwf TRISD
    
    clrf LATD ; turn off all LATD output pins
    BSF LATD,1 ; turn on LATD1
    
    ; Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    ; Set Fosc = 8MHz, which gives Tcy = 0.5us
    movlw B'01110000'
    movwf OSCCON 
    
    ; all channels set up for ADC - no particular reason why 
    movlw B'00000001'
 	movwf ADCON1
    
    ; set tad so that capacitor on ADC can fully charge - see pg129
    movlw B'00100010'
 	movwf ADCON2
    
    clrf ADCON0; select analog channel 0; 	
    BSF ADCON0,ADON; //enable ADC 
    
    BCF INTCON, GIE ;Disable global interrupts
    BCF T0CON, TMR0ON; turn off timer 0       
    BSF INTCON, TMR0IE; Enable TIMER0 interupt
     
    ;set up 1:2 prescaler so that TMR0 SFR is incremented every 2 Tcy  i.e. 1us
    BCF T0CON,0
    BCF T0CON,1
    bCF T0CON,2
    
    BCF T0CON, T0CS; use internal instruction cycle clock
    BCF T0CON, T08BIT; use 16 bit mode
    BCF T0CON, PSA; turn on prescaler
    
    ; setup so that timer0 overflow is triggered quickly
    ; after the first trigger then set it up so that it is triggered at the rate you want
    movlw 0xFF
    movwf TMR0L
    movlw 0xFF
    movwf TMR0H
    
    BSF INTCON2, TMR0IP; ; Set the timer0 interrupt up as high priority
    BSF INTCON, GIE ;Enable global interrupts  
    BSF T0CON, TMR0ON; turn on timer 0        
    
    goto main_loop
    
    ;----------------------------------------------------------------------------------------------------------
    ;-----High Priority Interrupt Service Routine -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------
    org 0x0200 
hi_isr
    BTFSS INTCON, TMR0IF
    goto end_int
    BCF INTCON, TMR0IF; reset interrupt
  
    ;An interrupt has been set up to be generated whenever TMR0 goes from FFFFh to 0000h i.e. on overflow.
    ;Would like the timer overflow flag triggered every 1ms so will set timer to 0xffff - 1000 = 0xFC17
    movlw 0x17
    movwf TMR0L
    movlw 0xFC
    movwf TMR0H
    
	BSF ADCON0,GO; start ADC conversion

    ; wait for hardware to reset GO bit - indicating ADRES SFR is ready to read
adc_not_ready    
	BTFSC ADCON0, GO 
    goto adc_not_ready
	
end_int
    retfie ;return and reset interrupts
 

    ;----------------------------------------------------------------------------------------------------------
    ;-----Low Priority Interrupt Service Routine  -------------------------------------------------------------
    ;----------------------------------------------------------------------------------------------------------   
    org 0x0300 
low_isr
    nop
    retfie ;return and reset interrupts

    end ; End of ASM code
Categories: pic18f, Uncategorized

pic18f assembly example 3 – an interrupt example

May 20, 2014 Leave a comment
;-----------------------------------------------------------------------------------------------------------------------------
; This assembly code uses a timer interrupt to set LATD2 high for 50ms then low for 50ms, repeatedly.
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;---------------------------------------------------------------------


; TRY TO DO THE FOLLOWING IN ORDER TO DEVELOP YOUR PROGRAMMING SKILLS:
;    1. Use the counter register set up in the code to change the on-off rate from 10Hz to 1Hz

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)

    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset
 
 ;NOTE: When an interrupt is triggered the micro jumps to 0x0008 for high priority and 0x0018 for low priority. 
    org 0x0008
    goto hi_isr
    org 0x0018
    goto low_isr
 
;--------------------------------------------------------------------------
; Main Program -------------------------------------------------------------
;--------------------------------------------------------------------------
    org 0x0100 
Main
counter  equ  0x10 ; counter refers to a register at address 0x10
    clrf counter ; clear the counter
    
    ; configure LATD0-LATD3 as outputs and RD4-RD7 as inputs
    banksel TRISD
    movlw 0xf0
    movwf TRISD
    
    clrf LATD ; turn off all LATD output pins
    bsf LATD,3 ; turn on LATD3
    
    ; Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    ; Set Fosc = 8MHz, which gives Tcy = 0.5us
    movlw B'01110000'
    movwf OSCCON 

    bcf INTCON, GIE ;Disable global interrupts
    bcf T0CON, TMR0ON; turn off timer 0       
    bsf INTCON, TMR0IE; Enable TIMER0 interupt
     
    ;set up 1:2 prescaler so that TMR0 SFR is incremented every 2 Tcy  i.e. 1us
    bcf T0CON,0
    bcf T0CON,1
    bcf T0CON,2
    
    bcf T0CON, T0CS; use internal instruction cycle clock
    bcf T0CON, T08BIT; use 16 bit mode
    bcf T0CON, PSA; turn on prescaler
    
    ; setup so that timer0 overflow is triggered quickly
    ; after the first trigger then set it up so that it is triggered at the rate you want
    movlw 0xFF
    movwf TMR0L
    movlw 0xFF
    movwf TMR0H
    
    bsf INTCON2, TMR0IP; ; Set the timer0 interrupt up as high priority
    bsf INTCON, GIE ;Enable global interrupts  
    bsf T0CON, TMR0ON; turn on timer 0    
    
loop   
    nop; ;loop waiting for interrupts to be trigged
    goto loop   

    ;-----High Priority Interrupt Service Routine -------------------------------------------------------------
    org 0x0200 
hi_isr
    btfss INTCON, TMR0IF
    goto end_int
    bcf INTCON, TMR0IF; reset interrupt
    ;An interrupt has been set up to be generated whenever TMR0 goes from FFFFh to 0000h i.e. on overflow.
    ;Would like timer overflow flag triggered every 500ms so will set timer to 0xffff - 1000 = 0x£CAF
    movlw 0xAF
    movwf TMR0L
    movlw 0x3C
    movwf TMR0H
    
    incf counter, f ; increment the counter
    
    ;invert LATD2
    movlw 0x4
    xorwf LATD,F

end_int
    retfie ;return and reset interrupts
 

    ;-----Low Priority Interrupt Service Routine  -------------------------------------------------------------   
    org 0x0300 
low_isr
    nop
    retfie ;return and reset interrupts

    end ; End of ASM code
Categories: pic18f, Uncategorized

pic18f assembly example 2 – digital output high-low

May 20, 2014 Leave a comment
 
;-----------------------------------------------------------------------------------------------------------------------------
; This assembly code uses a timer to set LATD2 high for 50ms then low for 50ms, repeatedly
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;------------------------------------------------------------------------------------------------------------------------------

; TRY TO DO THE FOLLOWING IN ORDER TO DEVELOP YOUR PROGRAMMING SKILLS:
;    1. Change the on-off rate from 10Hz to 100 Hz
;    2. Change the on-off rate from 10Hz to 1.25Hz by changing the timer prescaler  

;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset
 
;--------------------------------------------------------------------------
; Main Program
;--------------------------------------------------------------------------

    org 0x0100 
Main
    ; configure LATD0-LATD3 as outputs and RD4-RD7 as inputs
    movlw 0xf0
    movwf TRISD 
    clrf LATD
    bsf LATD,2 ; turn on LATD2
    bsf LATD,3 ; turn on LATD3
    
    ; Set clock frequency (section 2 of the PIC18F4620 Data Sheet)
    ; Set Fosc = 8MHz, which gives Tcy = 0.5us
    movlw B'01110000'
    movwf OSCCON 
    
    ;------- Set up timer0 to increment every 1us
    ;set up 1:2 prescaler so that TMR0 SFR is incremented every 2 Tcy  i.e. 1us
    bcf T0CON,0
    bcf T0CON,1
    bcf T0CON,2
    bcf T0CON, T0CS; use internal instruction cycle clock
    bcf T0CON, T08BIT; use 16 bit mode
    bcf T0CON, PSA; turn on prescaler
    
    ; setup so that timer0 overflow is triggered quickly
    ; after the first trigger then set it up so that it is triggered at the rate you want
    movlw 0xFF
    movwf TMR0L
    movlw 0xFF
    movwf TMR0H

    bcf INTCON, TMR0IF; reset timer overflow flag
    BSF T0CON, TMR0ON; turn on timer 0    
        
loop  
    ; check if the timer0 overflow flag has been set
    BTFSS INTCON, TMR0IF
    goto loop
    bcf INTCON, TMR0IF; reset timer overflow flag
    ;Could set up an interrupt to be generated whenever TMR0 goes from FFFFh to 0000h i.e. on overflow.
    ;The timer is incremented every 1us.
    ;Would like timer overflow flag triggered every 50ms so will set timer to 0xffff - 50000 = 0x3CAF
    movlw 0xAF
    movwf TMR0L
    movlw 0x3C
    movwf TMR0H
    
    ;invert LATD2
    movlw 0x4
    XORWF LATD,F

    goto loop   
    END
Categories: pic18f, Uncategorized

pic18f assembly example 1 – digital output controlled by digital input

May 20, 2014 Leave a comment
;-----------------------------------------------------------------------------------------------------------------------------
; This assembly code monitors RD4 (pin 27)  on the pic18f4620. If RD4 is high LATD2 (pin 21) is set high otherwise LATD2 is set low
;
; by David Dorran (https://dadorran.wordpress.com) May 2014
;-----------------------------------------------------------------------------------------------------------------------------

; TRY TO DO THE FOLLOWING IN ORDER TO DEVELOP YOUR PROGRAMMING SKILLS:
;    1. change the digital input monitored to RD3
;    2. Set LATD2 high if both RD3 and RD4 are high


;configure the  assembler directive 'list' so as to set processor to 18f4620 and set the radix used for data expressions to decimal (can be HEX|DEC|OCT)
    list p=18f4620, r=DEC
    #include <p18f4620.inc>
; configure the micro so that the watchdog timer is off, low-voltage programming is off, master clear is off and the clock works off the internal oscillator
    config WDT=OFF, LVP=OFF, MCLRE=OFF, OSC=INTIO67
;The org directive tells the compiler where to position the code in memory
    org 0x0000 ;The following code will be programmed in reset address location i.e. This is where the micro jumps to on reset
    goto Main ;Jump to Main immediately after a reset
 
 ;NOTE: When an interrupt is triggered the micro jumps to 0x0008 for high priority and 0x0018 for low priority. For this reason you 
 ;don't want to place any 'code' at these locations and this is why the you just jump to somewhere else in memory after a reset. 
 ;If interrupts aren't used then there's no problem just moving the Main code to address 0x0000
 

;--------------------------------------------------------------------------
; Main Program
;--------------------------------------------------------------------------
    org 0x0020 ;The main code section will be programmed starting from address 20H.
Main
    ; configure D0-D3 as outputs and D4-D7 as inputs by modifying the TRISD register
    movlw 0xf0
    movwf TRISD 
    CLRF LATD ; turn off all the outputs
    
main_loop
    BTFSS PORTD,4 ; if RD4 is set skip the next line
    goto turn_LATD2_off
        
    bsf LATD,2 ; turn on LATD2 - we wont reach this line in loop if RD4 is low
    goto main_loop
    
turn_LATD2_off   
    bcf LATD,2 ; turn on LATD2        
    goto main_loop   

    END

Categories: pic18f, Uncategorized