'=============================================================================== ' ' V E R S A T I L E E N G I N E S O U N D U N I T ' ' PROGRAM 2 OF 4 - SOUND GENERATION (PETROL) ' '=============================================================================== ' VERSION 2.0 14th October 2008 © A.F.Bond 2008 ' ' (ONLY FOR USE IN CONJUNCTION WITH v2.0 SPEED DEMAND MODULE) '=============================================================================== ' ' This module uses one of the PIC's ADCs to read a speed demand voltage and ' then uses that value to create a variable frequency output signal. The output ' signal comprises repeated cycles of a short burst of pseudo-random noise ' (to simulate an exhaust pulse) followed by a longer period of silence. The ' repetition rate of this cycle is organised to be proportional to the speed ' demand voltage. ' ' To give the engine a characteristic 'beat', a slightly different pitch of ' pseudo-random noise is assigned to each of the cylinders before looping round ' to repeat the sequence. ' ' A jumper link is read at program launch and its state determines if the ' cylinder selection mode is entered. If so, then the program succesively plays ' a few seconds of fixed speed sound from the 2,3,4,5 or 6 cylinder engine ' variants. Removing the link during one of these periods locks the chip into ' that mode. The cylinder count value is then stored in the PICAXE's EEPROM ie ' non-volatile memory, so that when the link is in the 'engine run' position the ' cylinder count previously set by the user can be read at power up. ' ' A counter is enabled whenever the engine is detected to be idling, and if a ' time-out value is reached, the engine enters a several second phase where it ' slowly runs down to a halt. Opening the throttle again causes a short 'cranking' ' sound to be issued before the engine begins to run again. ' ' ' NOTE: In the description below be aware that PIN1, PIN2 etc are virtual ' pins and not to be confused with the device's phyical pins, which in PIC ' parlance are refered to as 'legs' ' '=============================================================================== 'VARIABLE DEFINITIONS symbol pawse=w3 'time between exhaust pulses: note spelling ("pause" 'is a reserved word) symbol running =b1 'engine running flag (1=running 0=stopped) symbol demand=b2 'speed demand input, read from ADC on "pin4" (leg 3) symbol kount=b3 'general purpose counter 'note spelling ("count" is a reserved word) symbol idle_count=w2 'counts revolutions at idle symbol timeout = w6 'number of revolutions at idle before engine stops symbol p=b8 'exhaust pitch (passed from sound lookup table) symbol t=b9 'exhaust duration (passed from sound lookup table) symbol cyl_count=b10 'number of cylinders in engine 'note numbering begins at 0 as the lookup tables 'have a zero'th element. The length of the tables 'restricts the maximum cylinder count to six symbol cownt=b11 'another general purpose counter 'note spelling ("count" is a reserved word) 'CONSTANT DEFINITIONS symbol neutral_LED=0 'neutral LED driven from "pin0" (leg 7) high=ON 'EXPERIMENT WITH THESE VALUES TO CHANGE THE DYNAMICS OF THE ENGINE symbol tickover =7000 'as these values define the pause between each symbol topspeed =200 'cylinder firing then their numerical sense is 'inversely related to engine speed symbol revrange =25 'this is a multiplier or 'gain' factor that is 'applied to the speed demand input to the module 'ie adjusts the throttle sensitivity from tickover 'towards topspeed symbol limit=tickover-topspeed 'a derived value which is used to limit the 'top speed if the revrange multiplier is 'set too high symbol holt=20000 'the speed below tickover at which engine stops 'note spelling ("halt" or "stop" are reserved words) symbol rate = 1500 'rate of engine run-down to a stop 'EXPERIMENT WITH THESE VALUES TO CHANGE THE CHARACTER OF THE ENGINE 'values must lie in the range 128 to 255 symbol p1=235 'pitch of pseudo random sound for cylinder 1 symbol p2=133 '. . . . . . . . . . . . . . . . . . . . . 2 symbol p3=238 '. . . . . . . . . . . . . . . . . . . . . 3 symbol p4=243 '. . . . . . . . . . . . . . . . . . . . . 4 symbol p5=230 '. . . . . . . . . . . . . . . . . . . . . 5 symbol p6=244 '. . . . . . . . . . . . . . . . . . . . . 6 symbol d1=2 'duration of pseudo random sound for cylinder 1 symbol d2=4 '. . . . . . . . . . . . . . . . . . . . . . .2 symbol d3=2 '. . . . . . . . . . . . . . . . . . . . . . .3 symbol d4=2 '. . . . . . . . . . . . . . . . . . . . . . .4 symbol d5=2 '. . . . . . . . . . . . . . . . . . . . . . .5 symbol d6=2 '. . . . . . . . . . . . . . . . . . . . . . .6 'CHIP PROGRAMMING DIRECTIVE (only executed when program is loaded into chip) 'Pre-load non-zero value into EEPROM storage location 0 (cylinder count) data 0, (3) 'set default cylinder count to 4 '========================= PROGRAM STARTS HERE ================================ 'INITIALISATION setfreq m8 'set 8Mhz operation to yield 5uSec resolution init: if pin3=0 then 'check jumper link 'CYLINDER SELECT MODE SELECTED high neutral_LED 'turn on LED sound 1,(120,60) 'warning beep for cyl_count=1 to 5 'step through all cylinder values (omit single cyl) pause 2000 '1 sec pause between variants (8Mhz doubles values) for kount=0 to 15 'run for sixteen engine cycles for cownt= 0 to cyl_count 'for each cylinder in turn lookup cownt,(p1,p2,p3,p4,p5,p6),p 'get its exhaust pitch lookup cownt,(d1,d2,d3,d4,d5,d6),t 'get its exhaust duration sound 1,(p,t) 'make exhaust noise pause 60 'silence until next cylinder fires next cownt next kount if pin3=1 then 'has user selected the current cylinder variant? write 0,cyl_count 'YES - store value in non-volatile memory sound 1,(120,10) 'acknowledge with a beep goto init2 'and jump out of cylinder select mode end if 'NO - try next cylinder count next cyl_count goto init 'no selection made, loop round again else 'ENGINE RUN MODE read 0, cyl_count 'get cylinder count previously stored in EEPROM end if init2: 'set number of idle revs for approx 1 minute, adjusting for cylinder count 'note: variable is re-used rather than having to assign another word variable timeout=cyl_count+1 timeout=290*4/timeout 'ie 290 is approx 1 minute for 4 cyl engine 'MAIN LOOP main: readadc 4,demand 'check speed demand status with ADC4 if running=1 then 'ENGINE RUNNING 'process speed demand value and assign value to 'pawse' pawse=demand*revrange max limit 'set spread of speed, limiting if necessary pawse=tickover-pawse 'numerical sense of pawse is inversely related 'to speed (see above) 'generate a cycle of engine sound for cownt=0 to cyl_count 'for each cylinder in turn lookup cownt,(p1,p2,p3,p4,p5,p6),p 'get its exhaust pitch lookup cownt,(d1,d2,d3,d4,d5,d6),t 'get its exhaust duration sound 1,(p,t) 'make exhaust noise pulsout 2,pawse 'silence until next cylinder fires next 'check if speed demand is IDLE if demand<10 then 'ENGINE IDLING high neutral_LED 'LED on idle_count=idle_count+1 'increment idle time-out counter else 'NOT IDLING low neutral_LED 'LED off idle_count=0 'reset idle time-out counter end if 'check if engine stop required if idle_count>timeout then 'STOP ENGINE for pawse=tickover to holt step rate 'gradually slow engine 'generate a cycle of engine sound for cownt=0 to cyl_count 'for each cylinder in turn lookup cownt,(p1,p2,p3,p4,p5,p6),p 'get its exhaust pitch lookup cownt,(d1,d2,d3,d4,d5,d6),t 'get its exhaust duration sound 1,(p,t) 'make exhaust noise pulsout 2,pawse 'silence until next cylinder fires next cownt next pawse running=0 'clear "engine is running" flag end if 'from here program drops through to final "goto main" statement else 'ENGINE IS NOT RUNNING 'but has demand been increased from idle in the meantime? if demand>10 then 'YES - START ENGINE for cownt=150 to 25 step -25 'make primitive engine cranking noise sound 1,(185,6) sound 1,(205,3) sound 1,(235,2) 'some experimentation may be of benefit! sound 1,(254,2) 'or omit this for-next loop altogether pause cownt 'for instant start next 'but leave this next line in! running=1 'set "engine is running" flag else 'NO - ENGINE REMAINS STOPPED toggle neutral_LED 'flicker neutral LED to signify stopped pause 80 'sets rate of flicker end if end if goto main '=============================================================================== ' VERSION HISTORY '=============================================================================== 'v1.0 1st October 2008 'first release 'v2.0 14th October 2008 'Logarithmic lookup table function moved into the speed demand module, which 'allowed a longer lookup table to be used without code execution time problems 'as the speed demand code only has to run at the transmitter frame rate rather 'than the engine revolution rate. The resulting throttle response of the 'overall system is thereby much smoother. ' 'The program space saved by exporting the speed lookup table has been used to 'rework the speed demand processing to give single numeric values (for user 'experimentation) to set the tickover speed and the revs range plus a top speed 'limiter which operates if the revs range multiplier is set too high. ' 'The timing for main engine loop now uses 'pulsout' (to an unused output) to 'create the inter-cylinder delays rather than the 'pause' statement. Much 'larger values for an equivalent delay result, meaning that the speed resolution '(ie size of the steps between succesive values) is much improved. ' 'Again, utilising the increased program space, it has now been possible to vary 'the 'timeout' value with the cylinder count to yield the same idling period 'prior to cut-off regardless of the number of cylinders chosen. '===============================================================================