WJEC Assembler Code Tutorials

Please ensure you have read the Getting Started page before using these tutorials, so that you already know how to on-screen simulate and download a program.

WJEC / EDUQAS A Level Assembler – Overview

WJEC / EDUQAS A Level Assembler – Getting Started

 

Hardware

All tutorials can be simulated on-screen or downloaded to a real-life PICAXE-18M2 chip on the AXE056 or AXE091 boards (or on a home-made circuit on a breadboard).

If using the AXE056 project board to run a PIC16F88 (programmed via a conventional PIC programmer) instead of using the simpler PICAXE-18M2 system, please use this assembler template.

 

Tutorial 1 - Flash LED on and off

A student mnemonics reminder sheet can be downloaded here.

Type in and simulate / download the following example to flash an LED on pin B.1

init: 
    clrf   PORTB        ; clear PORTB output latches
    bsf    STATUS,RP0   ; memory page 1
    movlw  b'11111111'  ; set portA pins to input 
    movwf  TRISA        ; write to TRIS register 
    movlw  b'00000000'  ; set portB pins to output 
    movwf  TRISB        ; write to TRIS register 
    bcf    STATUS,RP0   ; memory page 0
main: 
    bsf    PORTB,1      ; output B.1 high 
    call   wait1000ms   ; delay 1000 milliseconds 
    bcf    PORTB,1      ; output B.1 low 
    call   wait1000ms   ; delay 1000 milliseconds 
    goto   main

Tip - to help check there are no typing mistakes click the ‘Syntax Check’ button.If you get a syntax error on line 3 make sure the PICAXE BASIC language pre-processor is switched off (installation step 5 here).

Key points:

  • All pins are inputs upon chip reset. TRISB startup value is therefore b'11111111'.
  • Any pin to be used as an output must therefore have it’s TRIS bit set to 0 during initialisation. Remember 1 looks like I=Input, 0 looks like O=Output.
  • Before converting to an output the PORTB bit should be cleared, so that the output always starts up in a known state.
  • TRISA and TRISB registers are on register memory page 1. All other registers used in these tutorials are on page 0. Use bsf/bcf STATUS,RP0 to navigate pages. 
  • Use predefined 'wait1000ms' procedure to create time delay.
  • A label such as 'main' requires a colon when defining the program position, but does not use a colon when in a command (such as goto, call etc.)
  • Labels cannot be PICAXE commands such as 'loop', so instead use unique labels such as 'loop1', 'loop2' etc. 

 

Tutorial 2 - Flash 3 LEDs on and off

Type in and simulate / download the following example to flash LEDs on pins B.2, B.1, B.0

init: 
    clrf   PORTB        ; clear PORTB output latches
    bsf    STATUS,RP0   ; memory page 1
    movlw  b'11111111'  ; set portA pins to input 
    movwf  TRISA        ; write to TRIS register 
    movlw  b'00000000'  ; set portB pins to output 
    movwf  TRISB        ; write to TRIS register 
    bcf    STATUS,RP0   ; memory page 0
main: 
    movlw  b'00000010'  ; set pin B.1 high, others low 
    movwf  PORTB        ; write to PORT register 
    call   wait1000ms   ; delay 1000 milliseconds 
    movlw  b'00000101'  ; set pin B.1 low, others high 
    movwf  PORTB        ; write to PORT register 
    call   wait1000ms   ; delay 1000 milliseconds 
    goto   main

 Key points:

  • When a PORT is written to using movwf all output pins in the port are written simultaneously.

 

Tutorial 3 - Flash LED ten times then stop

Type in and simulate / download the following example to flash an LED on pin B.1 ten times

init: 
    clrf   PORTB        ; clear PORTB output latches
    bsf    STATUS,RP0   ; memory page 1
    movlw  b'11111111'  ; set portA pins to input 
    movwf  TRISA        ; write to TRIS register 
    movlw  b'00000000'  ; set portB pins to output 
    movwf  TRISB        ; write to TRIS register 
    bcf    STATUS,RP0   ; memory page 0
main:
    movlw  d'10'        ; move decimal 10 into working register
    movwf  B1           ; write to B1 register 
loop1: 
    bsf    PORTB,1      ; output B.1 high 
    call   wait100ms    ; delay 100 milliseconds 
    bcf    PORTB,1      ; output B.1 low 
    call   wait100ms    ; delay 100 milliseconds 
    decfsz B1,F         ; decrement B1 and skip if zero 
    goto   loop1        ; not zero so loop back again 
loop2: 
    goto   loop2

 Key points:

  • decfsz decrements the specified register value and skips if now zero.
  • decfsz needs to use target of F in this situation (F = result into same register file, W = result into the working register)
  • The never ending loop at the end of the program means a power reset is required to re-run the program.
  • If the watchdog timer is enabled a 'clrwdt' command is required within loop2 to prevent a timeout.

 

Tutorial 4 - Make LED follow input switch

Type in and simulate / download the following example to make LED on pin B.1 follow push switch on A.7. Make sure the switch has a 10k pull-down resistor so that it does not float when not pushed. To simulate an input left-click on the A.7 pin in the simulation panel.

init: 
    clrf   PORTB        ; clear PORTB output latches
    bsf    STATUS,RP0   ; memory page 1
    movlw  b'11111111'  ; set portA pins to input 
    movwf  TRISA        ; write to TRIS register 
    movlw  b'00000000'  ; set portB pins to output 
    movwf  TRISB        ; write to TRIS register 
    bcf    STATUS,RP0   ; memory page 0
main: 
    btfsc  PORTA,7      ; skip if A.7 is clear 
    bsf    PORTB,1      ; output B.1 high 
    btfss  PORTA,7      ; skip if A.7 is set
    bcf    PORTB,1      ; output B.1 low 
    goto   main

 Key points:

  • btfsc / btfss skip the next instruction if the specified bit is clear (=0) / set (=1)

 

Tutorial 5 - Flash LED after 5 switch presses

Type in and simulate / download the following example to flash the LED on pin B.1 after switch on A.7 is pressed 5 times.  Make sure the switch has a 10k pull-down resistor so that it does not float when not pushed.

init: 
    clrf   PORTB        ; clear PORTB output latches
    bsf    STATUS,RP0   ; memory page 1
    movlw  b'11111111'  ; set portA pins to input 
    movwf  TRISA        ; write to TRIS register 
    movlw  b'00000000'  ; set portB pins to output 
    movwf  TRISB        ; write to TRIS register 
    bcf    STATUS,RP0   ; memory page 0

main: 
    movlw  d'5'         ; move decimal 5 into working register
    movwf  B1           ; write to B1 register

loop1: 
    call   wait10ms     ; delay 10 milliseconds to debounce
    btfss  PORTA,7      ; test switch 
    goto   loop1        ; not high so loop back again

loop2: 
    call   wait10ms     ; delay 10 milliseconds to debounce
    btfsc  PORTA,7      ; test switch is back off again 
    goto   loop2        ; not off yet so loop back again

    decfsz B1,F         ; decrement B1 and skip if zero
    goto   loop1        ; not zero yet loop back again

    bsf    PORTB,1      ; output B.1 high
    call   wait1000ms   ; delay 1000 milliseconds 
    bcf    PORTB,1      ; output B.1 low 
    goto   main         ; loop back to start 

 Key points:

  • To overcome switch bounce a small delay is used before testing for the switch off again
  • With each switch press the register B1 is decremented
  • decfsz decrements the specified register value and skips if result is now zero.

 

Tutorial 6 - Using an interrupt

Type in and simulate / download  the following example to flash the LED on pin B.1 every second. An interrupt on A.7 (switch) going high activates  a call to the ISR sub procedure as soon as the switch is pushed. During the interrupt the LED on B.2 will flash quickly. Make sure the A.7 switch has a 10k pull-down resistor so that it does not float when not pushed.

init: 
    clrf   PORTB          ; clear PORTB output latches
    bsf    STATUS,RP0     ; memory page 1
    movlw  b'11111111'    ; set portA pins to input 
    movwf  TRISA          ; write to TRIS register 
    movlw  b'00000001'    ; B.0 as input, other portB pins to output 
    movwf  TRISB          ; write to TRIS register
    bcf    STATUS,RP0     ; memory page 0

main:
    bsf    INTCON,INT0IE  ; set external interrupt enable
    bsf    INTCON,GIE     ; enable all interrupts 

loop1:
    bsf    PORTB,1        ; output B.1 high
    call   wait1000ms     ; delay 1000 milliseconds
    bcf    PORTB,1        ; output B.1 low
    call   wait1000ms     ; delay 1000 milliseconds 
    goto   loop1           ; loop forever

    W_SAVE EQU B20

interrupt:
    movwf  W_SAVE         ; save working register into register so can restore later 

    btfss  INTCON,INT0IF  ; check correct interrupt has occurred
    retfie                ; no, so return and re-enable GIE

loop2:
    bsf    PORTB,2        ; output B.2 high
    call   wait100ms      ; delay 100 milliseconds
    bcf    PORTB,2        ; output B.2 low 
    call   wait100ms      ; delay 100 milliseconds
    btfsc  PORTA,7        ; NB- change to PORTB,0 for a 16F88

    goto   loop2          ; no so loop again
    
    bcf    INTCON,INT0IF  ; clear interrupt flag 

    movf   W_SAVE,W       ; restore saved value back to working register 
    retfie                ; return and re-enable GIE

 Key points:

  • To enable an interrupt both the GIE (Global Interrupt Enable) and INT0IE (int 0 interrupt enable) bits must both be set. However to prevent glitches GIE should only be set after other IEs have already been set, not in the same instruction.
  • On the PICAXE-18M2 the external interrupt is on A.7 (not B.0 as for a PIC16F88)
  • When the interrupt occurs it immediately sets the appropriate flag (INT0IF) and then calls the ISR (interrupt service routine) labelled interrupt:
  • Within the ISR it is essential to save the working register value, as the value will be corrupted (by being used) within the ISR. Note that a simplified version is shown here - in real projects it is also necessary to save some other registers like STATUS.
  • Before returning from the ISR the interrupt flag (INT0IF) should be cleared and the working register value restored.
  • The retfie command re-enables the interrupt enable bit automatically (i.e. sets INTCON,GIE) upon the return
 

Tutorial 7 (extension) - Read analogue values

Type in and simulate / download the following example to read LDR (A.0), pot (A.1) and temperature (A.2) and then display the pot (A.1) value in binary on 8 LEDs (portB). If using the real-life chip 'call debug' will send all 3 results to the computer screen for display, if simulating right-click on the pin in the simulation panel to alter the analogue value.

init: 
    clrf   PORTB        ; clear PORTB output latches
    bsf    STATUS,RP0   ; memory page 1
    movlw  b'11111111'  ; set portA pins to input 
    movwf  TRISA        ; write to TRIS register 
    movlw  b'00000000'  ; set portB pins to output 
    movwf  TRISB        ; write to TRIS register 
    bcf    STATUS,RP0   ; memory page 0
main: 
    call   readadc0     ; readadc A.0 into register B0  
    call   readadc1     ; readadc A.1 into register B1 
    call   readtemp2    ; read temperature A.2 into register B2  
    call   debug        ; send values to computer screen (real-life chip)
    movf   B1,W         ; get ADC on pin A.1 result 
    movwf  PORTB        ; display as binary on 8 LEDs 
    call   wait100ms    ; delay 100 milliseconds 
    goto   main

 Key points:

  • Predefined readadc/readtemp subroutines read the analogue values 
  • Predefined debug routines sends values serially up cable for computer display

 

Tutorial 8 (extension) - Switch LED on when analogue value reaches a threshold

Type in and simulate / download the following example to make LED on pin B.1 switch on at an analogue threshold of 100 on A.1 (pot).

init: 
    clrf   PORTB        ; clear PORTB output latches
    bsf    STATUS,RP0   ; memory page 1
    movlw  b'11111111'  ; set portA pins to input 
    movwf  TRISA        ; write to TRIS register 
    movlw  b'00000000'  ; set portB pins to output 
    movwf  TRISB        ; write to TRIS register 
    bcf    STATUS,RP0   ; memory page 0
main: 
    call   readadc1     ; read analogue A.1 into register B1  
    call   debug        ; send values to computer screen
    movf   B1,W         ; mov register B1 into working register  
    sublw  d'100'       ; subtract W from 100
    btfsc  STATUS,C     ; if Carry is clear ADC >= 100 
    bsf    PORTB,1      ; output B.1 high 
    btfss  STATUS,C     ; if Carry is set ADC < 100
    bcf    PORTB,1      ; output B.1 low 
    goto   main

 Key points:

  • Note that sublw is subtract working register from literal (result = literal - WREG), not the other way around
  • if a subtraction overflows (ie is < 0 ) the C carry bit in STATUS is set, otherwise it is cleared. By testing the C bit we therefore know if the reading is higher or lower than the threshold value (set to d'100' in this example).