this project started about 2 years ago. I had a large piece of perf board, a super simple, relaxation oscillator, non-interupting, 1-channel cap sensing routine running on a 16F628A, and a 16 to 1 analog multiplexer, and some time to kill, so I arranged 16 finger sized copper tape squares on the underside of the perf board and wired them to the multiplexer, and then wired the multiplexer to the cap sensor circuit. lo and behold, it worked, and I made a routine to scan the keys and use the SOUND command to output a tone corresponding to the key. I originally wanted to use the HPWM channel to generate the correct tones, (maybe more than one at at time!) and keep them sustained for the duration of the key press. What I ended up with was a little less impressive.. out of tune tones generated by the SOUND command that just went beep beep beep if you held your finger on one key at a time.


The board has sat on my bench since then, collecting dust. But in that time, I've worked more and more with cap sensors, and I've always thought about putting cap sensors under the floor, and doing something cool with that. Fast forward to now, we are due to have our third kid around Christmas time, and my 7 year old daughter is moving her room from upstairs to the downstairs so the baby can have her old room.It's a little cold down there, there are spiders, and the window is tiny. So, I wanted to make her room special. I ripped up the old carpeting, re-painted, and now I'm installing laminate flooring. I thought 'Hey, here is my chance to put in cap sensors under the floor.. what should I do?'


I ended up laying out 16 piano keys -10 white keys, B through D, and their black keys, so 16 in total. They are foot sized sensors on the laminate pad made with copper tape and wired to that same controller/multiplexer board which now sits in a cutout in the drywall, which will be eventually hidden by the trim. I spent most of last weekend on my hands and knees, but now it is working with my super simple code that I wrote long ago.


Now that I've upgraded the hardware, I need to rethink the code. and how I can get different sounds, chords, and whatnot, without breaking the bank. I have an old keyboard that I could hack up and put fets or transistors on the key pads and control it that way... but that'll be a kludged together hack job.


Right now, I'm thinking that I'll run 3 wires to the buried 16F628 controller, +5V, GND and a serial data line that will spit out 2 bytes, 16 bits corresponding to the pressed/unpressed states of the 16 keys. Then, I'll have another pic reading that data and (somehow) make the music happen.


I'd love to have something like rmteo has posted:
http://www.pic24.ru/doku.php/en/osa/.../pk2_osa_piano




Any suggestions about how to go about making the music happen?


I also got 2 meters of RGB LEDs and a cheap controller from ebay that has a remote. Eventually it would be nice to get the piano and the RGBs working together...but that is for another day.


but anyway, here is the code that is running right now on the 16F628A, controlling the multiplexer and counting the pulses from the relaxation oscillator.


if I count for 8mS, I get a count of about 3100, so the oscillator is running at about 380KHz. put your foot on the sensor, with the laminate in between, and it drops to about 2950~3000, since then, I changed to counting for 4mS.


Any suggestions?


I realize that what I call 'average' is not really an average, it's just a snapshot of the values it saw when it was first powered on..
and, I see that my line to combine the timerH and timerL bytes is wrong, but I can't seem to get value=timerH.timerL to work.


Code:
'PIc and analog multiplexer capsense




'    PIC16F628A Configuration
'    ================




@ __CONFIG  _INTRC_OSC_NOCLKOUT & _MCLRE_OFF  &  _LVP_OFF & _WDT_ON & _PWRTE_ON  & _BODEN_ON


'    Hardware configuration
'    ======================


CLEARWDT


DEFINE OSC 4				'4 MHz internal oscillator




DEFINE DEBUG_REG PORTB		'RS-232 output on PORTB.4
DEFINE DEBUG_BIT 7
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0			'not inverted. using RS-232 chip, or pickit2
DEFINE DEBUG_PACING 1000






CMCON = %00000110           ' 2 common ref comparators with outputs  ..datasheet pdf page 64
TRISB = %01000000           ' B.6= timer input = Comparator output freq
TRISA = %00000111           ' Comparator inputs and Vref set to input
VRCON = %11100011	    	' turn on Vref, output connected to RA2, Low range, Vref = .6 when Vcc = 5V
			   			 	' ..datasheet pdf page 69




'    RAM Assignments and Variables
'    =============================




DEBUGPIN  var    PORTB.4
S0	      var    PORTB.0
S1	      var    PORTB.1
S2	  var    PORTB.5
S3        var    PORTB.7
EN    var    PORTB.2
SPEAKER var  PORTB.3








S0	  =0
S1	  =0
S2	  =0
S3    =0
EN    =1






SenseTime   CON  4     ' how many milliseconds to run the cap sense counter for one sample




Sleepy      var WORD    ' counter used with 'asleep'
asleep   	CON  1000	' number of times around the main loop with no activity to put the chip to sleep.
Sleeptime   CON  6       'Nap command period (5 = approx 480ms, 4 = approx 280ms)




TONE var BYTE[16]




TONE[15] = 48
TONE[14] = 53
TONE[13] = 56
TONE[12] = 61
TONE[11] = 64
TONE[10] = 68
TONE[9] =  72
TONE[8] =  75 
TONE[0] = 78
TONE[1] = 81
TONE[2] = 83
TONE[3] = 86
TONE[4] = 89
TONE[5] = 90
TONE[6] = 92
TONE[7] = 94 


Trip  CON 30
playtime  con  12


AVE		    VAR  WORD[16]	' current Capsense average
Value	VAR  WORD[16]	' instantaneous Capsense count array






SensorNumb  var BYTE




pause 3000




DEBUG REP $00\8,13,10,"Hello"


Sleepy = 0




GOSUB SCAN 


FOR SensorNumb = 0 to 15
	AVE[SensorNumb] = Value[SensorNumb]


NEXT SensorNumb






main:






GOSUB SCAN 








'DEBUG DEC Value[15], ",  ", DEC Value[14], ",  ", DEC Value[13], ",  ",DEC Value[12], ",  ",DEC Value[11], ",  ",DEC Value[10], ",  ", DEC Value[9],13,10




FOR SensorNumb = 0 to 15


	IF Value[SensorNumb] < (AVE[SensorNumb] - Trip) THEN
		SOUND SPEAKER,[TONE[SensorNumb],playtime]
		Sleepy = 0
		goto main
	ENDIF
NEXT SensorNumb








'Sleepy = Sleepy +1


	
IF Sleepy = asleep THEN 
	DEBUG REP $00\8,13,10,"zz.."
	CMCON=7                     		' disable internal comparator
	VRCON = %00000000			' disable voltage reference


	NAP Sleeptime				' places the microcontroller into low power mode 


	CMCON = %00000110  			' enable internal comparator
	VRCON = %11100011			' enable voltage reference
	Sleepy = (asleep -1)		' Preload the the sleepy counter so it'll go right back to sleep after one reading


ENDIF






goto main


' -=-=-=-=-=-=  Scan sensors and put results into Value[X] -=-=-=-=-=-=-=-=-=-= 
SCAN:


FOR SensorNumb = 0 to 15




		S0	  =SensorNumb.0
		S1	  =SensorNumb.1
		S2	  =SensorNumb.2
		S3    =SensorNumb.3
		EN    =0




		TMR1H = 0							'Clear high and low timer1 registers
		TMR1L = 0
		T1CON = %00000111					'Start counter
		pause SenseTime			  		    'wait 
		T1CON = %00000110					'Stop counter


		EN    =1


		Value[SensorNumb] = ((255 * TMR1H) + TMR1L) 	'Combine high and low byte into one word sized variable




NEXT SensorNumb


RETURN


End