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).