;----------------------------------------------------------------------------; ; Line following robot embedded program (Int.RC 8MHz) ;----------------------------------------------------------------------------; .include "m8def.inc" ; Device definition file included in "AVR Family Assembler". .include "avr.inc" .def _0 = r15 ;Zero reg. .def _Flags = r25 ;b0: Senor capture completed ;b1: Enable motor .def _Err = r14 ;Number of sensing error continue... ;-----------------------------------------------------------------------------; ; SRAM領域定義 .dseg .org RAMTOP ScanCh: .byte 2 ;Current channel and phase (for background process) SensReg:.byte 12 ;Processing registers (Value) .byte 12 ;Processing registers (Sensor #) .byte 12 ;Background scan register ComVal: .byte 12 ;Inter-channel compensation value Parms: .byte 3 ;Control parameters (PWM base, P-gain, D-gain) Pwm: .byte 3 ;PWM control variables (Left, Right, Phase) LineBuf:.byte 32 ;Online command line buffer ;-----------------------------------------------------------------------------; ; EEPROM initial value .eseg eeParms:.db 0x18, 0x20, 0xF0 ; PWM base, P gain, D gain eeComVal:.byte 12 ; Sensor compensation values ;-----------------------------------------------------------------------------; ; Vector table .cseg rjmp reset ; RESET rjmp 0 ; INT0 rjmp 0 ; INT1 rjmp 0 ; TC2 COMP rjmp 0 ; TC2 OVF rjmp 0 ; TC1 CAPT rjmp 0 ; TC1 COMPA rjmp 0 ; TC1 COMPB rjmp 0 ; TC1 OVF ; rjmp tc0_ovf ; TC0 OVF ; rjmp 0 ; SPI ; rjmp 0 ; USART RXC ; rjmp 0 ; USART UDRE ; rjmp 0 ; USART TXC ; rjmp 0 ; ADC ; rjmp 0 ; EE_RDY ; rjmp 0 ; ANA_COMP ; rjmp 0 ; TWI ; rjmp 0 ; SPM_RDY ;-----------------------------------------------------------------------------; ; TC0 overflow interrupt isr (9.6kHz) tc0_ovf: push AL outi TCNT0, -12 in AL, SREG pushw A pushw Y pushw Z rcall drive_pwm rcall scan_sens popw Z popw Y popw A out SREG, AL pop AL reti drive_pwm: in AH, PORTB cbr AH, bit1+bit2 sbrc _Flags, 1 ;Exit if PWM disable rjmp PC+3 ; out PORTB, AH ; ret ;/ ldsw Z, Pwm ;Load PWM values lds AL, Pwm+2 ;/ cp AL, ZL ;Left drive brcc PC+2 ; sbr AH, bit1 ;/ cp AL, ZH ;Right drive brcc PC+2 ; sbr AH, bit2 ;/ out PORTB, AH ;Set output subi AL, 1 ;PWM counter --; brcc PC+2 ; ldi AL, 23 ; sts Pwm+2, AL ;/ ret scan_sens: ldsw Y, ScanCh ;Get current channel pointer mov ZL, YL ; lsl ZL ; clr ZH ; addiw Z, SensReg+24 ;/ cpi YH, 0 ;Branch by channel phase breq rs_0 ; cpi YH, 1 ; breq rs_1 ; cpi YH, 2 ; breq rs_2 ; rjmp rs_3 ;/ rs_0: inw A, ADC ;Store base value stdw Z+0, A ;/ rs_1: inc YH ;Next phase rjmp rs_exit rs_2: sbi ADCSR, ADSC ;Capture peak value ldi AL, 33 ; dec AL ; brne PC-1 ;/ outi PORTD, 0x7f ;LED off inc YH ;Next phase rjmp rs_exit rs_3: ldd AH, Z+0 ;Store peak value - base value in AL, ADCL ; sub AL, AH ; std Z+0, AL ; ldd AH, Z+1 ; in AL, ADCH ; sbc AL, AH ; std Z+1, AL ; brcc PC+3 ; If result is minus, it is zero. std Z+0, _0 ; std Z+1, _0 ;/ clr YH ;Next cannel (0 -> 2 -> 4 -> 1 -> 3 -> 5) addi YL, 2 ; cpi YL, 6 ; brne PC+3 ; ldi YL, 1 ; rjmp PC+13 ;/ brcs PC+12 ;When all channels are completed, sbrc _Flags, 0 ; update working regs rjmp PC+9 ; ldiw Z, SensReg ; ldi AL, 12 ; ldd AH, Z+24 ; st Z+, AH ; dec AL ; brne PC-3 ; sbr _Flags, bit0 ; clr YL ;/ rcall sel_adch ;Capture base value sbi ADCSR, ADSC ; ldi AL, 33 ; dec AL ; brne PC-1 ;/ rcall sel_led ;LED on rs_exit: stsw ScanCh, Y ret sel_led: ;Select sensor LED specified by YL (0..5) mov ZL, YL clr ZH addiw Z, led_pat*2 lpm ZL, Z out PORTD, ZL ret sel_adch: ;Select sensor A/D channel specified by YL (0..5) mov ZL, YL clr ZH addiw Z, adch_pat*2 lpm ZL, Z out ADMUX, ZL ret led_pat:.db 0x7e, 0x7d, 0x7b, 0x6f, 0x5f, 0x3f adch_pat:.db 0xc0, 0xc1, 0xc2, 0xc3, 0xc6, 0xc7 ;-----------------------------------------------------------------------------; ; Power ON / Reset button released reset: ldiw A, RAMEND ;Initialize SP outw SP,A ;/ clr _0 ;Permanent zero ldiw Z, RAMTOP ;Clear RAM clr AL ; st Z+, _0 ; st Z+, _0 ; st Z+, _0 ; st Z+, _0 ; dec AL ; brne PC-5 ;/ outi PORTB,0b11101001 ;Initialize Port B outi DDRB, 0b00010110 ;/ outi PORTD, -1 ;Initialize Port D outi DDRD, 0b11110111 ;/ outi PORTC, 0b00110000 ;Initialize Port C outi TCCR0, 0b011 ;TC0.ck = 115kHz clr _Flags sei ldiw Z,m_start*2 ;Start up message rcall dp_str ;/ rcall load_allparms ;Load working parameters sbis PINB, MOSI ;Enter online mode if cable is attached rjmp monitor ;/ rjne enter_sleep ;Enter sleep mode if parameter is broken ;-----------------------------------------------------------------------------; ; Self Running Mode start: outi ADCSR, 0b11000101 ;Enable ADC outi TIMSK, (1< command line ld BH,X+ ; BH = command char rcall caps ; / cpi BH,0x0d ; Null line ? breq monitor ; yes, returen cpi BH,'O' ; Output port ? breq do_output ; yes, do cpi BH,'I' ; Input port ? breq do_input ; yes, do cpi BH,'E' ; Edit memory ? rjeq do_edit ; yes, do cpi BH,'S' ; Test motors/sensors ? rjeq do_test ; yes, do cpi BH,'R' ; Run ? rjeq start ; yes, do cmd_err:ldiw Z,m_error*2 ; Syntax error rcall dp_str ; / rjmp monitor ;--------------------------------------; ; I/Oレジスタに書き込み ; Write into I/O register do_output: rcall get_valh ; Get I/O address (0-3F) breq cmd_err ; / andi AL,0x3f ; I/O address in memory space (+0x20) mov ZL,AL ; ldi ZH,0 ; adiw ZL,0x20 ; / rcall get_valh ; Get data value to be written breq cmd_err ; / st Z,AL ; Output data rjmp monitor ;--------------------------------------; ; I/Oレジスタから読み込み ; Read from I/O register do_input: ld BH,X ; Get sub command rcall caps ; mov CL,BH ; cpi BH,'R' ; brne PC+2 ; inc XL ; / rcall get_valh ; Get I/O address (0-3F) breq cmd_err ; / andi AL,0x3f ; I/O address on memory area (+0x20) mov ZL,AL ; ldi ZH,0 ; adiw ZL,0x20 ; / ldi AL,0x0a ; LF rcall xmit ; / ld CH,Z ; 1st data com CH ; / sbic PINB,MOSI ; If break, exit loop rjmp monitor ; / ld AH,Z ; Wait data change cp AH,CH ; breq PC-4 ; / mov CH,AH ; Display data rcall di_disp ; / cpi CL,'R' breq PC-8 rjmp monitor di_disp: ldi AL,0x0d ; CR rcall xmit ; / mov AL,AH ; Hex rcall dp_byte ; / rcall space ; SP ldi BH,8 ; Bin ldi AL,'0' lsl AH adc AL,ZH rcall xmit dec BH brne PC-5 rcall space ; SP ret ;--------------------------------------; ; メモリに書き込み ; Write into memory do_edit: ld BH,X+ ; BH = command char rcall caps ; / cpi BH, 'M' ;Get destination breq PC+4 ; cpi BH, 'E' ; breq PC+2 ; rjmp cmd_err ; mov EH, BH ;/ rcall get_valh ;Get memory address rjeq cmd_err ; movw ZL,AL ;/ rcall get_valh ;Get data value to be written rjcs cmd_err ;/ breq de_lp ;Is interactive mode? rcall wr_mem ; no, store directly and exit rjmp monitor ;/ de_lp: ldi AL, 0x0a ; Display data prompt rcall xmit ; mov AL,ZH ; rcall dp_byte ; mov AL,ZL ; rcall dp_byte ; rcall space ; rcall rd_mem ; rcall dp_byte ; ldi AL, '-' ; rcall xmit ; / rcall get_line ; Input data value to be written ldiw X,LineBuf ; ld AL,X ; / cpi AL,'.' ; End of edit? rjeq monitor ; yes, exit. rcall get_valh ; Get data value rjcs cmd_err ; / breq PC+2 ; Skip if blank. rcall wr_mem ; Store data into memory adiw ZL,1 ; Next location rjmp de_lp ; Continue rd_mem: cpi EH, 'E' brne PC+2 rjmp read_eep ld AL, Z ret wr_mem: cpi EH, 'E' brne PC+2 rjmp write_eep st Z, AL ret ;--------------------------------------; ; Test motors and sensors do_test: outi ADCSR, 0b11000101 ;Enable ADC rcall get_valh ;secondary command (1-3) rjeq cmd_err cpi AL, 1 ;s1 (Output moror PWM) breq ds_1 cpi AL, 2 ;s2 (dislpay sensor status) breq ds_2 cpi AL, 3 ;s3 (calibrate sensor) rjeq do_cal rjmp cmd_err ds_1: rcall get_valh ;Left motor rjeq cmd_err ; sts Pwm+0, AL rcall get_valh ;Right motor rjeq cmd_err ; sts Pwm+1, AL sbr _Flags, bit1 ;Enable motor outi TIMSK, (1< - Test motor", 13, 10, "s2 - Test sensor", 13, 10, "s3 - Calibrate sensor", 13, 10, "ee0 - PWM base", 13, 10, "ee1 - P gain", 13, 10, "ee2 - D gain", 13, 10, 0 m_rule1: .db "-------",0