;***************************************************************************
;* BelliBot's first Brain :) - based on Atmels rc5uart for infrared controll
;* (c.) by B.F
;* thanks to many other resources on the internet
;* they may help me out
;*--------------------------------
;* File Name :"rc5uart.asm"
;* Title :RC5 IR Remote Control Decoder
;* Target MCU :AT90S2313
;*
;* DESCRIPTION
;* This Application note describes how to decode the frequently used
;* RC5 IR remote control protocol.
;*
;* The timing is adapted for 4 MHz crystal
;* This program is infact a mixing of the code for the rc5 communication
;* and a full duplex hardware UART
;*
;***************************************************************************
.include "2313def.inc"
;************ rc5 commands ********
.equ halt = 54
.equ vor = 28
.equ rueck = 48
.equ links = 33
.equ rechts = 32
.equ speedp = 30
.equ speedm = 31
.equ beep = 12
.equ light = 53
.equ erku = 61
;*************** Flag's in BotFlag ************ R25 ********
.equ Dwn = 0 ; Flag0 = hinten microschalter
.equ Rpt = 1 ; Flag1 =
.equ Acc = 2 ; Flag2 =
.equ aua = 3 ; Flag3 = Kollisionsflag inf.sensor !! - und interupt 1
.equ aual = 4 ; linker sensor front
.equ auar = 5 ; rechter sensor front
;portd6 = input tsop infrared
.equ INPUT =6 ;(PD6)
.equ SYS_ADDR =20 ;The system address
;**********************
.equ PZ = 6 ; Bit6 portb fuer piezo
;**********************
.def S =R0 ; Storage for the Status Register
.def inttemp =R1 ; Temporary variable for ISR
.def ref1 =R2
.def ref2 =R3 ; Reference for timing
.def tick =R4 ; time for tea every 16ms
.def stemp =R5 ; SPEED TEMP INC_DEC VALUE
.def outzeit = R6 ; Auszeit
.def RAND1 =R7 ;Random number generator needs three
.def RAND2 =R8 ;bytes. This could just as well be
.def RAND3 =R9 ;SRAM, but it would be a little slower
.def verz1 =R10 ; merker fuer delay
.def temp =R16 ; Temporary variable
.def timerL =R17 ; Timing variable updated every 14 us
.def timerH =R18 ; Timing variable updated every 16 ms
.def system =R19 ; Address data received
.def command =R20 ; Command received
.def bitcnt =R21 ; Counter
.def temp2=r22
.def M_reg = R23 ; motor register BellBot
.def M_sp = R24
.def BotFlag =R25 ; steuerflags fuer botis verhalten ( intelli )
;****************************************
.cseg
.org 0
rjmp RESET ;Reset Handler
nop ;rjmp autsch ;IRQ0 Handler
rjmp autsch ;IRQ1 Handler
nop;rjmp TIM_CAPT1 ;Timer1 Capture Handler
nop;rjmp TIM_COMP1 ;Timer1 Compare Handler
nop;rjmp TIM_OVF1 ;Timer1 Overflow Handler
rjmp TIM0_OVF ;Timer0 Overflow Handler
nop;rjmp UART_RXC ;UART RX Complete Handler
nop;rjmp UART_DRE ;UDR Empty Handler
nop;rjmp UART_TXC ;UART TX Complete Handler
nop;rjmp ANA_COMP ;Analog Comparator Handler
;********************************************************************
;* "TIM0_OVF" - Timer/counter overflow interrupt handler
;*
;* The overflow interrupt increments the "timerL" and "timerH"
;* every 64us and 16,384us.
;*
;* Crystal Frequency is 4 MHz
;*
;* Number of words:7
;* Number of cycles:6 + reti
;* Low registers used:1
;* High registers used: 3
;* Pointers used:0
;********************************************************************
;.org OVF0addr
TIM0_OVF:
in S,sreg ; Store SREG
push temp
inc timerL ; Updated every 64us
inc inttemp
brne TIM0_OVF_exit
inc timerH ; if 256th int inc timer
dec tick ; TeaTime
TIM0_OVF_exit:
pop temp
out sreg,S ; Restore SREG
reti
;*********** sensor1 interupt routine *******************************
autsch:
cli
in S,sreg ; Store SREG
push temp
in BotFlag,PinD ; PortD einlesen - welcher sensor wars denn '?
RCALL M_stop ; erstmal stop
sbr BotFlag,1<<aua ; flag setzen
pop temp
out sreg,S ; Restore SREG
sei
reti
;**********delay 320msec.**********************************************************
delay:
ldi temp,0x00 ; bit6 disaable ext interupt 1 on pind3
out GIMSK,temp
sbi PORTB,7 ;LED auge an
; @ T/C0-Int. alle 16 ms
;ldi temp2,2 ; äußeren Zähler laden
L1:
;ldi temp,0 ; inneren Zähler laden
mov tick,verz1
L2: mov temp2,tick
;rcall serout
sbis PIND,0 ; sbic - microschalter hinten / sbis if471
rjmp outdelay
tst tick ; Zählerstand = 0 ?
brne L2 ; wenn nicht, weiter warten
;dec temp2
;brne L1
cbi PORTB,7 ;LED auge aus
outdelay:
ldi temp,0x80 ; bit6 enable ext interupt 1 on pind3
out GIMSK,temp
ret
;********************************************************************
;* Example program
;*
;* Initializes timer, ports and interrupts.
;********************************************************************
reset:
;INIT RAM
ldi temp,low(RAMEND) ;Initialize stackpointer for parts with SW stack
out SPL,temp
;ldi temp,high(RAMEND) ; Commented out since 1200 does not have SRAM
;out SPH,temp
;INIT TIMER0
ldi temp,1 ;Timer/Counter 0 clocked at CK
out TCCR0,temp
ldi temp,1<<TOIE0 ;Enable Timer0 overflow interrupt
out TIMSK,temp
;INIT FULL DUPLEX HARDWARE UART
sbi ucr,txen ;enable UART transmitter
sbi ucr,rxen ;enable UART receiver
ldi r16,25 ;set baud rate
out ubrr,r16
;INIT PORTB
ser temp ;PORTB as output
out DDRB,temp
;clr temp
out PortB,temp ; alles nullen
;INIT PORTD
clr temp ; portd input
out DDRD,temp
ldi temp,0b01111001 ; PD0 - back switch
out PORTD,temp ; pullup on pd3 + pd4-pd6 pd3 interupt1 , pd6 infrarot,pd4+5
;sensor front l/r
; Init ext.Interupt for sensor
ldi temp,0x8 ; interupt 1 falling edge
out MCUCR,temp
ldi temp,0x80 ; bit6 enable ext interupt 1 on pind3
out GIMSK,temp
;INIT PWM
ldi temp,10
mov stemp,temp ; speed decrement value + -
pwmini: clr M_sp ; first clear all registers
out tccr1a,M_sp
out tccr1b,M_sp
out tcnt1h,M_sp ; Remember: always M_spite hi-byte first !
out tcnt1l,M_sp
out ocr1ah,M_sp
out ocr1al,M_sp
ldi M_sp,$81 ; now select pwm mode (8-bit, non inverted)...
out tccr1a,M_sp
ldi M_sp,$02 ; ... and the right clock
out tccr1b,M_sp
ldi M_sp,80 ; halbe kraft vorraus
out ocr1al,M_sp ; write new pwm-value (hi-byte doesn't care - 8 bit only)
rcall Init_Random
clr temp
mov BotFlag,temp
ldi temp,0xC0 ; lösche evtl.interup anforderung ;Flankentriggerung'die aufgetreten sein könnte
out GIFR,temp
sei ;Enable global interrupt
;**********************************************
main:
sbrc BotFlag,aua ; Skip, wenn collision.Flag gelöscht
rcall Flucht ; Sprung, wenn Flag gesetzt
rcall detect ;Call RC5 detect routine
cpi system,SYS_ADDR ;Responds only at the specified address, alter this variable to use other system adres
brne release
andi command,0x3F ;Remove control bit
CPI command,halt
BRNE x1
RCALL M_stop
x1:
CPI command,vor
BRNE x2
RCALL M_vor
x2:
CPI command,rueck
BRNE x3
RCALL M_rueck
x3:
CPI command,links
BRNE x4
RCALL M_links
x4:
CPI command,rechts
BRNE x5
RCALL M_rechts
x5:
CPI command,speedp
BRNE x6
RCALL M_spPlus
x6:
CPI command,speedm
BRNE x7
RCALL M_spMinus
x7:
CPI command,beep
BRNE x8
RCALL M_beep
x8: CPI command,light
BRNE x9
RCALL M_Light
x9: CPI command,erku
BRNE x10
RCALL M_erku
x10: nop
rjmp main
release:
clr command ;Clear command
; do a littelbit somthing
;**************************************************
;* here is the place for write your own code ******
;**************************************************
sbis PIND,0 ;test the rear sensor
RCALL Flucht03
nop
rjmp main
;******************* Flucht ******************************************
Flucht:
ldi temp,60 ;
mov verz1,temp ; Tea time
; - welcher sensor wars denn '?
sbrs BotFlag,auar
rjmp Flucht01 ; rechter sensor low
sbrs BotFlag,aual
rjmp Flucht02 ; linker sensor low
sbrs BotFlag,Dwn ; hinterer sensor
rjmp Flucht03
cbr BotFlag,1<<aua
RCALL M_Light
RCALL M_rueck
RCALL delay
RCALL M_Light
RCALL M_rechts
RCALL delay
RCALL M_Light
RCALL M_rueck
RCALL delay
RCALL M_Light
RCALL M_links
RCALL delay
RCALL M_L_out ; Licht bleibt an
RCALL M_vor
ret
Flucht01: ; rechter sensor
cbr BotFlag,1<<aua
RCALL M_beep
;RCALL M_stop ; erstmal stop
RCALL M_rueck
RCALL delay
RCALL M_rechts
RCALL delay
RCALL M_vor
ret
Flucht02: ; linker sensor
cbr BotFlag,1<<aua
RCALL M_beep
;RCALL M_stop ; erstmal stop
RCALL M_rueck
RCALL delay
RCALL M_links
RCALL delay
RCALL M_vor
ret
Flucht03: ; hinterer sensor
cbr BotFlag,1<<aua
RCALL M_beep
RCALL M_stop ; erstmal stop
RCALL M_Light
RCALL delay
RCALL M_vor
ret
;******************* Motorsteuerung BellBot**************************
;*
;*
;********************************************************************
M_stop:
clr temp
out ocr1al,temp ; write new pwm-value (hi-byte doesn't care - 8 bit only)
out PortB,temp ; alles nullen
ret
M_vor:
out ocr1al,M_sp ; write new pwm-value (hi-byte doesn't care - 8 bit
LDI M_reg,0b00000110
out PORTB,M_reg
ret
M_rueck:
out ocr1al,M_sp ; write new pwm-value (hi-byte doesn't care - 8 bit
LDI M_reg,0b00010001
out PORTB,M_reg
ret
M_links:
LDI M_reg,0b00000101
out PORTB,M_reg
ret
M_rechts:
LDI M_reg,0b00010010
out PORTB,M_reg
ret
M_spPlus:
;ldi temp3,10
add M_sp,stemp ; speicher fuer increment value for speed + -
out ocr1al,M_sp ; write new pwm-value (hi-byte doesn't care - 8 bit
ret
M_spMinus:
sub M_sp,stemp
out ocr1al,M_sp ; write new pwm-value (hi-byte doesn't care - 8 bit
ret
M_beep: rcall peep ; Beep Beep
ret
M_Light: sbis PORTB,7
rjmp M_L_out
cbi PORTB,7 ;toggle Light on/off
ret
M_L_out: sbi PORTB,7
ret
;********************************************************************
;* "detect" - RC5 decode routine
;*
;* This subroutine decodes the RC5 bit stream applied on PORTD
;* pin "INPUT".
;*
;* If success: The command and system address are
;* returned in "command" and "system".
;* Bit 6 of "command" holds the toggle bit.
;*
;* If failed: $FF in both "system" and "command"
;*
;* Crystal frequency is 4MHz
;*
;* Number of words:72
;* Low registers used: 3
;* High registers used: 6
;* Pointers used: 0
;********************************************************************
detect:
clr inttemp ; Init Counters
clr timerH
detect1:
clr timerL
detect2:
cpi timerH,8 ;If line not idle within 131ms
brlo dl1
rjmp fault ;then exit
dl1:
cpi timerL,55 ;If line low for 3.5ms
brge start1 ;then wait for start bit
sbis PIND,INPUT ;If line is
rjmp detect1 ;low - jump to detect1
rjmp detect2 ;high - jump to detect2
start1:
cpi timerH,8 ;If no start bit detected
brge fault ;within 130ms then exit
sbic PIND,INPUT ;Wait for start bit
rjmp start1
clr timerL ;Measure length of start bit
start2:
cpi timerL,17 ;If startbit longer than 1.1ms,
brge fault ;exit
sbis PIND,INPUT
rjmp start2 ;Positive edge of 1st start bit
mov temp,timerL ;timer is 1/2 bit time
clr timerL
mov ref1,temp
lsr ref1
mov ref2,ref1
add ref1,temp ;ref1 = 3/4 bit time
lsl temp
add ref2,temp ;ref2 = 5/4 bit time
start3:
cp timerL,ref1 ;If high period St2 > 3/4 bit time
brge fault ;exit
sbic PIND,INPUT ;Wait for falling edge start bit 2
rjmp start3
clr timerL
ldi bitcnt,12 ;Receive 12 bits
clr command
clr system
sample:
cp timerL,ref1 ;Sample INPUT at 1/4 bit time
brlo sample
sbic PIND,INPUT
rjmp bit_is_a_1 ;Jump if line high
bit_is_a_0:
clc ;Store a ’0’
rol command
rol system
;Synchronize timing
bit_is_a_0a:
cp timerL,ref2 ;If no edge within 3/4 bit time
brge fault ;exit
sbis PIND,INPUT ;Wait for rising edge
rjmp bit_is_a_0a ;in the middle of the bit
clr timerL
rjmp nextbit
bit_is_a_1:
sec ;Store a ’1’
rol command
rol system
;Synchronize timing
bit_is_a_1a:
cp timerL,ref2 ;If no edge within 3/4 bit time
brge fault ;exit
sbic PIND,INPUT ;Wait for falling edge
rjmp bit_is_a_1a ;in the middle of the bit
clr timerL
nextbit:
dec bitcnt ;If bitcnt > 0
brne sample ;get next bit
;All bits sucessfully received!
mov temp,command ;Place system bits in "system"
rol temp
rol system
rol temp
rol system
bst system,5 ;Move toggle bit
bld command,6 ;to "command"
;Clear remaining bits
andi command,0b01111111
andi system,0x1F
ret
fault:
ser command ;Both "command" and "system"
ser system ;0xFF indicates failure
ret
;******************************************************************
Init_Random:
ldi TEMP,$AA ;Init the random number generator
mov RAND1,TEMP ;since a 00,00,00 state will not
mov RAND2,TEMP ;progress.
mov RAND3,TEMP ;
ret
;********************** Random Number *****************************
;* for random action maybe , not used yet ! works fine
;******************************************************************
Random:
;Maximal legnth 19 bit shift register sequence,
push R16 ;Make workspace
push R17 ;
; RAND3 RAND2 RAND1
;22222111 11111110 00000000
;43210987 65432109 87654321
mov R16,RAND1 ;Make copy
mov R17,RAND3 ;Make copy
;clc ;not needed, because we will overwrite bit 0 later
rol RAND1 ;Shift the bits D7->Carry
rol RAND2 ;Carry->D0 D7->Carry
rol RAND3 ;Carry->D0 D7->Carry, but that will be fixed.
;Now we have to Xor the bits to see what
;goes in to bit 1
rol R17 ;Move bit 19->20
andi R17,$08 ;Important that D1,0 be zero
andi R16,$13 ;Mask out irrelevants, protecting bit 19
or R17,R16 ;Get bits 5->21 2->18 1->17
andi R17,$18 ;Nuke bits 18,17
lsr R17 ;19->19 5->20
lsr R17 ;19->18 5->19
lsr R17 ;19->17 5->18
eor R17,R16 ;First xor, result in R17 (5x2 in 02 and 19x1 in 01)
mov R16,R17 ;Make a copy
ror R16 ;Move the 5x2 result to 01
andi R17,$01 ;Mask off everything else
andi R16,$01 ;in both
eor R17,R16 ;
brne D_One ;If one, do that, else
D_Zero:
;Set a zero in the lsb of the low byte
mov R16,RAND1 ;Get the low byte
andi R16,$FE ;Make the LSB zero
mov RAND1,R16 ;Put it back
Rjmp D_Exit ;Bye bye
D_One:
;Set a one in the lsb of the low byte
mov R16,RAND1 ;Get the low byte
ori R16,$01 ;Make the LSB one
mov RAND1,R16 ;Put it back
D_Exit:
pop R17 ;Put everything back where I got it.
pop R16 ;
ret
;******************************************************************
; Ton erzeugung 4khz fuer piezo
;******************************************************************
;***Tactile feedback note generation routine*****************
;***provides a 4 kHz TONE to the piezo sounder for 5 ms*****
peep: clr temp2
tactile: cbi PORTB,PZ ;turn on piezo
ldi temp,210 ;for a short time
t1again: dec temp
brne t1again
sbi PORTB,PZ ;turn on piezo
ldi temp,210 ;for a short time
t2again: dec temp
brne t2again
inc temp2
cpi temp2,250 ;is half second up
brne tactile
ret
;******************************************************************
serout:
out udr,temp2 ;load UART data register
;out PORTB,command
serout1:
sbis usr,udre ;if UART data register empty bit is clear
rjmp serout1 ; loop back
;else return
ret
serin:
sbis usr,rxc ;if UART Receive Complete bit is clear
rjmp serin ; loop back
in r16,udr ;else get received byte in r16
ret ;and return