'**************************************************************** '* Name : ADC_blue_box_05.BAS * '* Author : df99 * '* Notice : Copyright (c) 2008 * '* : All Rights Reserved * '* Date : 3/12/2008 * '* Version : 0.9 * '* Notes : PWM blue box with single pin * '* : keyboard decode. Memory storage with twelve slots * '* : of up to 32 tones each. * '**************************************************************** ' 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 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 played when the ' key is first pressed to store will not be recorded. Reset the digit buffer ' by cycling power, saving a previous buffer to EEPROM, or changing modes. ' The box operates in two modes. In the default mode, it plays MF and ' the 2600 tone 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. ' 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_ON,PWRT_ON,MCLR_ON,BOD_OFF,CPD_OFF,PROTECT_OFF,IESO_OFF,FCMEN_OFF DEFINE OSC 20 ' 20 MHz clock 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 WORD 'Keydown loop counter MODE VAR WORD number VAR byte[34] 'Array for storage of up to 32 keypresses 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 NORMAL CON 0 'Alias for NORMAL mode PLAYBACK CON 1 'Alias for memory PLAYBACK mode MASKHI con $0F 'Low nibble mask for eewrite MASKLO CON $F0 'High nibble mask for eewrite eeprom 0*33,255 'Set eof indicator at beginning of first two eeprom banks when programmed eeprom 1*33,255 'Set eof indicator at beginning of next two eeprom banks when programmed eeprom 2*33,255 'Set eof indicator at beginning of next two eeprom banks when programmed eeprom 3*33,255 'Set eof indicator at beginning of next two eeprom banks when programmed eeprom 4*33,255 'Set eof indicator at beginning of next two eeprom banks when programmed eeprom 5*33,255 'Set eof indicator at beginning of next two eeprom banks when programmed pointer = 0 'Reset keypress array pointer number(0) = 255 'Set eof marker to beginning of array mode = normal 'Default mode to NORMAL '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 = 32)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. if pointer < 32 then number(pointer - 1) = 255 pointer = 0 'Set pointer to 0 to start buffer read 'Select the 33-byte correct bank to write if (digit <= 6) then wpointer = 33 * (digit - 1) if ((digit >= 7)and(digit <= 12)) then wpointer = 33 * (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 = 0 'Clear out keypress buffer pointer number(0) = 255 'Reset buffer EOF to empty buffer 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 = 33 * (digit - 1) if ((digit >= 7)and(digit <= 12)) then rpointer = 33 * (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 (digit = $0F) then return 'Stop playback when eof reached in ee IF (digit = 1)then FREQOUT 0,75,700,900 'MF1 IF (digit = 2)then FREQOUT 0,75,700,1100 'MF2 IF (digit = 3)then FREQOUT 0,75,900,1100 'MF3 IF (digit = 4)then FREQOUT 0,75,700,1300 'MF4 IF (digit = 5)then FREQOUT 0,75,900,1300 'MF5 IF (digit = 6)then FREQOUT 0,75,1100,1300 'MF6 IF (digit = 7)then FREQOUT 0,75,700,1500 'MF7 IF (digit = 8)then FREQOUT 0,75,900,1500 'MF8 IF (digit = 9)then FREQOUT 0,75,1100,1500 'MF9 IF (digit = 10)then FREQOUT 0,120,1100,1700 'KP IF (digit = 11)then FREQOUT 0,75,1300,1500 'MF0 IF (digit = 12)then FREQOUT 0,75,1500,1700 'ST IF (digit = 13)then FREQOUT 0,1000,2600 'Seize 'Pause for return wink after 2600 playback from ee 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 75 '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 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 return else if (mode = normal) then mode = playback 'Toggle mode to PLAYBACK 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 = 0 'Reset so move to playback mode clears buffer number(0) = 255 'Reset so move to playback mode clears buffer return endif endif 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