
![]() |
||||||||||
|
||||||||||
.device AT90S1200
.def delay = R16 ; define the registers we want to work with
.def leds = R17 ; (only 16..31 can be loaded with a constant !)
.def work = R18
.equ PortB = $18 ; these are I/O-registers we require
.equ DDRB = $17
.equ PinB = $16
reset: ldi work,$1f
out DDRB,work ; Set Pins PB0..PB4 to output, rest input
ldi work,$80
out PortB,work ; Enable internal pullup on PB7 and turn off
; all LEDs
clr leds ; Init LED-pattern (all 0)
loop: sbic PinB,7 ; Check RB7-Pin
rjmp left ; branch if Direction should be left
lsr leds ; shift LED-pattern to the right
tst leds ; Check if all 0
brne continue ; no => continue
ldi leds,$10 ; load new LED pattern (PB4 on, rest off)
rjmp continue
left: lsl leds ; shift LED-pattern to the left
tst leds ; all 0 ?
brne continue
ldi leds,$01 ; (PB0 on, rest off)
continue:
mov work,leds ; copy LED pattern
sbr work,$80 ; and ensure pullup on PB7 is enabled
out PortB,work ; write new pattern to the output
ldi delay,195 ; a little delay loop so we can see the movement
delay1: ldi work,255 ; internal loop: we'll have to wait
delay2: nop ; about 250.000 cycles
nop
dec work
brne delay2
dec delay
brne delay1
rjmp loop ; back to the main loop
Note: There is small gap if the LEDs are running to the left - can you fix it (exercise !) ? All AVRs expect the 90S1200 use a software stack. This means, that you have to set the stack pointer before making the first call or allowing any interrupts. On the 90S2313 the stack pointer is 8-bit wide only, the other ones use 'full' 16 bits. Commonly the stack pointer is set to the last s-ram location at startup. Place these lines at the beginning of your code, right after the interrupt table:
.equ sph = $3e ; Stack pointer (or use include) .equ spl = $3d .def wr = R18 ; Register definition reset: clr wr ; init stack pointer out sph,wr ; (hi-byte not required on 90S2313) ldi wr,$df out spl,wr ; (last s-ram location of an 90S2313) ret These are subs for using the UART in polling-mode (Has especially advantages on the S8515: Avoids the IRQ-Bug !). Before calling 'send' you have to put the character to send into 'R 18' (wr). After calling 'receive' you can find the received character in 'R 18' (wr).
.equ udr = $0c ; UART registers (or use include)
.equ usr = $0b
.equ ucr = $0a
.equ ubrr = $09
.def wr = R18 ; Register definition
init: ldi wr,23 ; init baudrate (19200 bps @ 7,328 MHz)
out ubrr,wr
ldi wr,$18 ; init UART for transmit and receive
out ucr,wr
ret
send: sbis usr,5 ; send character
rjmp send
out udr,wr
ret
receive: ; wait for and receive character
sbis usr,7
rjmp receive
in wr,udr
ret
These are subs for using the PWM on an 90S2313 (Should work also on other devices). At first, calling 'pwmini', the PWM-module is initialized with the output set to zero. Now the output can be changed using 'pwmset' which expects the new control value in 'R 18' (wr).
.equ tccr1a = $2f ; TMR1 registers (or use include) .equ tccr1b = $2e .equ tcnt1h = $2d .equ tcnt1l = $2c .equ ocr1ah = $2b .equ ocr1al = $2a .def wr = R18 ; Register definition pwmini: clr wr ; first clear all registers out tccr1a,wr out tccr1b,wr out tcnt1h,wr ; Remember: always write hi-byte first ! out tcnt1l,wr out ocr1ah,wr out ocr1al,wr ldi wr,$81 ; now select pwm mode (8-bit, non inverted)... out tccr1a,wr ldi wr,$02 ; ... and the right clock out tccr1b,wr ret pwmset: out ocr1al,wr ; write new pwm-value (hi-byte doesn't care - 8 bit only) ret Note: This is an example for 8-bit PWM. See datasheet how to expand to 9 or 10 bits ! The following example explains connecting an LCD-Module featuring an Hitachi-based controller (HD44780).
First the module must be initialized.'lcdinit' does this
also switching to the 4-bit-mode. After this you can send commands
or data using 'lcdcmd' or 'lcddata' respectively.
Both subs expect the command/character in 'R 18' (work).
Explaining all commands would take too long here. So I only tell
you the most important one: 'Set Data Address'. This command
lays down where to write the next character inside the display
ram - set bit #7 to one and write the address to the other bits
(Short: Address or $80). The address depends strongly
on the module - my '16 x 1' uses $00 - $07 for the first eight
characters and $40 - $47 for the second, others are linear and
use $00 - $0f. However, you can look up in the datasheet for this
value or simply try them - there nothing which can be damaged
then executing these tests. And here's the listing, writing also
a few characters to the display as a test:
; LCD - Controlled by AVR
.equ portddr = $11
.equ portd = $12
.equ portdi = $10
.equ portbdr = $17
.equ portb = $18
.equ portbi = $16
.equ stack = $3d
.equ d7 = 7 ; Port B
.equ d6 = 6
.equ d5 = 5
.equ d4 = 4
.equ rs = 5 ; Port D
.equ e = 6
.def work = r18
.def wt1 = r25
.def wt2 = r26
start:
; The next two lines are nesccessary if using an other AVR than
; 90S1200. They initialize the software stack !
ldi work,$df ; init stack
out stack,work
ldi work,$60
out portddr,work
ldi work,$f0
out portbdr,work
ldi work,$00
out portd,work
ldi work,$00
out portb,work
rcall lcdinit
ldi work,$80
rcall lcdcmd
ldi work,'H'
rcall lcddata
ldi work,$81
rcall lcdcmd
ldi work,'a'
rcall lcddata
ldi work,$82
rcall lcdcmd
ldi work,'l'
rcall lcddata
ldi work,$83
rcall lcdcmd
ldi work,'l'
rcall lcddata
ldi work,$84
rcall lcdcmd
ldi work,'o'
rcall lcddata
finito: rjmp finito
; Write character into the display memory -
; it must be supplied in 'R18' (work).
lcddata:
sbi portd,rs
rjmp docmd
; Send a command to the display module -
; it must be supplied in 'R18' (work).
lcdcmd:
cbi portd,rs
docmd: cbi portd,e
cbi portb,d7
sbrc work,7
sbi portb,d7
cbi portb,d6
sbrc work,6
sbi portb,d6
cbi portb,d5
sbrc work,5
sbi portb,d5
cbi portb,d4
sbrc work,4
sbi portb,d4
rcall epulse
cbi portb,d7
sbrc work,3
sbi portb,d7
cbi portb,d6
sbrc work,2
sbi portb,d6
cbi portb,d5
sbrc work,1
sbi portb,d5
cbi portb,d4
sbrc work,0
sbi portb,d4
rcall epulse
rcall delay5
ret
; This sub initializes the display for the
; 4-Bit-mode and clears it.
lcdinit:
rcall delay5
rcall delay5
rcall delay5
cbi portd,rs
cbi portd,e
sbi portb,d4
sbi portb,d5
cbi portb,d6
cbi portb,d7
rcall epulse ; set 8-Bit
rcall delay5
rcall epulse ; set 8-Bit
rcall delay5
rcall epulse ; set 8-Bit
rcall delay5
cbi portb,d4
sbi portb,d5
cbi portb,d6
cbi portb,d7
rcall epulse ; set 4-Bit
rcall delay5
cbi portb,d4
sbi portb,d5
cbi portb,d6
cbi portb,d7
rcall epulse ; set Font-A
cbi portb,d4
cbi portb,d5
sbi portb,d6
sbi portb,d7
rcall epulse ; set Font-B
rcall delay5
cbi portb,d4
cbi portb,d5
cbi portb,d6
cbi portb,d7
rcall epulse ; set Dsp-off-A
cbi portb,d4
cbi portb,d5
cbi portb,d6
sbi portb,d7
rcall epulse ; set Dsp-off-B
rcall delay5
cbi portb,d4
cbi portb,d5
cbi portb,d6
cbi portb,d7
rcall epulse ; set Cursor-A
cbi portb,d4
cbi portb,d5
sbi portb,d6
sbi portb,d7
rcall epulse ; set Cursor-B
rcall delay5
cbi portb,d4
cbi portb,d5
cbi portb,d6
cbi portb,d7
rcall epulse ; set Entry-A
cbi portb,d4
cbi portb,d5
sbi portb,d6
cbi portb,d7
rcall epulse ; set Entry-B
rcall delay5
ret
epulse: sbi portd,e ; pulse 'E-Clock'
nop
nop
nop
nop
nop
nop
nop
nop
cbi portd,e
ret
delay5: ldi wt1,50 ; delay loop
wtlp1: ldi wt2,255
wtlp2: dec wt2
brne wtlp2
dec wt1
brne wtlp1
ret
The following subs show how to use the internal ADC of several AVRs - they have been tested on an 90S8535. First you habe to turn on and init the ADC by calling 'init_adc'. Then you can query any channel using 'do_adc' which expects the channel number in 'R 18' (wr). If you do not need the ADC any more you can turn it off with the 'pd_adc'-sub. The first conversion after initializing or changing the channel is INVALID so you have to call 'do_adc' twice in this case.
.def wr = R18 .def resH = R10 .def resL = R11 .equ admux = $07 .equ adcsr = $06 .equ adch = $05 .equ adcl = $04 .equ adsc = 6 init_adc: ldi wr,$96 ; init ADC-control out adcsr,wr ; clr irq, clk = 8 MHz ret do_adc: andi wr,$07 ; select valid ADC-channel out admux,wr ; (supplied in wr) sbi adcsr,adsc ; start conversion wt_adc: sbic adcsr,adsc ; wait until conversion is rjmp wt_adc ; completed in resL,adcl ; read ADC-result, read in resH,adch ; always adcl first ! ret pd_adc: ldi wr,$10 ; turn off the ADC out adcsr,wr ret
This document may not be copied from this server neither to an other electronic media nor in any other way. The only exception is a single hardcopy for learning with it. This is only allowed for clear private purposes, any commercial usage requires the permission from the author. This means the explanations as well as the source codes which have been included on it. The author and the runners of this server don't give any warrenties for consequences of using the information supplied in this document. All brand names which have possible been mentioned belong to their respective owners. AVR is a registered trademark of the Atmel Corporation. For hints about errors or abuse the author will be grateful. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() ![]() |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||