'**************************************************************** '* Name : Booter_Hub.BAS * '* Author : Godfried-Willem RAES * '* Notice : Copyleft (c) 2020 Logosoft Public Domain * '* Date : 26-02-2020 * '* Last update: 02.03.2020 * '* Version : 3.0 * '* Notes : Based On whisper code model, * '* later ,, * '**************************************************************** '12.12.2019: Adding these 2 lines in the 18F2525.inc file made it work again: ' Declare HPWM1_Pin = PORTC.2 ' added 12.12.2019 ' Declare HPWM2_Pin = PORTC.1 ' Reminder: HPWM uses Timer2 ! ' It would be better to implement 10-bit PWM here. ' 10-bit PWM does work now, but if we do that, the PWM base frequency becomes 39kHz... ' 9 bit mode works now with PWM base frequency 19kHz ' Complete rewrite of the multitasking system, conform the setup for ' Total system crash noticed after more than 1 hour op operation under full load conditions... ' Loopspeed: 151kHz at no load [Tektronics TDS2024C measurement] ' 120kHz with all timers running and high midi-in density. '--------------------------------------------------------------------------------- '26.02.2020: Start coding for the Hybr & HybrHi booter-board ' PCB made (special issue) ' First version flashed, first bug seen: Green_Led on at startup... ' bug 1 found: loopspeed was defined on the same port...RB.2 '27.02.2020: First test for ctrl.66 passed. ' As we have an awfull lot of midi to be parsed, we may have to implement a midi-output buffer here. ' Loopspeed is now 147kHz at no load, going down to 95kHz with extreme midi load. '28.02.2020: Awaiting delivery from Farnell to finish the hardware... '02.03.2020: All hardware ready. First tests and failures... 'Include "18F2620.inc" 'version for the So board. (40MHz) Include "18F2525.inc" 'also possible 'Include "18F2520.inc" 'also possible. (40MHz) ' Mapping defines for midi-events on pin outputs and inputs: $define Hyb PORTA.0 ' relay outputs $define AC1 PORTA.1 ' noot 24 $define AC2 PORTA.2 ' noot 25 $define AC3 PORTA.3 ' noot 26 $define AC4 PORTA.4 ' noot 27 ' lights: $define Blue PORTC.0 ' blue 1W LED on board ' note 16 $define Lite12 PORTC.2 ' - pwm1 ' note 12 $define Lite13 PORTC.1 ' - pwm2 ' noot 13 $define Lite14 PORTC.4 ' noot 14 $define Lite15 PORTC.5 ' noot 15 'red LED for debug: $define Debug_Led PORTB.5 ' for testing - red led - watchdog $define Green_Led PORTB.2 ' on the PCB 'for loopspeed measurement: $define Loopspeed PORTB.1 ' configure the input and output pins: Clear SSPCON1.5 'RC3 must be available for I/O TRISA = %01000000 'bits set to 0 are output, 1 = input TRISB = %11100000 TRISC = %11000000 'RC1 en RC2 zijn pwm outputs and must be set to output 'RC6 en RC7 zijn USART I/O and must be set to input 'constant definitions: 'initialisations for the midi input parser: Symbol Midichannel = 8 ' Hybr_Channel - HybrHi channel Symbol NoteOff_Status = 128 + Midichannel ' 2 bytes follow Symbol NoteOn_Status = 144 + Midichannel Symbol Keypres_Status = 160 + Midichannel ' 2 bytes follow Symbol Control_Status = 176 + Midichannel Symbol ProgChange_Status = 192 + Midichannel ' 1 byte message Symbol Aftertouch_Status = 208 + Midichannel ' 1 byte follows Symbol Pitchbend_Status = 224 + Midichannel ' lsb msb follow 'application specific constants Symbol NrTasks = 5 ' 0 to 4 Symbol fPWM = 20000 ' 15.04.2015 his only affects 8-bit pwm mode... Symbol delaytime = 65535 ' should be 1.5 seconds Symbol dischargetime = 65535 ' to be determined. ' Setup the USART Declare Hserial_Baud = 31250 ' Set baud rate for the USART to MIDI specs. Declare Hserial_TXSTA = 0x24 ' instead of the normal 0x20 - ?? 0x24 Declare All_Digital = True ' Declare Hserial_Clear = On ' should clear on errors. Bytes get lost of course... ' Create variables Dim Cnt As Dword System Dim CntHw As Cnt.Word1 'used in the timer0 interrupt, to create a 32 bit timer Dim CntLw As TMR0L.Word 'this is the trick to read both TMR0L and TMR0H 'it makes Cntlw the low word of cnt 'We still have to copy the contents of Lw to Cnt Dim time As Cnt 'alias Dim maxtim As time.31 ' overflow bit, will cause timer reset after 1h45 ' Dim Tim3 As TMR3L.Word Dim Bytein As Byte System ' midi byte read from buffer Dim MidiIn As Byte System Dim StBit As Bytein.7 ' highest bit of ByteIn Dim i As Byte System ' general purpose counter Dim j As Word ' midi variables Dim statusbyte As Byte System Dim noteUit As Byte System ' note off + release value Dim release As Byte System Dim noteAan As Byte System ' note on + release value Dim velo As Byte System Dim notePres As Byte System ' note pressure + pressure value Dim pres As Byte System Dim Ctrl As Byte System ' continuous controller + value Dim value As Byte System Dim prog As Byte System ' program change + program-byte Dim aft As Byte System ' channel aftertouch Dim pblsb As Byte System ' pitch bend lsb Dim pbmsb As Byte System ' pitch bend msb Dim CC66 As Byte System ' global on/off switch Dim PowerOn As CC66.0 ' flag Dim Shutting_down As CC66.1 ' flag ' Dim pw1 As Word System ' Dim pw2 As Word System Dim st As Byte System Dim b1 As Byte System Dim b2 As Byte System Dim Lites As Byte System ' bits used as flags Dim idx As Byte System Dim nxt As Dword System Dim Vels[NrTasks] As Byte '----------------------------------------------------------------------------------------- ' Load the USART Interrupt handler And buffer read subroutines into memory 'Include "ADC.inc" ' Load the ADC macros into the program - used in the IRQ include. Dim IndexIn As Byte System Dim Indexout As Byte System Dim Ringbuffer[256] As Byte Include "Boot_Irq.inc" ' our own basic version for UART And Timer0/3 Interrupt, 12.2019 Include "HPWM10.inc" ' for 9 and 10-bit PWM ' if we dont include this, we default to 8 bit PWM $ifdef _HPWM10_INC_ 'OpenAnalog10 ' for 10-bit pwm 39kHz OpenAnalog9 ' for 9 bit pwm 19kHz $endif Dim Outbuffer[256] As Byte ' midi-outputbuffer for delay! Dim OutIdxIn As Byte System ' write idx pointer Dim OutIdxOut As Byte System ' read idx pointer 'framework for a multitasker, version 2019/2020 Dim TimVals[NrTasks] As Dword Dim Resort As Byte System Dim Resort_flag As Resort.0 ' flag to signal the requirement to resort timers Dim Dur[128] As Word ' duration lookup Dim Puls[128] As Word ' pulse durations for voetje 'make sure we initialize the used pins on start up: Low Hyb Low AC1 Low AC2 Low AC3 Low AC4 Low Debug_Led Low Lite14 Low Lite15 Low Blue Low Green_Led $ifndef _HPWM10_INC_ HPWM 2, 0, fPWM ' connected to RC1 lite 13 HPWM 1, 0, fPWM ' connected to RC2 lite 12 $else WriteAnalog1 0 WriteAnalog2 0 $endif Clear CC66 GoSub Dur_Lookup GoSub Puls_Lookup '----------------------------------------------------------------------------------------- ' Main program starts here MAIN: 'High Debug_Led DelayMS 50 ' wait for stability Low Debug_Led Low Lite14 Low Lite15 Low Blue Low Hyb Low Green_Led Set idx Set TimVals Clear Lites Clear PowerOn GoSub Init_Usart_Interrupt ' Initiate the USART serial buffer interrupt ' this procedure is in the include file GoSub Clear_Serial_Buffer ' Clear the serial buffer and reset its pointers ' in the include as well ' Configure Timer0 for: ' Clear TMR0L and TMR0H registers ' Interrupt on Timer0 overflow ' 16-bit operation ' Internal clock source 40MHz ' 1:256 Prescaler : thus 40MHz / 256 = 156.250kHz ' Opentimer0 (Timer_INT_On & T0_16BIT & T0_SOURCE_INT & T0_PS_1_256) in macro file. Clear T1CON Clear IntConBits_T0IF ' clear interrupt flag Set INTCONBITS_T0IE ' enable interrupt on overflow T0CON = %10000111 ' bit 7 = enable/disable ' bit 6 = 1=8 bit, 0=16 bit ' bit 5 = 1 pin input, 0= Internal Clk0 ' bit 4 = HL or LH transition when bit5 =1 ' bit 3 = 1= bypass prescaler, 0= input from prescaler ' bit 2-0 = prescaler select: 111= 1:256 ' Setup the High priorities for the interrupts ' open and start timer3 for sampling: Clear T3CON Clear PIR2BITS_TMR3IF ' clear IRQ flag Set PIE2BITS_TMR3IE ' irq on ' Clear Tim3 ' Clear TMR3L And TMR3H registers Set RCONbits_IPEN ' Enable priority interrupts Clear IPR2bits_TMR3IP ' Set Timer3 as a low priority interrupt source ' we can also set T3Con in one instruction as: T3CON = %10110000 ' oef, now it works... ' bit 7 = 16 bit mode ' bit 6,3 = 0, 0 ' bit 5,4 = 1:8 prescale ' bit 2 = 0 ' bit 1 = 0 Internal clock = Fosc/4 ' bit 0 : 1= enable timer 3, 0= disable set to 0 for Whisper! ' maximum count = 52.42ms, 1 tick =0.8uS, lowest freq.=19Hz ' HRSOut Ctrl, 66, 64 ' dummy, 2019 Clear Outbuffer Clear OutIdxIn Clear OutIdxOut ' start the main program loop: Do ' Create an infinite loop Cnt.Word0 = CntLw ' read timer, note time is an alias for Cnt GetMidiIn () Bytein = MidiIn ' Read data from the serial buffer, with no timeout ' Start the midi parser. Midi_Parse: If Bytein > Control_Status Then ' here higher statusses are not implemented. If Bytein > 253 Then '254 = midiclock, 255= reset 'midiclock can interrupt all other msg's... '255 had to be intercepted since thats what we 'get when no new byte flows in (?) GoTo Check_Timers 'throw away... Else Clear statusbyte 'reset the status byte GoTo Check_Timers 'throw away End If EndIf If StBit =1 Then 'should be faster than If Bytein > 127 Then 'status byte received, bit 7 is set Clear statusbyte 'if on another channel, the statusbyte needs a reset Select Bytein 'eqv to Select case ByteIn Case NoteOff_Status statusbyte = Bytein Set noteUit 'reset value. Cannot be 0 !!! Set release '0 is a valid midi note! Case NoteOn_Status statusbyte = Bytein Set noteAan Set velo Case Keypres_Status ' used for lights statusbyte = Bytein Set notePres Set pres Case Control_Status statusbyte = Bytein Set Ctrl Set value ' Case ProgChange_Status ' statusbyte = Bytein ' Set prog ' Case Aftertouch_Status ' statusbyte = Bytein ' set aft ' Case Pitchbend_Status ' statusbyte = Bytein ' set pblsb ' set pbmsb End Select Else 'midi byte is 7 bits Select statusbyte Case 0 'not a message for this channel GoTo Check_Timers 'disregard Case NoteOff_Status If noteUit = 255 Then noteUit = Bytein Else release = Bytein 'message complete, so we can do the action... Select noteUit Case 24 Clear AC1 Case 25 Clear AC2 Case 26 Clear AC3 Case 27 Clear AC4 Case 33 To 108 ' notes If PowerOn = 1 Then HRSOut NoteOff_Status, noteUit, release EndIf Case 115 To 124 ' lights on Hybr If PowerOn = 1 Then HRSOut NoteOff_Status, noteUit, release EndIf Case 12 $ifndef _HPWM10_INC_ HPWM 1, 0, fPWM ' connected to RC2 $else WriteAnalog1 0 $endif Case 13 $ifndef _HPWM10_INC_ HPWM 2, 0, fPWM ' connected to RC1 $else WriteAnalog2 0 $endif Case 14 Clear Lites.0 Set TimVals[0] Set Resort_flag Clear Lite14 Case 15 Clear Lites.1 Set TimVals[1] Set Resort_flag Clear Lite15 Case 16 ' blue Clear Lites.2 Set TimVals[2] Set Resort_flag Clear Blue EndSelect Set noteUit 'reset EndIf Case NoteOn_Status If noteAan = 255 Then noteAan = Bytein Else velo = Bytein If velo = 0 Then Select noteAan Case 33 To 108 If PowerOn = 1 Then HRSOut NoteOn_Status, noteAan, velo EndIf Case 114 To 124 If PowerOn = 1 Then HRSOut NoteOn_Status, noteAan, velo EndIf Case 24 Clear AC1 Case 25 Clear AC2 Case 26 Clear AC3 Case 27 Clear AC4 Case 12 $ifndef _HPWM10_INC_ HPWM 1, 0, fPWM ' connected to RC2 $else WriteAnalog1 0 $endif Case 13 $ifndef _HPWM10_INC_ HPWM 2, 0, fPWM ' connected to RC2 $else WriteAnalog2 0 $endif Case 14 Clear Lites.0 Set TimVals[0] Set Resort_flag Clear Lite14 Case 15 Clear Lites.1 Set TimVals[1] Set Resort_flag Clear Lite15 Case 16 ' blue Clear Lites.2 Set TimVals[2] Set Resort_flag Clear Blue EndSelect Else ' else for velo=0 ' in this case velo is > 0 Select noteAan Case 33 To 108 If PowerOn = 1 Then HRSOut NoteOn_Status, noteAan, velo EndIf Case 115 To 124 If PowerOn = 1 Then HRSOut NoteOn_Status, noteAan, velo EndIf Case 12 $ifndef _HPWM10_INC_ HPWM 1, velo << 1, fPWM ' connected to RC2 $else WriteAnalog1 velo << 2 $endif Case 13 $ifndef _HPWM10_INC_ HPWM 2, velo << 1, fPWM ' connected to RC1 $else WriteAnalog2 velo << 2 $endif Case 14 Set Lite14 Set Lites.0 If velo < 127 Then TimVals[0] = time + Dur[velo] Else Set TimVals[0] EndIf Vels[0] = velo Set Resort_flag Case 15 Set Lite15 Set Lites.1 If velo < 127 Then TimVals[1] = time + Dur[velo] Else Set TimVals[1] EndIf Vels[1] = velo Set Resort_flag Case 16 Set Blue Set Lites.2 If velo < 127 Then TimVals[2] = time + Dur[velo] Else Set TimVals[2] EndIf Vels[2] = velo Set Resort_flag Case 24 Set AC1 Case 25 Set AC2 Case 26 Set AC3 Case 27 Set AC4 EndSelect EndIf Set noteAan EndIf Case Keypres_Status 'used for lite flashing speed modulation If notePres = 255 Then notePres = Bytein Else pres = Bytein GoSub KeyPres ' sub must handle output to Hybr EndIf Case Control_Status 'this is where the action takes place for controllers If Ctrl = 255 Then Ctrl = Bytein Else value = Bytein GoSub Controller EndIf ' Case ProgChange_Status ' If prog = 255 Then 'single byte message ' prog = Bytein 'weak coding... ' GoSub ProgChange 'is prog. change implemented on Hybr? ' EndIf ' case Aftertouch_status ' case Pitchbend_Status EndSelect EndIf If Resort_flag = 1 Then GoSub SortTimers ' so we resort only if an incoming midi command changed something with the timers EndIf Check_Timers: If idx < NrTasks Then ' we moeten alleen checken wanneer er een timer loopt If time >= nxt Then ' nagaan of de eerstvolgende timer afgelopen is... ' in dit geval is de eerste timer afgelopen en moeten we de juiste aktie ondernemen: Set nxt.31 ' timer reset, is immers afgelopen ' aan de hand van idx weten we welke timer dit is ' clear notes.idx dit slikt de compiler niet... Select idx Case 0 If Lites.0 = 0 Then 'stop task, as lite is switched off Set TimVals[0] Clear Lite14 Else 'reload task0 - light i = Vels[0] 'compiler refuses the notation Dur[Vels[0]] TimVals[0] = time + Dur[i] 'here we need the rsi value to be used... Btg Lite14 'Toggle EndIf Case 1 If Lites.1 = 0 Then Set TimVals[1] 'stop task, as lite is switched off Clear Lite15 Else i = Vels[1] TimVals[1] = time + Dur[i] Btg Lite15 EndIf Case 2 If Lites.2 = 0 Then Set TimVals[2] Clear Blue Else i = Vels[2] TimVals[2] = time + Dur[i] Btg Blue EndIf Case 3 ' one shot voor controller 66 HRSOut Control_Status, 66, 64 ' send power ON command to Hybr and HybrHi Set PowerOn Set Green_Led Set TimVals[3] ' clear the timer Case 4 ' wait time after power down, to let the capacitors discharge. Clear Shutting_down ' clear flag Clear Blue Set TimVals[4] ' clear the timer ' Case Else ' ' in dit geval is idx geset ' GoTo jumpout ' no need to resort EndSelect GoSub SortTimers ' find a new nxt and idx EndIf Else ' idx >= NrTasks, no timers running, so to avoid overflows, we can reset the timer If maxtim = 1 Then Clear Cnt ' = time Set TimVals Clear Lites EndIf EndIf ' here we insert a toggle bit to measure the loopspeed. jumpout: Btg Loopspeed Loop ' end of the main loop SortTimers: 'look up the next smallest timer value in the Timvals array ' zoek de de volgende kleinste timer waarde: Set idx ' makes it 255 Set nxt.31 ' nxt is set on entry. - for speed, we just set the highest bit For i = 0 To NrTasks -1 If TimVals[i] < nxt Then nxt = TimVals[i] ' NrTasks dword comparisons idx = i EndIf Next i Clear Resort_flag Return KeyPres: 'the note to which the pressure should be applied is passed in NotePres, the value in Pres 'here we use it for flashing lights, shaking the shaker and slow PWM the gambling machine... '20.08.2013: coding modified such that the repetition period is only refreshed after the previous ' timer flip over. ' Thus we can make smoother accel. and decel. '17.02.2020: version '26.02.2020: Select notePres Case 33 To 108 If PowerOn = 1 Then HRSOut Keypres_Status, notePres, pres EndIf Case 118 To 127 ' not sure whether this is implemented for the lights If PowerOn = 1 Then HRSOut Keypres_Status, notePres, pres EndIf Case 12 $ifndef _HPWM10_INC_ j = pres << 1 HPWM 1, j, fPWM ' connected to RC2 $else j = pres << 2 ' j must be word! WriteAnalog1 j $endif Case 13 $ifndef _HPWM10_INC_ j = pres << 1 HPWM 2, j, fPWM ' connected to RC1 $else j = pres << 2 ' j must be word! WriteAnalog2 j $endif Case 14 If Lites.0 = 1 Then TimVals[0] = time + Dur[pres] Vels[0] = pres Else Set TimVals[0] Clear Lite14 EndIf Set Resort_flag Case 15 If Lites.1 = 1 Then TimVals[1] = time + Dur[pres] Vels[1] = pres Else Set TimVals[1] Clear Lite15 EndIf Set Resort_flag Case 16 If Lites.2 = 1 Then TimVals[2] = time + Dur[pres] Vels[2] = pres Else Set TimVals[2] Clear Blue EndIf Set Resort_flag End Select Set notePres '= 255 Return 'ProgChange: ' ' is this implemented on Hybr??? ' If PowerOn = 1 Then ' HRSOut statusbyte, prog ' EndIf ' Set prog '= 255 'this is not realy required 'Return 'Pitchbend: ' 'not implemented on Hybr and HybrHi ' ' if poweron = 1 then ' ' HRSOut statusbyte, pblsb, pbmsb ' ' endif ' Set pblsb '= 255 'Return 'Aftertouch: ' 'this is the channel aftertouch, affecting all notes ' 'not implemented on Hybr nor HybrHi ' ' if PowerOn = 1 then ' ' HRSOut statusbyte, aft ' ' endif ' Set aft '= 255 'not mandatory 'Return Controller: Select Ctrl Case 1 To 7 If PowerOn = 1 Then HRSOut Control_Status, Ctrl, value EndIf Case 13 If PowerOn = 1 Then HRSOut Control_Status, Ctrl, value EndIf Case 16 To 63 If PowerOn = 1 Then HRSOut Control_Status, Ctrl, value EndIf Case 66 'on/off for the robot 'here we must start a timer before sending the delayed command to Hybr If value = 0 Then ' power-down ' we may not have time here to send a Ctrl 66 = 0 to hybr here. ' the ARM's need some time to peform the required action, and we ' are cutting their power here right away. If PowerOn = 1 Then ' if power is off, we should not even try this. HRSOut Control_Status, 66, 0 ' give it a try..., if it harms, we should rem this out. EndIf TimVals[4] = time + dischargetime ' make sure we give the capacitors time to discharge!!! Clear PowerOn 'CC66.0 ' this disables all midi messages to Hybr Set Shutting_down ' set the shut down flag, cleared in the timer. Low Hyb ' unpower Hybr and HybrHi Clear Green_Led GoSub PowerDown ' for functions on this board, sets resort_flag Else ' powering up of Hybr and HybrHi If Shutting_down = 0 Then ' in this case we can start-up If PowerOn = 0 Then ' if it's already switched on, dont do it again!!! TimVals[3] = time + delaytime ' ctrl 66 is sent to Hybr in the timer Set Resort_flag ' the PowerOn flag also is set in the timer High Hyb Clear Blue Else HRSOut Control_Status, 66, 127 ' it would be harmless to do this EndIf Else ' if it is still shutting down, we refuse the command. ' set the blue light as a warning: Clear Green_Led ' show that we are not powered up! Set Blue EndIf EndIf Case 67 To 113 If PowerOn = 1 Then HRSOut Control_Status, Ctrl, value EndIf Case 123 If PowerOn = 1 Then HRSOut Control_Status, 123, value EndIf GoSub AllNotesOff Case 124 If PowerOn = 1 Then HRSOut Control_Status, 124, value EndIf End Select Set Ctrl 'mandatory reset Return AllNotesOff: 'SET TimVals ' dont do all! we should not cancel the power on/off timers! Set TimVals[0] Set TimVals[1] Set TimVals[2] Set Resort_flag Clear Lite14 Clear Lite15 Clear Blue $ifndef _HPWM10_INC_ HPWM 2, 0, fPWM ' connected to RC1 HPWM 1, 0, fPWM ' RC2 $else WriteAnalog2 0 WriteAnalog1 0 $endif Return PowerDown: 'SET TimVals Set TimVals[0] Set TimVals[1] Set TimVals[2] Set Resort_flag Clear Lite14 Clear Lite15 Clear Blue $ifndef _HPWM10_INC_ HPWM 2, 0, fPWM ' connected to RC1 HPWM 1, 0, fPWM ' RC2 $else WriteAnalog2 0 WriteAnalog1 0 $endif Return Dur_Lookup: 'this lookup is for a good scaling of the velocity byte on event periodicity ' the values are calculated based on a timer resolution of 24 microseconds. ' The values must be containable in a word (16 bits!) ' This is the simple Power Basic program wherewith the lookup was calculated: 'FUNCTION PBMAIN ()AS LONG ' OPEN "Whisper_Dur_scales.inc" FOR OUTPUT AS #1 ' LOCAL unit, fastest, slowest, velo_traject AS DOUBLE ' LOCAL velo, i AS DWORD ' unit = 0.000024 ' in seconds (24 microseconds) ' fastest = 1 / 16 ' 16 Hz ' slowest = 1.5 ' 0.66 Hz ' velo_traject = slowest - fastest ' PRINT# 1, "Lookup for Whisper durations in periodic events" ' FOR i = 1 TO 127 ' velo = velo_traject / i ' PRINT i; velo, ' PRINT# 1 ,"Dur[";i;"] ="; velo ' NEXT i 'DO: LOOP UNTIL INKEY$ <> "" 'END FUNCTION Dur[ 1 ] = 59896 Dur[ 2 ] = 29948 Dur[ 3 ] = 19965 Dur[ 4 ] = 14974 Dur[ 5 ] = 11979 Dur[ 6 ] = 9983 Dur[ 7 ] = 8557 Dur[ 8 ] = 7487 Dur[ 9 ] = 6655 Dur[ 10 ] = 5990 Dur[ 11 ] = 5445 Dur[ 12 ] = 4991 Dur[ 13 ] = 4607 Dur[ 14 ] = 4278 Dur[ 15 ] = 3993 Dur[ 16 ] = 3743 Dur[ 17 ] = 3523 Dur[ 18 ] = 3328 Dur[ 19 ] = 3152 Dur[ 20 ] = 2995 Dur[ 21 ] = 2852 Dur[ 22 ] = 2723 Dur[ 23 ] = 2604 Dur[ 24 ] = 2496 Dur[ 25 ] = 2396 Dur[ 26 ] = 2304 Dur[ 27 ] = 2218 Dur[ 28 ] = 2139 Dur[ 29 ] = 2065 Dur[ 30 ] = 1997 Dur[ 31 ] = 1932 Dur[ 32 ] = 1872 Dur[ 33 ] = 1815 Dur[ 34 ] = 1762 Dur[ 35 ] = 1711 Dur[ 36 ] = 1664 Dur[ 37 ] = 1619 Dur[ 38 ] = 1576 Dur[ 39 ] = 1536 Dur[ 40 ] = 1497 Dur[ 41 ] = 1461 Dur[ 42 ] = 1426 Dur[ 43 ] = 1393 Dur[ 44 ] = 1361 Dur[ 45 ] = 1331 Dur[ 46 ] = 1302 Dur[ 47 ] = 1274 Dur[ 48 ] = 1248 Dur[ 49 ] = 1222 Dur[ 50 ] = 1198 Dur[ 51 ] = 1174 Dur[ 52 ] = 1152 Dur[ 53 ] = 1130 Dur[ 54 ] = 1109 Dur[ 55 ] = 1089 Dur[ 56 ] = 1070 Dur[ 57 ] = 1051 Dur[ 58 ] = 1033 Dur[ 59 ] = 1015 Dur[ 60 ] = 998 Dur[ 61 ] = 982 Dur[ 62 ] = 966 Dur[ 63 ] = 951 Dur[ 64 ] = 936 Dur[ 65 ] = 921 Dur[ 66 ] = 908 Dur[ 67 ] = 894 Dur[ 68 ] = 881 Dur[ 69 ] = 868 Dur[ 70 ] = 856 Dur[ 71 ] = 844 Dur[ 72 ] = 832 Dur[ 73 ] = 820 Dur[ 74 ] = 809 Dur[ 75 ] = 799 Dur[ 76 ] = 788 Dur[ 77 ] = 778 Dur[ 78 ] = 768 Dur[ 79 ] = 758 Dur[ 80 ] = 749 Dur[ 81 ] = 739 Dur[ 82 ] = 730 Dur[ 83 ] = 722 Dur[ 84 ] = 713 Dur[ 85 ] = 705 Dur[ 86 ] = 696 Dur[ 87 ] = 688 Dur[ 88 ] = 681 Dur[ 89 ] = 673 Dur[ 90 ] = 666 Dur[ 91 ] = 658 Dur[ 92 ] = 651 Dur[ 93 ] = 644 Dur[ 94 ] = 637 Dur[ 95 ] = 630 Dur[ 96 ] = 624 Dur[ 97 ] = 617 Dur[ 98 ] = 611 Dur[ 99 ] = 605 Dur[ 100 ] = 599 Dur[ 101 ] = 593 Dur[ 102 ] = 587 Dur[ 103 ] = 582 Dur[ 104 ] = 576 Dur[ 105 ] = 570 Dur[ 106 ] = 565 Dur[ 107 ] = 560 Dur[ 108 ] = 555 Dur[ 109 ] = 550 Dur[ 110 ] = 545 Dur[ 111 ] = 540 Dur[ 112 ] = 535 Dur[ 113 ] = 530 Dur[ 114 ] = 525 Dur[ 115 ] = 521 Dur[ 116 ] = 516 Dur[ 117 ] = 512 Dur[ 118 ] = 508 Dur[ 119 ] = 503 Dur[ 120 ] = 499 Dur[ 121 ] = 495 Dur[ 122 ] = 491 Dur[ 123 ] = 487 Dur[ 124 ] = 483 Dur[ 125 ] = 479 Dur[ 126 ] = 475 Dur[ 127 ] = 472 Return Puls_Lookup: ' voor voetje ' range must be 62ms to 400ms we guess ' unit = 0.000024 ' in seconds (24 microseconds) ' thus values must be 2583 to 16666 ' one step is then (16666 - 2583) / 127 = 111 Puls[0] = 0 Puls[1] = 2583 For i = 2 To 127 Puls[i] = Puls[i-1] + 111 Next i Return '[EOF]