As you may have guessed, this tutorial will show you how to make your PIC18F452 make an LED blink, programming with assembler.
First off, you should have a kind of standard header put together from the last tutorial. If not, go to the Basic Assembler tutorial.
There's a bit more wiring to do, but it's easy. Take a a 220 Ohm resistor and connect one end to a port pin on the pic. I used pin D1 since it's conveniently in the corner. Connect the other end of the resistor to an empty row of the breadboard.
Now take an LED and connect it to the resistor and to ground, with the ground pin (usually the longer one) in ground. That's it.
So you have the setup from the last tutorial. Modify the descriptive header for this program. Note this setup is for a 4MHz external crystal clock, if yours is different, change the configuration to suit.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ledblink.asm: Blinks an LED on port D1 ;; ;; By Ian Smith-Heisters ian{remove this}\at 0x09{remove this}.com ;; 12-04-2004: Started ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; title "Hello World" List p=18f452,f=inhx32 #include <p18f452.inc> __CONFIG _CONFIG1H, _OSCS_ON_1H & _XT_OSC_1H ; External Clock on OSC1 & OSC2 __CONFIG _CONFIG2L, _BOR_ON_2L & _BORV_20_2L & _PWRT_OFF_2L ; Brown out reset on at 2.0V, no power-up timer __CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_128_2H ; watchdog off, postscaler count to 128 __CONFIG _CONFIG3H, _CCP2MX_ON_3H ; CCP2 pin Mux enabled. What is this? __CONFIG _CONFIG4L, _STVR_ON_4L & _LVP_ON_4L & _DEBUG_OFF_4L ; Stack under/overflow reset on, LVP on, debug off __CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L ; all protection off __CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H __CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L __CONFIG _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H __CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L __CONFIG _CONFIG7H, _EBTRB_OFF_7H org 0x0000
If we just turn the LED on and off as fast as possible we won't see anything, so we're going to need to turn it on, wait, then turn it off, and wait, then repeat. In order to wait we need to have a delay loop. The delay loop will just decrement a number until the number is zero, then move on. The size of the decremented number will determine how long the delay is. Since the processor does 4 million operations per second at 4MHz, we need a big number. The largest number one byte can hold is 255. Our delay loop will be built with labels, goto statements to loop back, and conditionals that will skip the goto when we've done enough looping.
First we need to define the variables that we'll decrement. We'll use two:
COUNT1 equ 0x01 COUNT2 equ 0x02
We'll get to the actual loop in a bit. Next we need to set up our output port. On the PIC there is an 8 bit register for each port. Each bit corresponds to a pin on the port. Setting a pin high sets the port to input, setting a bit low sets the pin to output. These registers are called TRISA, TRISB etc. We're only using one pin, but we might as well set them all to output. There is some discussion about what one should do with unused pins, but I haven't had a problem so far, so we'll do it this way.
clrf TRISD ; set all bits in TRISD to zero.
Most PIC programs have a main loop so that they continue running, instead of running once and finishing. To do this make a label named "Main" and a goto statement to that label, like this:
Main goto Main
The main body of your code will go there. It can break out to go into subroutines, but then it returns to this main loop.
To turn on the LED you'll set the pin it's on high, then to turn it off you'll set the pin low. The code to do that should go within the main loop. To set one pin you set a bit using bsf in a register corresponding to the port the pin is part of.
Main bsf PORTD, RD1 ; set bit RD1 in the PORTD register bcf PORTD, RD1 ; clear bit RD1 in the PORTD register goto Main
I hope you guessed that this presents the problem of turning the LED on and off too fast for the human eye to see, so we'll write the delay loop.
setf COUNT1 ; set all the bits in COUNT1, eg. set it equal to 255 setf COUNT2 Loop1 ; this is a label since it's in the first column decfsz COUNT1, F ; decrement COUNT1, store result in COUNT1, skip next line if COUNT1 is zero goto Loop1 ; loop - gets skipped if COUNT1 == 0 setf COUNT1 ; reinit COUNT1 decfsz COUNT2, F goto Loop1 return
As you may have noticed, it's a nested loop. Essentially it's looping over COUNT2, each iteration it loops over COUNT1.
We could paste this right after the bsf and the bcf to have the delay, but that would be messy and you need to learn how to do a subroutine. So add put the delay code at the end of the file and put a label on the line before it starts called "Delay". We'll call the subroutine with the 'call' instruction after the bsf and the bcf. End the file with the end instruction, so the whole file looks like this:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ledblink.asm: Blinks an LED on port D1 ;; ;; By Ian Smith-Heisters ian{remove this}\at 0x09{remove this}.com ;; 12-04-2004: Started ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; title "Hello World" List p=18f452,f=inhx32 #include <p18f452.inc> __CONFIG _CONFIG1H, _OSCS_ON_1H & _XT_OSC_1H ; External Clock on OSC1 & OSC2 __CONFIG _CONFIG2L, _BOR_ON_2L & _BORV_20_2L & _PWRT_OFF_2L ; Brown out reset on at 2.0V, no power-up timer __CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_128_2H ; watchdog off, postscaler count to 128 __CONFIG _CONFIG3H, _CCP2MX_ON_3H ; CCP2 pin Mux enabled. What is this? __CONFIG _CONFIG4L, _STVR_ON_4L & _LVP_ON_4L & _DEBUG_OFF_4L ; Stack under/overflow reset on, LVP on, debug off __CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L ; all protection off __CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H __CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L __CONFIG _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H __CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L __CONFIG _CONFIG7H, _EBTRB_OFF_7H org 0x0000 COUNT1 equ 0x01 COUNT2 equ 0x02 clrf TRISD ; set all bits in TRISD to zero. Main bsf PORTD, RD1 ; set bit RD1 in the PORTD register call Delay bcf PORTD, RD1 ; clear bit RD1 in the PORTD register call Delay goto Main Delay setf COUNT1 ; set all the bits in COUNT1, eg. set it equal to 255 setf COUNT2 Loop1 ; this is a label since it's in the first column decfsz COUNT1, F ; decrement COUNT1, store result in COUNT1, skip next line if COUNT1 is zero< goto Loop1 ; loop - gets skipped if COUNT1 == 0 setf COUNT1 ; reinit COUNT1 decfsz COUNT2, F goto Loop1 return end
Burn this into your chip and it should blink the LED on and off forever.