No to coś napisałem na AVRStudio 4.05.0.181 (na kolanie)

. Co prawda na
ATmega8, ale przeportowanie to pestka(niektóre wektory przerwań do skasowania/zmiany nazwy i
"2313def.inc" zamiast
"m8def.inc", prędkość kwarcu
Xtal też do poprawki...), raczej tu chyba nie ma rozkazów niezaimplementowanych w
AT90S2313.
;included in next file - line ".device m8def.inc (ATmega8)" prohibits using of non-implemented instructions
.include "m8def.inc"
.cseg
.org $00
rjmp RESET ;Reset Handle
.org INT0addr
reti ;rjmp EXT_INT0;EXT_INT0; External Interrupt0 Handle
.org INT1addr
rjmp EXT_INT1 ;reti;EXT_INT1; External Interrupt1 Handle
.org OC2addr
reti ;rjmp ; Output Compare2 Interrupt Vector Address
.org OVF2addr
reti ;rjmp ; Overflow2 Interrupt Vector Address
.org ICP1addr ; Input Capture1 Interrupt Vector Address
reti ;rjmp TIM1_CAPT ;Input Capture1 Interrupt Vector Address
.org OC1Aaddr
reti ;rjmp TIM1_COMPA ;Output Compare1A Interrupt Vector Address
.org OC1Baddr
reti ;rjmp TIM1_COMPB ;Output Compare1B Interrupt Vector Address
.org OVF1addr
reti ;rjmp TIM1_OVR ;OverflowTimer1 Interrupt Vector Address
.org OVF0addr
rjmp TIM0_OVR ;reti ;OverflowTimer0 Interrupt Vector Address
.org SPIaddr
reti ;rjmp SPI_STC ;SPI Interrupt Vector Address
.org URXCaddr
reti ;rjmp UART_RXC ;USART Receive Complete Interrupt Vector Address
.org UDREaddr
reti ;rjmp UART_DRE ;USART Data Register Empty Interrupt Vector Address
.org UTXCaddr
reti ;rjmp UART_TXC ;USART Transmit Complete Interrupt Vector Address
.org ADCCaddr
reti ;rjmp ; ADC Interrupt Vector Address
.org ERDYaddr
reti ;rjmp ; EEPROM Interrupt Vector Address
.org ACIaddr
reti ;rjmp ANA_COMP ;Analog Comparator Interrupt Vector Address
.org TWIaddr
reti ;rjmp ; Irq. vector address for Two-Wire Interface
.org SPMRaddr
reti ;rjmp ; SPM complete Interrupt Vector Address
.equ Xtal=16000000 ;16 MHz => ~62,5e-9 s ~=62,5ns clock tick
.def MemoByteLo =r0 ;Used for EEPROM & Program Flash Memory access and Lo byte for result of multiply
.def MemoByteHi =r1 ; Hi byte for result of multiply
.def IntSaveMemoByteLo =r2 ;
.def IntSaveSREGByte =r3 ;
.def IntSaveTempA = r4 ;
.def IntSaveTempB = r5
.def IntSaveDataByte =r6 ;
.def IntSaveXLByte = r7
.def IntSaveXHByte = r8
.def IntSaveZLByte = r9
.def IntSaveZHByte = r10
.def StoreZL = r11
.def StoreZH = r12
.def ZeroByte = r13 ; Usefull in routines, where every cycle have gold meaning...
.def IntMul = r14 ;
.def DummyByte=r15 ;used in decrement and increment X, Y, Z by (ld DummyByte, (-)X/Y/Z(+)
.def DataByte =r16 ;
.def TempA = r17 ;
.def TempB = r18 ;
.def CountBtL =r19 ;
.def CountBtH =r20 ;
.def TempCInt = r21 ;
.def TL = r22 ;
.def TH = r23 ;
.def AddWordL =r24 ;
.def AddWordH =r25 ;
.equ IFlag=7
.equ TFlag=6
.equ HFlag=5
.equ SFlag=4
.equ VFlag=3
.equ NFlag=2
.equ ZFlag=1
.equ CFlag=0
;r26-r31 -> X, Y, Z
; ********** MACROS **********
.macro SaveOnEnterInt
in IntSaveSREGByte, SREG ;save SREG
mov IntSaveMemoByteLo, MemoByteLo ;save MemoByteLo
mov IntSaveTempA, TempA ;save TempA
mov IntSaveTempB, TempB ;save TempB
mov IntSaveDataByte, DataByte ;save DataByte
mov IntSaveXLByte, XL ;save X
mov IntSaveXHByte, XH
mov IntSaveZLByte, ZL ;save Z
mov IntSaveZHByte, ZH
.endmacro
.macro RestoreOnEndInt
mov ZL, IntSaveZLByte
mov ZH, IntSaveZHByte ;restore Z
mov XL, IntSaveXLByte
mov XH, IntSaveXHByte ;restore X
mov DataByte, IntSaveDataByte ;restore DataByte
mov TempB, IntSaveTempB ;restore TempB
mov TempA, IntSaveTempA ;restore TempA
mov MemoByteLo, IntSaveMemoByteLo ;restore MemoByteLo
out SREG, IntSaveSREGByte ;restore SREG
.endmacro
;Interrupts procedures
EXT_INT1: ; External Int1 reqest routine
.equ IRQ1MeterTicks = 6 ; number of Interrupts on 1 meter
.dseg
MeasureTime:
.byte 0x02
.cseg
SaveOnEnterInt
; Save time counter as measure result (multiplication of milisecond)
lds DataByte, TimeCnt
sts MeasureTime, DataByte
lds DataByte, TimeCnt+1
sts MeasureTime+1, DataByte
; Clear time counter
sts TimeCnt, ZeroByte
sts TimeCnt+1, ZeroByte
; reset BOOL Variables
sts bTimeCntOverflov, ZeroByte
EXT_INT1End:
RestoreOnEndInt
reti
TIM0_OVR: ;Timer0 Overflows ($FF -> $00)
.dseg
TimeCnt:
.byte 0x02 ; 2-Byte Time Counter
bTimeCntOverflov: ; if INT0 ticks too slow
.byte 0x01
.cseg
SaveOnEnterInt
;**************************************************
;Reload timer 0 now to preserve accuracy
;**************************************************
ldi TempA,T0cnt ;Reload early, avoid the latency
out TCNT0,TempA ;
;********************************************************
lds DataByte, bTimeCntOverflov
sbrc DataByte, 0x00 ; Skip next instruction if bit0 in DataByte is cleared
rjmp IncTimeCntEnd ; counter will be skiped, untill INT1 not ocure.
IncTimeCnt0:
lds DataByte, TimeCnt
inc DataByte
sts TimeCnt, DataByte
breq IncTimeCnt1
rjmp IncTimeCntEnd
;- - - - - - - - - - - - -
IncTimeCnt1:
lds DataByte, TimeCnt+1
inc DataByte
sts TimeCnt+1, DataByte
brne IncTimeCntEnd
;Counter overflows
ldi DataByte, 0x01
sts bTimeCntOverflov, DataByte
;- - - - - - - - - - - - -
IncTimeCntEnd:
RestoreOnEndInt
reti
RESET:
;Proc InitStack()
InitStack:
; It mustn't to be a subroutine, because must
; be stack point initialised before call it
; Inicialise Stack Point - push decrement it, pop increment
cli ; it's more safetly to disable interrupts durring initialisation
clr ZeroByte
ldi TempA, high(RAMEND)
out SPH, TempA
mov XH, TempA
ldi TempA, low(RAMEND)
out SPL, TempA
mov XL, TempA
InitSRAMClr:
st -X, ZeroByte
cpi XH, high(RAMSTART-1)
brne InitSRAMClr
cpi XL, low(RAMSTART-1)
brne InitSRAMClr
InitTim0:
;Proc InitTim0()
.equ Trise=0x07
.equ Tfall=0x06
.equ Tdiv1024=0x05
.equ Tdiv256=0x04
.equ Tdiv64=0x03
.equ Tdiv8=0x02
.equ Tdiv1=0x01
.equ Tstop=0x00
.equ T0div=Tdiv256
.equ Prescale0=1024*(T0div==Tdiv1024)+256*(T0div==Tdiv256)+64*(T0div==Tdiv64)+8*(T0div==Tdiv8)+(T0div==Tdiv1)
.equ T0IntusPulse = 1000/IRQ1MeterTicks; 1000/IRQ1MeterTicks microseconds - 1/IRQ1MeterTicks ms Int0Ovrfl pulse
.equ usDiv = 1000000; microsecond divisor
.equ T0dly = ((T0IntusPulse*Xtal)/(usDiv*Prescale0))
.equ T0cnt=(0xFF-T0dly)
;Set timer0 running (p.70)
ldi TempA,T0div
out TCCR0,TempA ;Set the prescaler
ldi TempA,T0cnt ;Define the reload value
out TCNT0,TempA ;Put that in T0
ldi TempA,1<<TOV0
out TIFR,TempA ; Clear TOV0/ clear pending interrupts
ldi TempA,1<<TOIE0
out TIMSK,TempA ; Enable Timer/Counter0 Overflow Interrupt
;Proc InitIRQ1()
InitIRQ1:
.equ IntPort=PORTD
.equ IntDirPort=DDRD
.equ IRQ1IN = PD3
cbi IntDirPort, IRQ1IN ; INT1 pin in
sbi IntPort, IRQ1IN ; INT1 pin pull up
in TempA, GIMSK
sbr TempA, 1<< IRQ1IN
out GIMSK, TempA
;INT1 sense source :
; ISC10 clr, ISC11 clr - low level
; ISC10 clr, ISC11 set - falling edge
; ISC10 set, ISC11 set - rising edge
;the rest is in the silence ;-)
; Falling edge of INT1 generates an interupt request
in TempA, MCUCR
cbr TempA, 1<<ISC10
sbr TempA, 1<<ISC11
out MCUCR, TempA
sei ; end of initialisation, interrupts can to run ;)
rjmp MainProc ; --> Main.asm
Wejście podłączamy do
INT1, jak wolisz do
INT0, to trzeba zaczepić się o inny wektor i co innego inicjalizować w RESET, zmienić i/lub zamienić niektóre definicje i stałe.
Odwrotność dwubajtowej zmiennej
MeasureTime jest prędkością w metrach na milisekundę

Mnożąc ją razy 1000 otrzymamy prędkość w m/s(1000/
MeasureTime). Jeżeli czujnik za wolno się kręci to mamy tam 0(co przy dzieleniu wypada nieszczególnie, trzeba do tego dołożyć korektę, jaki i do przekroczenia prędkości maksymalnej{1km/s - chcemy szybciej - trzeba zwiększyc rozdzielczość licznika
TimeCnt i timerek musi "tykać częściej"}...). Jeżeli chcemy pomiar mniejszych prędkości, to albo zwiększamy rozdzielczość licznika do np. 32 bitów, albo zmieniamy czujnik na taki o większej ilości impulsów na metr.
Stała
IRQ1MeterTicks definiuje tutaj ilość impulsów na metr(wpisałem tak jak kolega podał - 6

). Procedurę dzielącą dla obliczeń można znaleźć w podanych wcześniej linkach do przykładów (polega w sumie na wielokrotnym odejmowaniu, póżniej dla części ułamkowej resztę mnożymy razy 10 i znów dzielimy itd.). Z tego co mi się kojarzy, po pewnych modyfikacjach pewnie też da się to użyć jako wstawki
$asm do Bascom lub w C(
#pragma asm)...
Nie wykluczam też istnienie pewnych niezamierzonych pomyłek, które wyjdą w "praniu"(nie testowałem)...
Życzymy udanych pomiarów...
P.S.
Jak widać zmieniłem (Ach te nocne nasiadówki

) koncepcję podaną wcześniej aby licznik liczył impulsy, które w procedurze przerwania czasowego byłyby mierzone, wynik wtedy byłby bezpośrednio prędkością, ale to też nietrudno zmodyfikować.
Pozdrawiam, LightI