Here is the next batch, there is still a lot of editing to do and the figures are not in place
The two LEDs to to lines 0 and 1
Change the program so that it looks like the following:
Code:
con
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
pub main
cognew(@toggle, 0)
dat
org 0 'start of the program storage locations
toggle mov dira, pin 'pin now sets lines 0 and 1 as outputs
mov time, cnt 'sets the delay time to 10m cycles
add time, #9 'adds 9 to the time count
:loop waitcnt time, delay 'the wait instruction
mov outa, pin0on 'sets output 0 on and 1 off
waitcnt time, delay 'the wait instruction
mov outa, pin1on 'sets output 1 on and 0 off
jmp #:loop 'go back and loop.
pin long %00000000_00000000_00000000_00000011 'used to set 0 and 1 as outputs
kine0on long %00000000_00000000_00000000_00000001 'used to turn on line 0
line1on long %00000000_00000000_00000000_00000010 'used to turn on line 1
delay long 10_000_000 'delay cycles defined
time res 1 'storage location for time
Program XXX
Blinking lines alternately.
The above program XXX will blink the LEDs on lines 0 and 1 on and off alternately. This code is easy to read but it is archaic and it is not the best way to do it. An only slightly better way to write this program is shown next in Program XXX. Again the changes are to the looped part of the program
Code:
con
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
pub main
cognew(@toggle, 0)
dat
org 0 'start of the program storage locations
toggle mov dira, pin 'pin now sets lines 0 and 1 as outputs
mov time, cnt 'sets the delay time to 10m cycles
add time, #9 'adds 9 to the time count
:loop waitcnt time, delay 'the wait instruction
or outa, %01 'sets output 0 on and 1 off
waitcnt time, delay 'the wait instruction
or outa, %10 'sets output 1 on and 0 off
jmp #:loop 'go back and loop.
delay long 10_000_000 'delay cycles defined
time res 1 'storage location for time
Program XXX a slightly better way to write program XXX
Blinking lines 0 and 1 alternately.
When you run the above program you will see that two LEDS can be turned on and off alternately with the above register assignments. The program shows you how to set the lines as Inputs and Outputs with simple statements and how to affect the I/O operation of the pins. However this is both the tedious and archaic way of doing it. A number of better ways to do it follow. In these examples we are using shorthand notation and binary math techniques to manipulate the registers. Handling registers in this way is important in almost all the things that we will be doing. The techniques we use next use the following principles:
There are three basic things we can do to one bit in one operation.
Change it from a low to high-level (0-->1)
Change it from a high to low-level (1-->0)
Invert its state, in other words toggle the bit. Make it high if low and low if high.
Assume that the current 4 bits under consideration are %1010
We can change any bit in this group to high with the ora operation on that bit.
1010 current content
ora 0001 addresses the last bit
1011 result: the last bit is turned on (changed from 0 to 1)
If we want to turn a bit off we can do it with the andn operation
1010 current content
andn 0010 addresses the third bit
1000 result: the third bit is turned off (changed from 1 to 0)
If we want to change (or toggle) the state of a bit we use the xor command
1010 current content
xor 0011 addresses the third and fourth bits.
1001 result: the third and fourth bit are toggled (changed from 1 to 0 and 0 to 1)
Now let us look at the looping part of the code in our program and see how we can use the above commands to make the LEDS flash alternatively.
The simplest way is to first set the two bits that control the LEDs to 01 or 10 with the outa command and then do a toggling procedure with the xor command.
Code:
dat
org 0 'start of the program storage locations
toggle mov dira, #%11 'pin now sets lines 0 and 1 as outputs
mov time, cnt 'sets the delay time to 10m cycles
add time, #20 'adds 12 to the time count
mov outa, #%01 'sets the two bits
:loop waitcnt time, delay
xor outa, #%11 'toggles bits 0 and 1
jmp #:loop
Now that we understand the simplest of bit manipulations and the creation of the simplest of loops. Let us expand on these idea to learn how to undertake some other often used techniques.
Shifting the bits in a register left and right.
The two instructions used to shift bits left and right are SHL and SHR. Bits can be shifted from 1 to 32 places within the 32 bit registers.
If we use a bit shifting technique to move the ON bit back and forth to alternate the coming on of the two bits we have been considering above, the data part of program would look like the listing shown in Program XXX. Here we have to wait after each shift to duplicate the effect in program XXX above.
Code:
dat
org 0 'start of the program storage locations
toggle mov dira, #%11 'pin now sets lines 0 and 1 as outputs
mov time, cnt 'sets the delay time to 10m cycles
add time, #20 'adds 12 to the time count
mov outa, #%01 'sets the two bits
:loop waitcnt time, delay 'delay
shl outa, #%1 'shift left one bit
waitcnt time, delay 'delay
shr outa, #%1 'shift back right one bit
jmp #:loop
Program XXX
Controlling off the LEDs by shifting the active bit left and right.
Creating Subroutines/Methods
PASM has the waitcnt command for creating pauses but we are going to ignore that in the immediate discussion.
First let us see how we call a subroutine in PASM. We will make the wait a part of a subroutine and then call the subroutine whenever we need to wait. This needs to be done after each shift command. The complete code for this is
Code:
con
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
pub main
cognew(@toggle, 0)
dat
org 0 'start of the program storage locations
toggle mov dira, #%11 'pin now sets lines 0 and 1 as outputs
mov time, cnt 'sets the delay time to 10m cycles
add time, #200 'adds 12 to the time count
mov outa, #%01 'sets the two bits
:loop
call #clkdelay 'call the delay subroutine
shl outa, #%1 'shift left one bit
call #clkdelay 'call the delay subroutine
shr outa, #%1 'shift back right one bit
jmp #:loop
clkdelay waitcnt time, delay 'the delay subroutine
clkdelay_ret ret 'return for delay subroutine
delay long 10_000_000 'delay cycles defined
time res 1 'location for time
Program XXX
Places the waitcnt command in a subroutine.
Often we need to be able to do something a fixed number of times and then do something else. In order to do this we need to learn how to set up counters. Let us use a counter that uses waits of one quarter (0.25 seconds) repeatedly to make up the delays we need in our programs from time to time. The wait period will need to run through 80_000_000_/4 cycles of an empty loop before exiting. We will then place this method in our blink routine to make sure it works.
Again: our clock is running at 80 MHz, so one second takes 80_000_000 cycles and 0.25 seconds take 20_000_000 cycles. We also know that the average instruction takes 4 clock cycles. So our 0.25 second subroutine has to have 5_000_000 iterations through its loop.(Our counts are not exact because we are not counting every instruction but it will be close enough for what we are trying to learn at this time. We will learn to count exact cycles later on in the book)
Code:
con
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
pub main
cognew(@toggle3, 0)
dat
org 0 'start of the program storage locations
toggle3 mov dira, #%11 'pin now sets lines 0 and 1 as outputs
mov outa, #%01 'sets the two bits
:loop
call #clkdelay 'call the delay subroutine
shl outa, #%1 'shift left one bit
call #clkdelay 'call the delay subroutine
shr outa, #%1 'shift back right one bit
jmp #:loop
clkdelay mov time, deltime 'the delay subroutine, load deltime into toime
take4 'imternal to subroutine flag
sub time, #1 wz 'sub 1 from time and set flag if 0
if_nz jmp #take4 'if flag not 0 go back to take4
clkdelay_ret ret 'return for delay subroutine
deltime long 5_000_000 'time of delay
time res 1 'location for time
Program XXX
Subroutine creation and use for 0.25 second delay.
Harprit
Bookmarks