'**************************************************************** '* Name : ADC_blue_box_05.BAS * '* Author : df99 * '* Notice : Copyright (c) 2008 * '* : All Rights Reserved * '* Date : 3/20/2008 * '* Version : 12 * '* Notes : PWM blue box with single pin * '* : keyboard decode. Memory storage with twelve slots * '* : of up to 32 tones each. Configurable defaults. * '**************************************************************** ' Resistor network detection values assume a network of 14-1KOhm ' resistors in series, from Vdd to Vss, with a tap between each ' resistor pair. Taps at Vdd and Vss are not used, to avoid ADC ' issues when trying to read at the voltage rails. ' The slight effect of a 250KOhm pull-down resistor on the ADC input ' pin is also factored into the calculations, although the effect is ' almost negligible. ' On power up, a mode change, or a memory store operation, the device ' saves the tone mode plus the next 32 keypresses in a buffer. This buffer may ' be written to one of the twelve non-volatile memory locations (1-12) by pressing and ' holding the corresponding digit for two seconds. The tone mode (MF or DTMF) is ' saved as well as the buffer. The tone played when the key is first pressed ' to store will not be recorded. Reset the digit buffer by cycling power, ' saving a buffer to EEPROM, or changing normal/playback modes. ' The box operates in two operating modes. In the default normal mode, it plays tones ' manually. Pressing and holding the 2600 button more than ' one second toggles to the playback mode. In this mode, sequences stored ' in the 12 memories may be played by pressing the corresponding key. Another one ' second press of the 2600 key, or power cycling, returns to normal mode. ' The powerup tone mode may be temporarily toggled between MF and DTMF by holding the 2600 ' button down while powering up. The current tone mode is stored to the non-volatile ' memory slots as well as the buffered digits, so the memories may contain a ' mix of MF and DTMF sequences. Both MF and DTMF may not be saved in the same ' memory slot. ' The power-up tone mode and tone duration/spacing are stored in eeprom and ' Read at powerup. The power-up defaults may be changed. Holding down the "*" ' key at powerup will read the current tone mode (MF or DTMF) from eeprom, ' toggle it and write it back to eeprom. Similarly, holding down the "#" key ' while powering up will toggle the default tone duration spacing between ' 75 ms. and 120 ms. The KP tone duration is always 120 ms., regardless of ' this setting. The 2600 tone is always 1.5 seconds duration. ' Memory locations may be cleared by pressing and holding the corresponding ' key in normal mode immediately after the buffer has been cleared at power-up, ' after a mode change back to normal mode, or after storing a digit sequence. ' Set PIC configuration fuses. PICBASIC PRO refreshes WDT automatically. ' HS_OSC works well for the Murata 20 MHz ceramic resonator. No parallel ' resistor required. @ DEVICE PIC12F683,HS_OSC,WDT_OFF,PWRT_ON,MCLR_ON,BOD_OFF,CPD_OFF,PROTECT_OFF,IESO_OFF,FCMEN_OFF DEFINE no_clrwdt 1 'Disable automatic WDT refresh for more code space DEFINE OSC 20 ' Use 20 MHz clock for timing calculations DEFINE ADC_BITS 10 'Use 10 bit resolution with ADCIN DEFINE ADC_CLOCK 3 'Use internal RC clock for ADC only DEFINE ADC_SAMPLEUS 50 'Wait 50 uS before read after ADCIN turns on ADC ADCON0 = %10001001 'Right justify ADC, Vdd ref, Chan 2, enable ADC KEY VAR WORD 'Define variable for ADC input value KEYDOWN VAR byte 'Keydown loop counter MODE VAR byte 'Normal/playback mode state mode2 var byte 'MF/DTMF mode state number VAR byte[35] 'Array for storage of up to 32 keypresses, tone mode, eof, storage key pointer var byte 'Pointer for writing or reading the above array rpointer var byte 'EEPROM read pointer wpointer var byte 'EEPROM write pointer digit var byte 'The code of the most recently pressed key digit2 var byte 'Temporary variable for eewrite processing mask VAR BYTE 'Mask cariable for eewrite processing temp var byte 'Temporary storage digit3 var byte 'Temporary storage mode2_tmp var byte 'Temporary storage length var byte 'Tone length, inter-digit delay NORMAL CON 0 'Alias for NORMAL mode PLAYBACK CON 1 'Alias for memory PLAYBACK mode MF con 0 DTMF con 1 MASKHI con $0F 'Low nibble mask for eewrite MASKLO CON $F0 'High nibble mask for eewrite MF_MODE con 0 'Key code for MF mode DTMF_MODE con 14 'Key code for DTMF mode mode2_stor con 254 'ee location for mode length_stor con 255 'ee location for tone length, inter-digit delay eeprom 0*34,[255] 'Set eof indicator at beginning of first two eeprom banks when programmed eeprom 1*34,[255] 'Set eof indicator at beginning of next two eeprom banks when programmed eeprom 2*34,[255] 'Set eof indicator at beginning of next two eeprom banks when programmed eeprom 3*34,[255] 'Set eof indicator at beginning of next two eeprom banks when programmed eeprom 4*34,[255] 'Set eof indicator at beginning of next two eeprom banks when programmed eeprom 5*34,[255] 'Set eof indicator at beginning of next two eeprom banks when programmed eeprom mode2_stor,[MF] 'Pre-store initial powerup tone mode in ee as MF eeprom length_stor,[75] 'Pre-store initial tone length, inter-digit delay in ee mode = normal 'Default mode to NORMAL read mode2_stor,mode2 'Retrieve default tone mode read length_stor,length 'Retrieve default tone length 'Temporarily toggle tone mode if 2600 key held at powerup (until next powerup) ADCIN 2, KEY 'Get keypad value IF ((KEY > 37) AND (KEY <= 110)) THEN '2600 key detect if (mode2 = MF) then mode2 = DTMF 'Toggle mode to DTMF, if MF in ee else if (mode2 = DTMF) then mode2 = MF 'Toggle tonemode to MF endif Endif Freqout 0,1000,1700 'Play beep endif 'Toggle power-up tone mode and store in ee if "*" held at power-up IF ((KEY > 256) AND (KEY <= 329)) THEN '"*" key detect read mode2_stor,temp 'Get current ee default tone mode if (temp = MF) then temp = DTMF 'Toggle mode to DTMF, if MF in ee write mode2_stor,temp else if (temp = DTMF) then temp = MF 'Toggle tonemode to MF write mode2_stor,temp 'Save the normal mode tone mode endif Endif read mode2_stor,mode2 'Retrieve and set new default tone mode Freqout 0,1000,1700 'Play beep endif 'Toggle power-up tone length and store in ee if "#" held at power-up IF ((KEY > 110) AND (KEY <= 182)) THEN read length_stor,temp 'Get current ee default length if (temp = 75) then temp = 120 'Change length in ee to 120 if 75 write length_stor,temp else if (temp = 120) then temp = 75 'Change length in ee to 75 if 120 write length_stor,temp 'Save the normal mode tone mode endif Endif read length_stor,length 'Retrieve and set new default tone length Freqout 0,1000,1700 'Play beep endif hold2: ADCIN 2, KEY 'Get keypad value again Pause 10 'Allow ADC to settle between reads IF (KEY > 37) THEN hold2 'Wait for key release before continuing pointer = 1 'Clear out keypress buffer pointer 'Save tone mode in first location of buffer if (mode2 = mf) then number(0) = mf_mode if (mode2 = DTmf) then number(0) = DTmf_mode number(1) = 255 'Set eof marker 'Main Loop loop: ADCIN 2, KEY 'Get keypad value again keydown = 0 'Clear keydown value IF (KEY > 37) THEN GOSUB keytest 'If any keypress detected, decode Pause 10 'Allow ADC to settle between reads GOTO loop 'Do it again - idle loop ' Any key value <= 37 is essentially 0 VDC because of the pull-down ' resistor, with some margin for noise. This means that no key has ' been pressed. keytest: ' 4.64 volts calculated, with Vdd = 5VDC. ADC value=949 ' Prototype measured value with 5% resistors: 4.65 VDC IF ((KEY > 914) AND (KEY <= 1023)) THEN digit = 1 gosub play gosub update endif ' 4.29 volts calculated, with Vdd = 5VDC. ADC value=878 ' Mean with previous value = 914 ' Prototype measured value with 5% resistors: 4.29 VDC IF ((KEY > 841) AND (KEY <= 914)) THEN digit = 2 gosub play gosub update endif ' 3.93 volts calculated, with Vdd = 5VDC. ADC value=804 ' Mean with previous value = 841 ' Prototype measured value with 5% resistors: 3.94 VDC IF ((KEY > 767) AND (KEY <= 841)) THEN digit = 3 gosub play gosub update endif ' 3.57 volts calculated, with Vdd = 5VDC. ADC value=730 ' Mean with previous value = 767 ' Prototype measured value with 5% resistors: 3.58 VDC IF ((KEY > 694) AND (KEY <= 767)) THEN digit = 4 gosub play gosub update endif ' 3.21 volts calculated, with Vdd = 5VDC. ADC value=657 ' Mean with previous value = 694 ' Prototype measured value with 5% resistors: 3.22 VDC IF ((KEY > 621) AND (KEY <= 694)) THEN digit = 5 gosub play gosub update endif ' 2.86 volts calculated, with Vdd = 5VDC. ADC value=585 ' Mean with previous value = 621 ' Prototype measured value with 5% resistors: 2.86 VDC IF ((KEY > 549) AND (KEY <= 621)) THEN digit = 6 gosub play gosub update endif ' 2.50 volts calculated, with Vdd = 5VDC. ADC value=512 ' Mean with previous value = 549 ' Prototype measured value with 5% resistors: 2.51 VDC IF ((KEY > 475) AND (KEY <= 549)) THEN digit = 7 gosub play gosub update endif ' 2.14 volts calculated, with Vdd = 5VDC. ADC value=438 ' Mean with previous value = 475 ' Prototype measured value with 5% resistors: 2.15 VDC IF ((KEY > 401) AND (KEY <= 475)) THEN digit = 8 gosub play gosub update endif ' 1.78 volts calculated, with Vdd = 5VDC. ADC value=364 ' Mean with previous value = 401 ' Prototype measured value with 5% resistors: 1.79 VDC IF ((KEY > 329) AND (KEY <= 401)) THEN digit = 9 gosub play gosub update endif ' 1.43 volts calculated, with Vdd = 5VDC. ADC value=293 ' Mean with previous value = 329 ' Prototype measured value with 5% resistors: 1.43 VDC IF ((KEY > 256) AND (KEY <= 329)) THEN digit = 10 gosub play gosub update endif ' 1.07 volts calculated, with Vdd = 5VDC. ADC value=219 ' Mean with previous value = 256 ' Prototype measured value with 5% resistors: 1.07 VDC IF ((KEY > 182) AND (KEY <= 256)) THEN digit = 11 gosub play gosub update endif ' 0.71 volts calculated, with Vdd = 5VDC. ADC value=145 ' Mean with previous value = 182 ' Prototype measured value with 5% resistors: 0.72 VDC IF ((KEY > 110) AND (KEY <= 182)) THEN digit = 12 gosub play gosub update endif ' 0.36 volts calculated, with Vdd = 5VDC. ADC value=74 ' Mean with previous value = 110 ' Mean with ground (0VDC) = 37 ' Prototype measured value with 5% resistors: 0.36 VDC IF ((KEY > 37) AND (KEY <= 110)) THEN digit = 13 '2600 gosub play gosub update endif ' The following code waits until the key is released (if pressed) to insure ' one tone burst per keypress. Delay seems needed for reliable ADC settling, ' since loop is so small. A counter tracks the number of 10 ms iterations ' through the loop to time the keydown periods to trigger mode change or ' eewrite. again: 'Get keypad value again ADCIN 2, KEY 'Increment keydown count KEYDOWN = KEYDOWN + 1 'Toggle modes between NORMAL and PLAYBACK after 1 second 'of 2600 key keydown if ((KEYDOWN > 100)and(KEY > 37)AND(KEY <= 110))then gosub modechg 'Do EEPROM write if other keys held down for > 2 seconds IF mode = normal then if ((KEYDOWN > 200)and(KEY > 110))then gosub eewrite endif 'Allow ADC to settle between reads Pause 10 'Loop through again if key is still pressed IF (KEY > 37) THEN again RETURN 'Save the first 32 keypresses after power up or a mode change 'back to normal mode from PLAYBACK mode. These keypresses may be 'written to locations 1-12 by pressing the corresponding button 'for > 2 seconds. Buffer is cleared by power cycle, ee write, 'or mode change. update: if ((pointer = 34)or(mode = playback)) then return number(pointer) = digit pointer = pointer + 1 number(pointer) = 255 return 'Routine to write the buffer array described above to EEPROM 'Banks 1-12. eewrite: FREQOUT 0,75,1700 'Short high beep at start of ee write 'Adjust temporary array for extra digit stored when requesting an 'ee write. Note buffer always stores 1 extra digit so this works if 'user stores the buffer after pressing MORE than 32 keys. number(pointer - 1) = 255 pointer = 0 'Set pointer to 0 to start buffer read 'Select the 34-byte correct bank to write if (digit <= 6) then wpointer = 34 * (digit - 1) if ((digit >= 7)and(digit <= 12)) then wpointer = 34 * (digit - 7) agn: if number(pointer) = 255 then 'Detect keypress buffer eof digit2 = $0F gosub fixwrite 'Adjust value to correct nibble write wpointer,digit2 'Write eof to flash if at end of buffer pointer = 1 'Clear out keypress buffer pointer 'Save tone mode in first location of buffer if (mode2 = mf) then number(0) = mf_mode if (mode2 = DTmf) then number(0) = DTmf_mode number(1) = 255 'Set eof marker FREQOUT 0,1000,1500 'Long beep after ee write complete hold: ADCIN 2, KEY 'Get keypad value again Pause 10 'Allow ADC to settle between reads IF (KEY > 37) THEN hold 'Wait for key release before exiting return endif 'Start here to write next location to ee digit2 = number(pointer) 'Get the next value from key buffer gosub fixwrite 'Adjust the value to correct nibble write wpointer,digit2 'Write the next adjusted value to ee pointer = pointer + 1 'Increment the buffer pointer wpointer = wpointer + 1 'Increment the ee pointer goto agn 'Do until the end of buffer 'Dual purpose routine to play the decoded keys in NORMAL mode or 'to read and play back the stored ee digit strings, depending upon 'entry point and mode. play: 'Skip ee playback setup if in NORMAL, real-time mode if (mode = normal) then goto play2 'Set the correct EE bank to play back if ((digit >= 1)and(digit <= 6)) then rpointer = 34 * (digit - 1) if ((digit >= 7)and(digit <= 12)) then rpointer = 34 * (digit - 7) if (digit > 12) then return 'Do not attempt playback of 2600 key digit3 = digit 'Save original entry digit value for fixread agn2: read rpointer,digit2 'Get the digit from the next ee location GOSUB FIXREAD 'Get the correct nibble to play back play2: if (mode2 = DTMF) then play3 if (digit = $0F) then return 'Stop playback when eof reached in ee IF (digit = 0)then mode2 = mf 'Change mode on playback mode change IF (digit = 1)then FREQOUT 0,length,700,900 'MF1 IF (digit = 2)then FREQOUT 0,length,700,1100 'MF2 IF (digit = 3)then FREQOUT 0,length,900,1100 'MF3 IF (digit = 4)then FREQOUT 0,length,700,1300 'MF4 IF (digit = 5)then FREQOUT 0,length,900,1300 'MF5 IF (digit = 6)then FREQOUT 0,length,1100,1300 'MF6 IF (digit = 7)then FREQOUT 0,length,700,1500 'MF7 IF (digit = 8)then FREQOUT 0,length,900,1500 'MF8 IF (digit = 9)then FREQOUT 0,length,1100,1500 'MF9 IF (digit = 10)then FREQOUT 0,120,1100,1700 'KP IF (digit = 11)then FREQOUT 0,length,1300,1500 'MF0 IF (digit = 12)then FREQOUT 0,length,1500,1700 'ST IF (digit = 13)then FREQOUT 0,1000,2600 'Seize IF (digit = 14)then mode2 = dtmf 'Change mode on playback mode change if (mode2 = MF) then hop play3: if (digit = $0F) then return 'Stop playback when eof reached in ee IF (digit = 0)then mode2 = mf 'Change mode on stored mode change IF (digit = 1)then FREQOUT 0,length,697,1209 'DTMF1 IF (digit = 2)then FREQOUT 0,length,697,1336 'DTMF2 IF (digit = 3)then FREQOUT 0,length,697,1477 'DTMF3 IF (digit = 4)then FREQOUT 0,length,770,1209 'DTMF4 IF (digit = 5)then FREQOUT 0,length,770,1336 'DTMF5 IF (digit = 6)then FREQOUT 0,length,770,1477 'DTMF6 IF (digit = 7)then FREQOUT 0,length,852,1209 'DTMF7 IF (digit = 8)then FREQOUT 0,length,852,1336 'DTMF8 IF (digit = 9)then FREQOUT 0,length,852,1477 'DTMF9 IF (digit = 10)then FREQOUT 0,length,941,1209 'DTMF* IF (digit = 11)then FREQOUT 0,length,941,1336 'DTMF0 IF (digit = 12)then FREQOUT 0,length,941,1477 'DTMF# IF (digit = 13)then FREQOUT 0,1000,2600 'Seize IF (digit = 14)then mode2 = dtmf 'Change mode on stored mode change 'Pause for return wink after 2600 playback from ee hop: if ((digit = 13)and(mode = playback)) then pause 1500 if (mode = normal) then return 'Stop here if decoding manual keypresses rpointer = rpointer + 1 'Go to the next ee location pause length 'Insert pause between digits played goto agn2 'Get the next digit in ee return 'Routine to toggle the mode if "2600" button held for > 1 second modechg: if (mode = playback) then mode = normal 'Toggle mode to NORMAL mode2 = mode2_tmp 'Restore saved tone mode keydown = 0 'Reset keydown counter 'Play high to low beep to confirm mode change to NORMAL freqout 0,75,1700 'Play high beep freqout 0,75,1300 'Play low beep else if (mode = normal) then mode = playback 'Toggle mode to PLAYBACK mode2_tmp = mode2 'Save the normal mode tone mode keydown = 0 'Reset keydown counter 'Play low to high beep to confirm mode change to PLAYBACK Freqout 0,75,1300 'Play low beep freqout 0,75,1700 'Play high beep pointer = 1 'Reset so move to playback mode clears buffer 'Save tone mode in first location of buffer if (mode2 = mf) then number(0) = mf_mode if (mode2 = DTmf) then number(0) = DTmf_mode number(1) = 255 'Set eof marker endif endif hold3: ADCIN 2, KEY 'Get keypad value again Pause 10 'Allow ADC to settle between reads IF (KEY > 37) THEN hold3 'Wait for key release before exiting return 'Subroutine to adjust key data to high or low nibble storage depending 'upon storage key presed. High nibble storage for locations 7-12, low 'nibble storage for locations 1-6. fixwrite: 'Move retrieved buffer value to high nibble while preserving ee low nibble if (digit >= 7) then mask = maskhi digit2 = digit2 << 4 'Shift bits left four places endif 'Move retrieved buffer value to low nibble while preserving ee high nibble if (digit <= 6) then mask = MASKLO read wpointer,temp temp = ((temp)&(mask)) 'Mask old high nibble digit2 = ((digit2)|(temp)) 'Add new high nibble while preserving low nibble return 'Subroutine to retrieve correct nibble from ee, depending upon 'play key pressed. High nibble storage for locations 7-12, low 'nibble storage for locations 1-6. fixread: 'If requesting memories 7-12, get high nibble and convert to digit value if ((digit3 >= 7)and(digit3 <= 12)) then digit = (digit2 >> 4) 'Shift bits right four places else 'If requesting memories 1-6, get low nibble and convert to digit value if ((digit3 >= 1)and(digit3 <= 6)) then mask = MASKHI digit = (digit2 & mask) 'Mask high nibble endif endif return