;-----------------------------------------------------------------------------------------------; ; Program: Clock ; ; Developed by David J. Brown ; ; Copyright (c) April 13, 2004 David J. Brown ; ; Email: davebr@earthlink.net ; ; Web site: http://modularsynthesis.com ; ;-----------------------------------------------------------------------------------------------; ; LICENSE AGREEMENT: ; ; This program is free software. You can redistribute it and/or modify it. ; ; ; ; This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, ; ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ; ;-----------------------------------------------------------------------------------------------; ; ; Description: ; ; This program displays the time and also speaks the time ; when start is true and also on the hour. The seconds are ; captured when start is pressed. The time spoken is thus the ; time when start was pressed, not the current time (e.g. ; it is off by the number of seconds required to speak the ; time). ; ; Set the initial starting time in lines 475 - 479 ; ; inputs: ; start = speak time ; stop = ; in-1 = ; in-2 = ; in-3 = ; in-4 = ; aux = ; midi-in = ; ; outputs: ; out-1 = ; out-2 = ; out-3 = ; out-4 = ; aux = ; midi-out= ; speakjet= voice output ; ; run led = toggles @ 1S ; stop led = ; ; written by David J. Brown ; revision: 0.6 ; April 11, 2010 ; history: 0.6 removed debug_led and updated debug_speakjet ; to eliminiate push/pop ; 0.5 changed speakjet to i2c protocol ; 0.4 added display of time ; 0.3 added display of program name ; 0.2 added time_flg for on-the-hour announcements ; 0.1 changed gra=2001 for accurate time ; 0.0 initial release of SpeakJet Clock ; written: January 1, 2005 ; ;########################################### ; ; ### CONDITIONAL COMPILING OPTION ### ; set MIDI INTERRUPT mode ; ; comment out next line for polled mode ; midi_int_en con 1 ;define to enable midi-in interrupts ; comment to set polled midi-in mode ; ;########################################### ; ; ### CONDITIONAL COMPILING OPTION ### ; set TIMER INTERRUPT mode ; note: Run led will blink if timer_int_en defined ; ; comment out next line to disable timer interrupts timer_int_en con 1 ;define to enable timer interrupts ; comment to disable timer interrupts ; ;########################################### ; ; ### CONDITIONAL COMPILING OPTION ### ; set INPUT INTERRUPT mode ; note: Requires timer_int_en to be defined ; Speakjet and console serial output is not compatible with this mode ; ; comment out next line to disable input interrupts ' input_int_en con 1 ;define to enable input interrupt mode ; comment to set polled input mode ; ;########################################### ; ;psim template written by David J. Brown ;based on code from Brice Hornback and Grant Richter ;revision: 0.44 ; December 18, 2004 ;history: 0.44 streamlined debug_speakjet routine ; 0.43 corrected send_speakjet pin label error, changed ; display_led to debug_led, changed send_console to ; debug_console, added debug_speakjet routine, changed ; led_data and con_data to debug_data ; 0.42 renamed start_b to start_j, renamed stop_b to ; stop_j, added push/pop to display_led, changed ; comment delimiter to semicolon, added send_console ; routine, re-aliased input pins, sends midi all notes ; off during initialization, added midi program change ; 0.41 upper case conversion to lower, variables and ; labels renamed ; 0.4 added averaged input input driver (polled or ; interrupt mode), display_led driver (for debug), ; speakjet driver, renamed program to djb template ; 0.3 added program header information, modified ; pin initialization ; 0.2 initialize aux output low and speakjet pins ; 0.1 added DAC & led initialization, 1 mS timestamp, ; stop led blinks when midi data received, run ; led toggles @ 0.5 S for health indication ; 0.0 initial release of midi input & output program ;date: April 13, 2004 ;******************************************* ; module: PSIM-1 REV1b ; processor Type: Basic Micro - Basic Atom Pro24M ;******************************************* ; ; Basic Micro Atom Pro-24M Configuration ; ; P0 - in-1 ; P1 - in-2 ; P2 - in-3 ; P3 - in-4 ; P4 - start button (momentary normally open switch) ; P5 - stop button (momentary normally open switch) ; P6 - j3 pin 2 (speakjet buffer half full) ; P7 - j3 pin 1 (serial data to speakjet) ; P8 - aux digital I/O ; P9 - stop led ; P10 - run led ; P11 - load_dacs ; P12 - ser_data ; P13 - clock ; P14 - j5 pin 1 (midi-in) ; P15 - j5 pin 2 (midi-out) ; ;******************************************* ; ;pin declarations pin_j1 con p0 ;in-1 pin pin_j2 con p1 ;in-2 pin pin_j3 con p2 ;in-3 pin pin_j4 con p3 ;in-4 pin start_j var in4 ;start jack and switch stop_j var in5 ;stop jack and switch spkj_full var in6 ;speakjet buffer half full spkj_sdata con p7 ;speakjet data aux_j con p8 ;aux jack (output mode) aux_in var in8 ;aux jack (input mode) stop_led con p9 ;stop led (red) stop_led_out var out9 ;variable alias for let command run_led con p10 ;run led (green) run_led_out var out10 ;variable alias for let command load_dacs con p11 'load dac pin ser_data con p12 'serial data to dac pin clock con p13 'dac clock pin midi_sdata con p15 ;midi data serial output ;i/o declarations in_j1 var word ;in-1 value: get_inputs, get_inputs_avg, avg1 in_j2 var word ;in-2 value: get_inputs, get_inputs_avg, avc2 in_j3 var word ;in-3 value: get_inputs, get_inputs_avg, avg3 in_j4 var word ;in-4 value: get_inputs, get_inputs_avg, avg4 out_j1 var word ;out-1 value: load_outputs out_j2 var word ;out-2 value: load_outputs out_j3 var word ;out-3 value: load_outputs out_j4 var word ;out-4 value: load_outputs ;midi variable declarations note_off con $80 ;midi note-off command: send_note_on, send_note_off note_on con $90 ;midi note-on command: send_note_on, send_note_off pgm_chg con $c0 'midi program change command:send_prog_change midi_chan var nib ;midi channel (0 - 15): send_note_on, send_note_off midi_note var byte ;midi note value: send_note_on, send_note_off midi_vel var byte ;midi velocity value: send_note_on, send_note_off midi_pgm var byte 'midi program change value:send_prog_change ;midi driver variable declarations midi_data var byte ;variable: check_midi, send_midi, get_rcx_bfr, send_note_on, send_note_off midi_data_isr var byte ;variable: midi_in_isr rcx_status var byte ;variable: check_midi, send_midi rcx_ptr_strt var byte ;received data start pointer (first data in buffer): get_rcx_bfr rcx_ptr_end var byte ;received data end pointer (last data in buffer+1): check_midi, midi_in_isr rcx_bfr_num var byte ;number of bytes in data buffer: check_midi, get_rcx_bfr, midi_in_isr rcx_data_flg var bit ;received data flag (1=data, 0=no data): get_rcx_bfr rcx_bfr_len con 32 ;midi-in buffer length: rcx_bfr rcx_bfr var byte(rcx_bfr_len) ;midi-in data buffer: check_midi, get_rcx_bfr, midi_in_isr ;timer declarations #ifdef timer_int_en time_count var long ;1 mS timer count value: tm_isr turn_off var long ;time value to turn off stop led: tm_isr #endif ;input buffer declarations in_j1_ptr var byte ;in-1 buffer pointer: avgx, get_inputs_avg #ifdef input_int_en in_j2_ptr var byte ;in-2 buffer pointer: avgx in_j3_ptr var byte ;in-3 buffer pointer: avgx in_j4_ptr var byte ;in-4 buffer pointer: avgx isr_cnt var nib ;timer pass counter: tm_isr #endif in_j1_tmp var long ;in-1 temporary variable: avgx, get_inputs_avg in_j2_tmp var long ;in-2 temporary variable: avgx, get_inputs_avg in_j3_tmp var long ;in-3 temporary variable: avgx, get_inputs_avg in_j4_tmp var long ;in-4 temporary variable: avgx, get_inputs_avg in_j1_bfr var long(2) ;in-1 last 4 samples buffer: avgx, get_inputs_avg in_j2_bfr var long(2) ;in-2 last 4 samples buffer: avgx, get_inputs_avg in_j3_bfr var long(2) ;in-3 last 4 samples buffer: avgx, get_inputs_avg in_j4_bfr var long(2) ;in-4 last 4 samples buffer: avgx, get_inputs_avg ;misc declarations tempb var byte ;temp byte spkj_data var byte ;variable: send_speakjet debug_data var byte ;variable: debug_led, debug_console, debug_speakjet p_index var word ;phrase index counter: debug_speakjet fivevolts con 1920 ;5 volt output value ;clock declarations sec_1 var byte ;seconds count sec_1tmp var byte ;temporary for seconds sec_10 var byte ;tens of seconds count sec_10tmp var byte ;temporary for tens of seconds min_1 var byte ;minutes count min_10 var byte ;tens of minutes count hour var byte ;hours count am_pm var byte ;am=0, pm=1 digit var byte ;digit to speak time_flg var byte ;flag for hour ;0 - 19 phrase declarations ;terminate speakjet phrase data with 255 ;bytetable length MUST be even for offsets so pad with extra 255 if necessary ;&%!/# compiler cannot calculate offsets so must define each phrase length len_0 con 12 ;length of data_0 phrase: 'oh' data_0 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 137, 137, 255, 255 len_1 con 8 ;length of data_1 phrase: 'one' data_1 bytetable 147, 014, 136, 008, 141, 006, 255, 255 len_2 con 6 ;length of data_2 phrase: 'two' data_2 bytetable 008, 191, 162, 006, 255, 255 len_3 con 8 ;length of data_3 phrase: 'three' data_3 bytetable 008, 190, 148, 008, 128, 006, 255, 255 len_4 con 6 ;length of data_4 phrase: 'four' data_4 bytetable 186, 007, 137, 153, 006, 255 len_5 con 6 ;length of data_5 phrase: 'five' data_5 bytetable 186, 157, 166, 006, 255, 255 len_6 con 10 ;length of data_6 phrase: 'six' data_6 bytetable 008, 187, 129, 014, 194, 007, 187, 006, 255, 255 len_7 con 10 ;length of data_7 phrase: 'seven' data_7 bytetable 008, 187, 007, 131, 166, 131, 141, 006, 255, 255 len_8 con 6 ;length of data_8 phrase: 'eight' data_8 bytetable 154, 004, 191, 006, 255, 255 len_9 con 6 ;length of data_9 phrase: 'nine' data_9 bytetable 141, 014, 157, 141, 006, 255 len_10 con 14 ;length of data_10 phrase: 'ten' data_10 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 191, 131, 131, 141, 255, 255 len_11 con 18 ;length of data_11 phrase: 'eleven' data_11 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 007, 129, 145, 131, 166, 007, 131, 141, 255, 255 len_12 con 16 ;length of data_12 phrase: 'twelve' data_12 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 008, 191, 007, 147, 131, 145, 166, 255 len_13 con 16 ;length of data_13 phrase: 'thirteen' data_13 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 008, 190, 007, 151, 191, 128, 141, 255 len_14 con 16 ;length of data_14 phrase: 'fourteen' data_14 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 186, 007, 153, 007, 191, 128, 141, 255 len_15 con 16 ;length of data_15 phrase: 'fifteen' data_15 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 186, 129, 186, 191, 128, 141, 255, 255 len_16 con 20 ;length of data_16 phrase: 'sixteen' data_16 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 008, 187, 007, 129, 014, 194, 187, 007, 191, 128, 141, 255 len_17 con 22 ;length of data_17 phrase: 'seventeen' data_17 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 008, 187, 007, 131, 007, 166, 007, 131, 141, 007, 191, 128, 141, 255 len_18 con 14 ;length of data_18 phrase: 'eighteen' data_18 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 154, 004, 191, 128, 141, 255 len_19 con 18 ;length of data_19 phrase: 'nineteen' data_19 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 141, 007, 105, 155, 141, 191, 128, 008, 141, 255 ;phrase offset calculations for table off_0 con 0 ;offset to data_0 off_1 con off_0+len_0 ;offset to data_1 off_2 con off_1+len_1 ;offset to data_2 off_3 con off_2+len_2 ;offset to data_3 off_4 con off_3+len_3 ;offset to data_4 off_5 con off_4+len_4 ;offset to data_5 off_6 con off_5+len_5 ;offset to data_6 off_7 con off_6+len_6 ;offset to data_7 off_8 con off_7+len_7 ;offset to data_8 off_9 con off_8+len_8 ;offset to data_9 off_10 con off_9+len_9 ;offset to data_A off_11 con off_10+len_10 ;offset to data_B off_12 con off_11+len_11 ;offset to data_C off_13 con off_12+len_12 ;offset to data_D off_14 con off_13+len_13 ;offset to data_E off_15 con off_14+len_14 ;offset to data_F off_16 con off_15+len_15 ;offset to data_A off_17 con off_16+len_16 ;offset to data_B off_18 con off_17+len_17 ;offset to data_C off_19 con off_18+len_18 ;offset to data_D ;phrase offset table p_len bytetable off_0,off_1,off_2,off_3,off_4,off_5,off_6,off_7,off_8,off_9,| off_10,off_11,off_12,off_13,off_14,off_15,off_16,off_17,off_18,off_19 ;10's - 50's phrase declarations len_00 con 12 ;length of data_0 phrase: 'oh' data_00 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 137, 137, 255, 255 len_ten con 14 ;length of data_ten phrase: 'ten' data_ten bytetable 020, 096, 021, 114, 022, 088, 023, 005, 191, 131, 131, 141, 255, 255 len_20 con 20 ;length of data_20 phrase: 'twenty' data_20 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 008, 007, 191, 007, 147, 131, 141, 007, 191, 128, 255, 255 len_30 con 16 ;length of data_30 phrase: 'thirty' data_30 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 008, 190, 007, 151, 191, 128, 255, 255 len_40 con 14 ;length of data_40 phrase: 'forty' data_40 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 186, 007, 153, 191, 128, 255 len_50 con 14 ;length of data_50 phrase: 'fifty' data_50 bytetable 020, 096, 021, 114, 022, 088, 023, 005, 186, 129, 186, 191, 128, 255 ;phrase offset calculations for table off_00 con 0 ;offset to data_00 off_ten con off_00+len_00 ;offset to data_ten off_20 con off_ten+len_ten ;offset to data_20 off_30 con off_20+len_20 ;offset to data_30 off_40 con off_30+len_30 ;offset to data_40 off_50 con off_40+len_40 ;offset to data_50 ;phrase offset table p_len_00 bytetable off_00,off_ten,off_20,off_30,off_40,off_50 ;other phrase declarations ;phrase 'the time is' p_time bytetable 020, 096, 021, 114, 022, 088, 023, 005, 008, 169, 008, 128, 008, 191, 157, 008, 140, 008, 129, 167, 255 ;phrase 'o-clock' p_o bytetable 020, 096, 021, 114, 022, 088, 023, 005, 137, 008, 195, 007, 146, 008, 136, 197, 255 ;phrase 'and' p_and bytetable 020, 096, 021, 114, 022, 088, 023, 005, 008, 132, 008, 141, 177, 255 ; ;phrase 'am' p_am bytetable 020, 096, 021, 114, 022, 088, 023, 005, 154, 128, 131, 131, 140, 255 ; ;phrase 'pm' p_pm bytetable 020, 096, 021, 114, 022, 088, 023, 005, 198, 128, 128, 131, 131, 140, 255 ;phrase 'exactly' p_ex bytetable 020, 096, 021, 114, 022, 088, 023, 005, 130, 196, 188, 132, 194, 191, 145, 128, 255 ; ;phrase 'seconds' p_sec bytetable 020, 096, 021, 114, 022, 088, 023, 005, 008, 187, 131, 195, 133, 141, 177, 167, 255 ; ;ding p_ding bytetable 020, 096, 021, 114, 022, 088, 023, 005, 008, 250, 255 ; ;pause p_pause bytetable 020, 096, 021, 114, 022, 088, 023, 005, 006, 255 ; ;******************************************* ; ;initialize pins ;note: setting midi-out, i2c_clock, and i2c_data to outputs can send glitches so initialize as inputs dirs=%0011111000000000 ;configure pin direction (1=output, 0=input) ;inputs: midi-in, aux, start, stop, in-4, in-3, in-2, in-1 ;outputs: load_dacs, ser_data, clock, stop led, run led, i2c clock & data low run_led ;set run led off low stop_led ;set stop led off high load_dacs ;set dac load-0 high low ser_data ;set dac data low low clock ;set dac clock low let out_j1=0 ;set out-1 low let out_j2=0 ;set out-2 low let out_j3=0 ;set out-3 low let out_j4=0 ;set out-4 low gosub load_outputs ; ;initialize midi hardware ;these next 6 commands need to be in this order! let scr3=%00000000 ;reset Serial Control Register let smr=%00000000 ;set Serial Mode Register ; asynchronous ; 8 bits ; parity disabled ; even parity (disabled) ; 1 stop bit ; multiprocessor mode disabled ; brr clock source direct let brr=15 ;set Bit Rate Register for 31500 baud pauseus 100 ;let brr settle for 50 uS let scr3=%00110000 ;set Serial Control Register ; transmit or receive interrupts disabled ; transmit and receive enabled ; multiprocessor interrupt disabled ; transmit end interrupt disabled ; internal baud rate generator let pmr1=%00001110 ;set Port Mode Register ; P17 general I/O port ; P16 general I/O port ; P15 general I/O port ; P14 general I/O port ; txd output ; P10 general I/O port ; #ifdef timer_int_en ;initialize timer hardware for 1 mS interrupts let tmrw=%10001000 ;set Timer Mode Register to enable count let tcrw=%10110000 ;set Timer Control Register ; TCNT cleared by compare match ; /8 internal clock let tierw=%01110000 ;set Timer Interrupt register to disable overflow interrupt let tsrw=%01110000 ;set Timer Status Register to default let tior0=%10001000 ;set Timer I/O Register 0 to default let tior1=%10001000 ;set Timer I/O Register 1 to default let gra=20023 ;set General Register A ; let gra=20000 ;set General Register A ; 16 MHz clock /8 = 2 MHz ; 20000 counts = 10 mS interrupt ;adjusted by external measurement for 10 mS #endif ; ;initialize misc variables let rcx_ptr_strt=0 ;set receive start pointer let rcx_ptr_end=0 ;set receive end pointer let rcx_bfr_num=0 ;set receive buffer to empty let midi_chan=0 ;set midi channel to 0 let midi_note=0 ;set midi note to 0 let midi_vel=$40 ;set default velocity gosub send_all_off ;make sure all notes off let debug_data=0 ;set debug_data to 0 let in_j1_ptr=0 ;set in-1 pointer to 0 #ifdef input_int_en let in_j2_ptr=0 ;set in-2 pointer to 0 let in_j3_ptr=0 ;set in-3 pointer to 0 let in_j4_ptr=0 ;set in-4 pointer to 0 let isr_cnt=0 ;set isr pass counter to 0 #endif let in_j1_bfr(0)=0 ;set in-1 buffer data to 0 let in_j1_bfr(1)=0 let in_j2_bfr(0)=0 ;set in-2 buffer data to 0 let in_j2_bfr(1)=0 let in_j3_bfr(0)=0 ;set in-3 buffer data to 0 let in_j3_bfr(1)=0 let in_j4_bfr(0)=0 ;set in-4 buffer data to 0 let in_j4_bfr(1)=0 ; ;display program name pause 250 ;let processors initialize let midi_data=$f0 ;sysex gosub send_midi let midi_data=$7d ;display id gosub send_midi let midi_data=$0a ;clear display gosub send_midi let midi_data=$18 ;overwrite gosub send_midi let midi_data="S" gosub send_midi let midi_data="p" gosub send_midi let midi_data="e" gosub send_midi let midi_data="a" gosub send_midi let midi_data="k" gosub send_midi let midi_data="J" gosub send_midi let midi_data="e" gosub send_midi let midi_data="t" gosub send_midi let midi_data=" " gosub send_midi let midi_data="C" gosub send_midi let midi_data="l" gosub send_midi let midi_data="o" gosub send_midi let midi_data="c" gosub send_midi let midi_data="k" gosub send_midi let midi_data=" " gosub send_midi let midi_data=" " gosub send_midi let midi_data=$f7 ;end sysex gosub send_midi ;enable TTS256 i2cout p6,p7,$0,[($48<<1),"passthruon",$0d] ;turn pass through mode on ; ;enable timer interrupts #ifdef timer_int_en let time_count=0 ;set real time counter to 0 let turn_off=0 ;set time to turn off to time_count oninterrupt timerwint_imiea, tm_isr enable timerwint_imiea ;enable timer interrupt #endif ; ;enable midi interrupts #ifdef midi_int_en oninterrupt sci3int_rdrf, midi_in_isr enable sci3int_rdrf ;enable midi-in interrupt #endif ; ;initialize correct time let hour=2 ;set initial hours 1 - 12 let min_10=0 ;set initial ten minutes 0 - 5 let min_1=5 ;set initial minutes 0 - 9 let am_pm=1 ;set am=0 or pm=1 ; let sec_10=0 ;initialize seconds to 0 let sec_1=0 let time_flg=0 goto time ;say initial time ; ;main program main: pause 50 if min_10=0 and min_1=0 and sec_10=0 and sec_1=0 then if time_flg=0 then let time_flg=1 goto time endif else let time_flg=0 ;reset on-the-hour flag endif if start_j=0 then main ;speak time when start is true time: let sec_1tmp=sec_1 ;capture seconds (adjusts for delay of speaking) let sec_10tmp=sec_10 ;speak 'the time is' let p_index=0 ;initialize pointer let spkj_data=p_time(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=p_time(p_index) ;get next byte wend ;speak the hours let p_index=p_len(hour) ;get offset to phrase let spkj_data=data_0(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=data_0(p_index) ;get next byte wend ;pause let p_index=0 ;initialize pointer let spkj_data=p_pause(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=p_pause(p_index) ;get next byte wend ;o'clock or minutes if min_10=0 and min_1=0 then ;speak 'o-clock' let p_index=0 ;initialize pointer let spkj_data=p_o(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=p_o(p_index) ;get next byte wend else if min_10=1 then ;speak 10 to 19 let p_index=p_len(10+min_1) ;get offset to phrase let spkj_data=data_0(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=data_0(p_index) wend else ;speak ten minutes let p_index=p_len_00(min_10) ;get offset to phrase let spkj_data=data_00(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=data_00(p_index) wend ;speak minutes if min_1<>0 then ;skip if zero let p_index=p_len(min_1) ;get offset to phrase let spkj_data=data_0(p_index) while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=data_0(p_index) wend endif endif endif ;pause let p_index=0 ;initialize pointer let spkj_data=p_pause(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=p_pause(p_index) ;get next byte wend if am_pm=0 then ;speak 'am' let p_index=0 ;initialize pointer let spkj_data=p_am(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=p_am(p_index) ;get next byte wend else ;speak 'pm' let p_index=0 ;initialize pointer let spkj_data=p_pm(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=p_pm(p_index) ;get next byte wend endif if sec_10tmp=0 and sec_1tmp=0 then ;speak 'exactly' let p_index=0 ;initialize pointer let spkj_data=p_ex(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=p_ex(p_index) ;get next byte wend else ;speak 'and' let p_index=0 ;initialize pointer let spkj_data=p_and(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=p_and(p_index) ;get next byte wend if sec_10tmp=1 then ;speak 10 to 19 let p_index=p_len(10+sec_1tmp) ;get offset to phrase let spkj_data=data_0(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=data_0(p_index) wend else ;speak ten seconds if sec_10tmp>0 then ;skip if zero let p_index=p_len_00(sec_10tmp) let spkj_data=data_00(p_index) while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=data_00(p_index) wend endif ;speak seconds if sec_1tmp<>0 then ;skip if zero let p_index=p_len(sec_1tmp) ;get offset to phrase let spkj_data=data_0(p_index) while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=data_0(p_index) wend endif endif ;speak 'seconds' let p_index=0 ;initialize pointer let spkj_data=p_sec(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=p_sec(p_index) ;get next byte wend endif goto main ; ;******************************************* ; subroutines ;******************************************* ; ;display time dsp_time: let midi_data=$f0 ;sysex gosub send_midi let midi_data=$7d ;display id gosub send_midi let midi_data=$0a ;clear display gosub send_midi let midi_data=$18 ;overwrite gosub send_midi let midi_data="C" gosub send_midi let midi_data="l" gosub send_midi let midi_data="o" gosub send_midi let midi_data="c" gosub send_midi let midi_data="k" gosub send_midi let midi_data=" " gosub send_midi if am_pm=0 then ;display AM or PM let midi_data="A" gosub send_midi else let midi_data="P" gosub send_midi endif let midi_data="M" gosub send_midi if hour>9 then let midi_data=$31 ;display tens of hours gosub send_midi let midi_data=hour-10+$30 ;display hours gosub send_midi else let midi_data=" " ;display blank gosub send_midi let midi_data=hour+$30 ;display hours gosub send_midi endif let midi_data=":" ;display : gosub send_midi let midi_data=min_10+$30 ;display tens of minutes gosub send_midi let midi_data=min_1+$30 ;display minutes gosub send_midi let midi_data=":" ;display : gosub send_midi let midi_data=sec_10+$30 ;display tens of seconds gosub send_midi let midi_data=sec_1+$30 ;display seconds gosub send_midi let midi_data=$f7 ;end sysex gosub send_midi return ; ; #ifndef midi_int_en ;poll midi-in ;puts data into buffer and sets rcx_bfr_num to number of entries ;written by David J. Brown check_midi: let rcx_status=ssr if rcx_status&%01000000 then ;data has been received let midi_data=rdr ;read Receiver Data Register if midi_data<>$fe then ;ignore if active status ;put midi_data into receive buffer ;check to see if buffer full if rcx_bfr_num=rcx_bfr_len then ;buffer is full ;simply loose data else ;buffer has space let rcx_bfr(rcx_ptr_end)=midi_data let rcx_bfr_num=rcx_bfr_num+1 let rcx_ptr_end=rcx_ptr_end+1 if rcx_ptr_end=rcx_bfr_len then rcx_ptr_end=0 ;wrap pointer at max value endif endif endif else ;no data received ;check if error if rcx_status&%00111000 then ;error condition let rcx_status=rcx_status&%10000111 let ssr=rcx_status ;reset error bits endif endif return #endif ; ;gets midi_data from buffer ;rcx_data_flg=1 if successful, rcx_data_flg=0 if no data in buffer ;written by David J. Brown get_rcx_bfr: #ifdef midi_int_en disable sci3int_rdrf ;isr uses the same variables #endif ;check to see if buffer empty if rcx_bfr_num=0 then ;buffer is empty let rcx_data_flg=0 ;set empty flag else ;buffer has data let midi_data=rcx_bfr(rcx_ptr_strt) let rcx_bfr_num=rcx_bfr_num-1 let rcx_ptr_strt=rcx_ptr_strt+1 if rcx_ptr_strt=rcx_bfr_len then let rcx_ptr_strt=0 ;wrap pointer at max value endif let rcx_data_flg=1 ;set data returned flag endif #ifdef midi_int_en enable sci3int_rdrf #endif return ; ;output midi note-on command send_note_on: let midi_data=note_on+midi_chan gosub send_midi let midi_data=midi_note gosub send_midi let midi_data=midi_vel gosub send_midi return ; ;output midi note-off command send_note_off: let midi_data=note_off+midi_chan gosub send_midi let midi_data=midi_note gosub send_midi let midi_data=0 gosub send_midi return ; ;output midi all notes off command send_all_off: let midi_data=$b0+midi_chan ;send all notes off gosub send_midi let midi_data=$7b gosub send_midi let midi_data=0 gosub send_midi return ; ;output 3 byte program change command send_prog_change: let midi_data=pgm_chg+midi_chan gosub send_midi let midi_data=midi_pgm gosub send_midi return ; ;send midi_data ;waits until transmitter ready send_midi: let rcx_status=ssr if rcx_status&%10000000 then ;check transmitter ready ;ready to transmit let tdr=midi_data ;send data to tdr return endif goto send_midi ; ;send spkj_data via i2c send_speakjet: if spkj_data="X" then ;X terminates pass through let spkj_data=89 endif i2cout p6,p7,$0,[($48<<1),spkj_data] ;send out i2c return ; #ifndef input_int_en ;sample in-1 to in-4 ;injx is input value (0 - 1023) ;150 uS execution time get_inputs: adin pin_j1,in_j1 adin pin_j2,in_j2 adin pin_j3,in_j3 adin pin_j4,in_j4 return ; ;sample and average in-1 to in-4 ;injx is input value averaged over last four samples (0 - 1023) ;injx_bfr(0) & injx_bfr(1) are last four word samples ;600 uS execution time ;written by David J. Brown get_inputs_avg: adin pin_j1,in_j1_bfr.word1(in_j1_ptr) ;get in-1 into buffer let in_j1_tmp=in_j1_bfr(0)+in_j1_bfr(1) ;add two high words together and low words together let in_j1=(in_j1_tmp.word1+in_j1_tmp.word0)/4 adin pin_j2,in_j2_bfr.word1(in_j1_ptr) ;get in-2 into buffer let in_j2_tmp=in_j2_bfr(0)+in_j2_bfr(1) ;add two high words together and low words together let in_j2=(in_j2_tmp.word1+in_j2_tmp.word0)/4 adin pin_j3,in_j3_bfr.word1(in_j1_ptr) ;get in-3 into buffer let in_j3_tmp=in_j3_bfr(0)+in_j3_bfr(1) ;add two high words together and low words together let in_j3=(in_j3_tmp.word1+in_j3_tmp.word0)/4 adin pin_j4,in_j4_bfr.word1(in_j1_ptr) ;get in-4 into buffer let in_j4_tmp=in_j4_bfr(0)+in_j4_bfr(1) ;add two high words together and low words together let in_j4=(in_j4_tmp.word1+in_j4_tmp.word0)/4 let in_j1_ptr=(in_j1_ptr+1)&$03 ;increment pointer and wrap at 3 return #endif ; ;send debug_data to console ;written by David J. Brown debug_console: #ifdef timer_int_en disable timerwint_imiea ;interrupts must be off for correct timing #endif #ifdef midi_int_en disable sci3int_rdrf #endif serout s_out,i38400,[hex debug_data,13] #ifdef midi_int_en enable sci3int_rdrf #endif #ifdef timer_int_en enable timerwint_imiea #endif return ; ;send debug_data to speakjet ;written by David J. Brown debug_speakjet let tempb=debug_data ;save debug data let debug_data=debug_data>>4 ;get high nibble let p_index=p_len(debug_data) ;get offset to phrase let spkj_data=data_0(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=data_0(p_index) ;get next byte wend let debug_data=tempb let debug_data=debug_data&$0f ;get bottom nibble let p_index=p_len(debug_data) ;get offset to phrase let spkj_data=data_0(p_index) ;get first byte while spkj_data<>255 ;output until 255 gosub send_speakjet let p_index=p_index+1 ;increment pointer let spkj_data=data_0(p_index) ;get next byte wend let debug_data=tempb return ; ;output outjx values to dacs ;based on code written by Grant Richter ;750 uS execution time load_outputs: ;add addresses to values ;shift out 16 bits mode 4 shiftout ser_data,clock,4,[(out_j1+49152)\16] pulsout load_dacs,1 ;pulse loaddacs for each channel shiftout ser_data,clock,4,[(out_j2+32768)\16] pulsout load_dacs,1 ;pulse loaddacs for each channel shiftout ser_data,clock,4,[(out_j3+16384)\16] pulsout load_dacs,1 ;pulse loaddacs for each channel shiftout ser_data,clock,4,[out_j4\16] pulsout load_dacs,1 ;pulse loaddacs for each channel return ; ;******************************************* ;interrupt service routines ;******************************************* ; #ifdef timer_int_en ;interrupt service routine for timer ;increments time_count value ;turn off stop led at turn_off value ;toggle run led at 1S intervals ;written by David J. Brown tm_isr: let time_count=time_count+1 ;increment real time count if time_count=100 then gosub dsp_time ;display time let sec_1=sec_1+1 ;increment seconds if sec_1=10 then ;check carry let sec_1=0 let sec_10=sec_10+1 ;increment 10 seconds if sec_10=6 then ;check carry let sec_10=0 let min_1=min_1+1 ;increment minutes if min_1=10 then ;check carry let min_1=0 let min_10=min_10+1 ;increment 10 minutes if min_10=6 then ;check carry let min_10=0 let hour=hour+1 ;increment hour if hour=12 then ;check am / pm if am_pm=0 then let am_pm=1 ;toggle am / pm else let am_pm=0 endif endif if hour=13 then ;check carry let hour=1 endif endif endif endif endif toggle run_led let time_count=0 endif #endif #ifndef input_int_en resume ;resume if input polled mode #endif #ifdef input_int_en ;continue if input interrupt mode ;sample in-1 - in-4 at specific intervals ;injx is input averaged over last 4 samples (0 - 1023) ;injx_bfr(0) & injx_bfr(1) are last 4 word samples let isr_cnt=isr_cnt+1 ;change the following table to modify the scan rate for each input ;175 uS execution time so maximum of one sample and average per interrupt ;currently set for: in-1 @ 2 mS, in-2 @ 4 mS, in-3 @ 8 mS, in-4 @ 8 mS branch isr_cnt, [avg1,avg2,avg1,avg3,avg1,avg2,avg1,avg4,avg1,avg2,avg1,avg3,avg1,avg2,avg1,avg4] ;sample in-1 avg1: adin pin_j1,in_j1_bfr.word1(in_j1_ptr) ;get in-1 into buffer let in_j1_tmp=in_j1_bfr(0)+in_j1_bfr(1) ;add two high words together and low words together let in_j1=(in_j1_tmp.word1+in_j1_tmp.word0)/4 let in_j1_ptr=(in_j1_ptr+1)&$03 ;increment pointer and wrap at 3 resume ;sample in-2 avg2: adin pin_j2,in_j2_bfr.word1(in_j2_ptr) ;get in-2 into buffer let in_j2_tmp=in_j2_bfr(0)+in_j2_bfr(1) ;add two high words together and low words together let in_j2=(in_j2_tmp.word1+in_j2_tmp.word0)/4 let in_j2_ptr=(in_j2_ptr+1)&$03 ;increment pointer and wrap at 3 resume ;sample in-3 avg3: adin pin_j3,in_j3_bfr.word1(in_j3_ptr) ;get in-3 into buffer let in_j3_tmp=in_j3_bfr(0)+in_j3_bfr(1) ;add two high words together and low words together let in_j3=(in_j3_tmp.word1+in_j3_tmp.word0)/4 let in_j3_ptr=(in_j3_ptr+1)&$03 ;increment pointer and wrap at 3 resume ;sample in-4 avg4: adin pin_j4,in_j4_bfr.word1(in_j4_ptr) ;get in-4 into buffer let in_j4_tmp=in_j4_bfr(0)+in_j4_bfr(1) ;add two high words together and low words together let in_j4=(in_j4_tmp.word1+in_j4_tmp.word0)/4 let in_j4_ptr=(in_j4_ptr+1)&$03 ;increment pointer and wrap at 3 resume #endif ; #ifdef midi_int_en ;interrupt service routine for midi-in data ;puts data into buffer and sets rcx_bfr_num to number of entries ;priority given to midi-in over timer interrupts ;written by David J. Brown midi_in_isr: ;read Receiver Data Register must be first instruction to clear interrupt let midi_data_isr=rdr ;read Receiver Data Register disable timerwint_imiea ;disable timer interrupts if midi_data_isr<>$fe then ;ignore if active status ;check to see if buffer full if rcx_bfr_num=rcx_bfr_len then ;buffer is full ;simply loose data else ;put data into buffer let rcx_bfr(rcx_ptr_end)=midi_data_isr let rcx_bfr_num=rcx_bfr_num+1 ;set rcx_bfr_num to number of entries let rcx_ptr_end=rcx_ptr_end+1 ;increment pointer for next entry if rcx_ptr_end=rcx_bfr_len then rcx_ptr_end=0 ;wrap pointer at max value endif endif endif enable timerwint_imiea resume #endif ; ;******************************************* ;end of program ;*******************************************