Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

SparkFun Touch Shield


  • Please log in to reply
2 replies to this topic

#1 Eric Falsken

Eric Falsken

    Member

  • Members
  • PipPip
  • 25 posts
  • LocationSan Francisco, CA, USA

Posted 05 November 2011 - 04:59 PM

As seen on the SparkFun website. (schematic) It comes fully assembled but for the shield headers. The TouchShield has a sequence of capacitive touch pads. (1-9) The pads are controlled by a Freescale MPR121 (datasheet).

The capacitive pads are surprisingly sensitive. Unfortunately, if you have fat fingers you may contact the area between the pads where the circuits are routed, causing false positives on other pads. e.g. the circuit for pad 2 and 5 pass between pads 7 and 8, so if you're pressing 8 and you're just slightly to the left, the board will read as contacting pads 2, 5, and 8. This might be tweaked by adjusting the threshold values, but I haven't tried yet.

The hardware works with no modifications necessary. Here's the code adapted to C#:

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;

namespace SparkFun {
	public class TouchShield {
		const byte TOU_THRESH = 0x0F;
		const byte REL_THRESH = 0x0A;
		const byte MPR121_ADDRESS = 0x5A;
		const int MPR121_TIMEOUT = 40;

		[Flags]
		public enum Cap_Buttons : int { 
			KEY_0 = 0x0400,
			KEY_1 = 0x0100, 
			KEY_2 = 0x0020,
			KEY_3 = 0x0004,
			KEY_4 = 0x0080,
			KEY_5 = 0x0010,
			KEY_6 = 0x0002,
			KEY_7 = 0x0040,
			KEY_8 = 0x0008,
			KEY_9 = 0x0001,
			KEY_10,
			KEY_11,
			KEY_12
		}
		readonly int[] DigitMap = {0x0400,0x0100,0x0020,0x0004,0x0080,0x0010,0x0002,0x0040,0x0008,0x0001};

		public static class Registers {
			public const byte ELE0_7_TOUCH_STATUS = 0x00;
			public const byte ELE8_11_PROX_TOUCH_STATUS = 0x01;

			public const byte ELE0_7_OOR_STATUS = 0x02;
			public const byte ELE8_11_PROX_OOR_STATUS = 0x03;

			public const byte ELE0_FILTER_DATA_LSB = 0x04;
			public const byte ELE0_FILTER_DATA_MSB = 0x05;
			public const byte ELE1_FILTER_DATA_LSB = 0x06;
			public const byte ELE1_FILTER_DATA_MSB = 0x07;
			public const byte ELE2_FILTER_DATA_LSB = 0x08;
			public const byte ELE2_FILTER_DATA_MSB = 0x09;
			public const byte ELE3_FILTER_DATA_LSB = 0x0A;
			public const byte ELE3_FILTER_DATA_MSB = 0x0B;
			public const byte ELE4_FILTER_DATA_LSB = 0x0C;
			public const byte ELE4_FILTER_DATA_MSB = 0x0D;
			public const byte ELE5_FILTER_DATA_LSB = 0x0E;
			public const byte ELE5_FILTER_DATA_MSB = 0x0F;
			public const byte ELE6_FILTER_DATA_LSB = 0x10;
			public const byte ELE6_FILTER_DATA_MSB = 0x11;
			public const byte ELE7_FILTER_DATA_LSB = 0x12;
			public const byte ELE7_FILTER_DATA_MSB = 0x13;
			public const byte ELE8_FILTER_DATA_LSB = 0x14;
			public const byte ELE8_FILTER_DATA_MSB = 0x15;
			public const byte ELE9_FILTER_DATA_LSB = 0x16;
			public const byte ELE9_FILTER_DATA_MSB = 0x17;
			public const byte ELE10_FILTER_DATA_LSB = 0x18;
			public const byte ELE10_FILTER_DATA_MSB = 0x19;
			public const byte ELE11_FILTER_DATA_LSB = 0x1A;
			public const byte ELE11_FILTER_DATA_MSB = 0x1B;
			public const byte ELEPROX_FILTER_DATA_LSB = 0x1C;
			public const byte ELEPROX_FILTER_DATA_MSB = 0x1D;

			public const byte ELE0_BASELINE = 0x1E;
			public const byte ELE1_BASELINE = 0x1F;
			public const byte ELE2_BASELINE = 0x20;
			public const byte ELE3_BASELINE = 0x21;
			public const byte ELE4_BASELINE = 0x22;
			public const byte ELE5_BASELINE = 0x23;
			public const byte ELE6_BASELINE = 0x24;
			public const byte ELE7_BASELINE = 0x25;
			public const byte ELE8_BASELINE = 0x26;
			public const byte ELE9_BASELINE = 0x27;
			public const byte ELE10_BASELINE = 0x28;
			public const byte ELE11_BASELINE = 0x29;
			public const byte ELEPROX_BASELINE = 0x2A;

			public const byte MHD_RISING = 0x2B;
			public const byte NHD_AMOUNT_RISING = 0x2C;
			public const byte NCL_RRISING = 0x2D;
			public const byte FDL_RISING = 0x2E;
			public const byte MHD_FALLING = 0x2F;
			public const byte NHD_AMOUNT_FALLING = 0x30;
			public const byte NCL_FALLING = 0x31;
			public const byte FDL_FALLING = 0x32;
			public const byte NHD_AMOUNT_TOUCHED = 0x33;
			public const byte NCL_TOUCHED = 0x34;
			public const byte FDL_TOUCHED = 0x35;

			public const byte ELEPROX_MHD_RISING = 0x36;
			public const byte ELEPROX_NHD_AMOUNT_RISING = 0x37;
			public const byte ELEPROX_NCL_RRISING = 0x38;
			public const byte ELEPROX_FDL_RISING = 0x39;
			public const byte ELEPROX_MHD_FALLING = 0x3A;
			public const byte ELEPROX_NHD_AMOUNT_FALLING = 0x3B;
			public const byte ELEPROX_NCL_FALLING = 0x3C;
			public const byte ELEPROX_FDL_FALLING = 0x3D;
			public const byte ELEPROX_NHD_AMOUNT_TOUCHED = 0x3E;
			public const byte ELEPROX_NCL_TOUCHED = 0x3F;
			public const byte ELEPROX_FDL_TOUCHED = 0x40;

			public const byte ELE0_Touch_Threshold = 0x41;
			public const byte ELE0_Release_Threshold = 0x42;
			public const byte ELE1_Touch_Threshold = 0x43;
			public const byte ELE1_Release_Threshold = 0x44;
			public const byte ELE2_Touch_Threshold = 0x45;
			public const byte ELE2_Release_Threshold = 0x46;
			public const byte ELE3_Touch_Threshold = 0x47;
			public const byte ELE3_Release_Threshold = 0x48;
			public const byte ELE4_Touch_Threshold = 0x49;
			public const byte ELE4_Release_Threshold = 0x4A;
			public const byte ELE5_Touch_Threshold = 0x4B;
			public const byte ELE5_Release_Threshold = 0x4C;
			public const byte ELE6_Touch_Threshold = 0x4D;
			public const byte ELE6_Release_Threshold = 0x4E;
			public const byte ELE7_Touch_Threshold = 0x4F;
			public const byte ELE7_Release_Threshold = 0x50;
			public const byte ELE8_Touch_Threshold = 0x51;
			public const byte ELE8_Release_Threshold = 0x52;
			public const byte ELE9_Touch_Threshold = 0x53;
			public const byte ELE9_Release_Threshold = 0x54;
			public const byte ELE10_Touch_Threshold = 0x55;
			public const byte ELE10_Release_Threshold = 0x56;
			public const byte ELE11_Touch_Threshold = 0x57;
			public const byte ELE11_Release_Threshold = 0x58;
			public const byte ELEPROX_Touch_Threshold = 0x59;
			public const byte ELEPROX_Release_Threshold = 0x5A;

			public const byte Debounce_Touch_Release = 0x5B;

			public const byte AFE_Cenfiguration = 0x5C;
			public const byte Filter_Configuration = 0x5D;
			public const byte Electrode_Configuration = 0x5E;

			public const byte ELE0_Electrode_Current = 0x5F;
			public const byte ELE1_Electrode_Current = 0x60;
			public const byte ELE2_Electrode_Current = 0x61;
			public const byte ELE3_Electrode_Current = 0x62;
			public const byte ELE4_Electrode_Current = 0x63;
			public const byte ELE5_Electrode_Current = 0x64;
			public const byte ELE6_Electrode_Current = 0x65;
			public const byte ELE7_Electrode_Current = 0x66;
			public const byte ELE8_Electrode_Current = 0x67;
			public const byte ELE9_Electrode_Current = 0x68;
			public const byte ELE10_Electrode_Current = 0x69;
			public const byte ELE11_Electrode_Current = 0x6A;
			public const byte ELEPROX_Electrode_Current = 0x6B;

			public const byte ELE0_ELE1_Charge_Time = 0x6C;
			public const byte ELE2_ELE3_Charge_Time = 0x6D;
			public const byte ELE4_ELE5_Charge_Time = 0x6E;
			public const byte ELE6_ELE7_Charge_Time = 0x6F;
			public const byte ELE8_ELE9_Charge_Time = 0x70;
			public const byte ELE10_ELE11_Charge_Time = 0x71;
			public const byte ELEPROX_Charge_Time = 0x72;

			public const byte GPIO_CTRL0 = 0x73;
			public const byte GPIO_CTRL1 = 0x74;
			public const byte GPIO_DATA = 0x75;
			public const byte GPIO_DIRECTION = 0x76;
			public const byte GPIO_ENABLE = 0x77;
			public const byte GPIO_DATA_SET = 0x78;
			public const byte GPIO_DATA_CLEAR = 0x79;
			public const byte GPIO_DATA_TOGGLE = 0x7A;

			public const byte AUTO_CONFIG_CONTROL_0 = 0x7B;
			public const byte AUTO_CONFIG_CONTROL_1 = 0x7C;
			public const byte AUTO_CONFIG_USL = 0x7D;
			public const byte AUTO_CONFIG_LSL = 0x7E;
			public const byte AUTO_CONFIG_TARGET_LEVEL = 0x7F;
		}


		readonly InterruptPort irqpin = new InterruptPort(Pins.GPIO_PIN_D2, true, ResistorModes.Disabled, Port.InterruptMode.InterruptEdgeLow);
		//static MPR121 controller;
		readonly I2CDevice Device;
		readonly I2CDevice.Configuration Config;

		public TouchShield(I2CDevice device) {
			Config = new I2CDevice.Configuration(MPR121_ADDRESS, MPR121_TIMEOUT);
			Device = device;
			QuickConfig();
			irqpin.OnInterrupt += new NativeEventHandler(getNumber);
		}

		/// <summary>
		/// Simple read of device.
		/// </summary>
		/// <param name="memoryAddress">Initial register address.</param>
		/// <param name="responseLength">Optional read length.</param>
		/// <returns></returns>
		public byte[] Read(byte memoryAddress, int responseLength = 1, int timeout = 40) {
			lock (Device) {
				Device.Config = this.Config;
				var buffer = new byte[responseLength];
				var transaction = new I2CDevice.I2CTransaction[] {
					I2CDevice.CreateWriteTransaction(new byte[] { memoryAddress }),
					I2CDevice.CreateReadTransaction(buffer)
				};
				int result = Device.Execute(transaction, timeout);
				return buffer;
			}
		}

		/// <summary>
		/// Simple write to the device.
		/// </summary>
		/// <param name="memoryAddress">Register address to write.</param>
		/// <param name="value">Byte to write.</param>
		public void Write(byte memoryAddress, byte value, int timeout = 40) {
			lock (Device) {
				Device.Config = this.Config;
				var transaction = new I2CDevice.I2CTransaction[] {
					I2CDevice.CreateWriteTransaction(new byte[] { memoryAddress, value })
				};
				int result = Device.Execute(transaction, timeout);
			}
		}


		public void QuickConfig() {
			// Section A
			// This group controls filtering when data is > baseline.
			Write(Registers.MHD_RISING, 0x01);
			Write(Registers.NHD_AMOUNT_RISING, 0x01);
			Write(Registers.NCL_RRISING, 0x00);
			Write(Registers.FDL_RISING, 0x00);

			// Section B
			// This group controls filtering when data is < baseline.
			Write(Registers.MHD_FALLING, 0x01);
			Write(Registers.NHD_AMOUNT_FALLING, 0x01);
			Write(Registers.NCL_FALLING, 0xFF);
			Write(Registers.FDL_RISING, 0x02);

			// Section C
			// This group sets touch and release thresholds for each electrode
			Write(Registers.ELE0_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE0_Release_Threshold, REL_THRESH);
			Write(Registers.ELE1_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE1_Release_Threshold, REL_THRESH);
			Write(Registers.ELE2_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE2_Release_Threshold, REL_THRESH);
			Write(Registers.ELE3_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE3_Release_Threshold, REL_THRESH);
			Write(Registers.ELE4_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE4_Release_Threshold, REL_THRESH);
			Write(Registers.ELE5_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE5_Release_Threshold, REL_THRESH);
			Write(Registers.ELE6_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE6_Release_Threshold, REL_THRESH);
			Write(Registers.ELE7_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE7_Release_Threshold, REL_THRESH);
			Write(Registers.ELE8_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE8_Release_Threshold, REL_THRESH);
			Write(Registers.ELE9_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE9_Release_Threshold, REL_THRESH);
			Write(Registers.ELE10_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE10_Release_Threshold, REL_THRESH);
			Write(Registers.ELE11_Touch_Threshold, TOU_THRESH);
			Write(Registers.ELE11_Release_Threshold, REL_THRESH);

			// Section D
			// Set the Filter Configuration
			// Set ESI2
			Write(Registers.Filter_Configuration, 0x02);

			// Section E
			// Electrode Configuration
			// Must be written last
			// Enable 6 Electrodes and set to run mode
			Write(Registers.Electrode_Configuration, 0x0C); // Enables all 12 Electrodes
			//Write(Registers.Electrode_Configuration, 0x06); // Enables first 6 Electrodes
		}


		void getNumber(uint data1, uint data2, DateTime time) {
			byte[] status = Read(0x00, 2);
			int buttonStatus = (status[1] << 8) | status[0];
			string buttons = String.Empty;

			for (int n = 0; n < DigitMap.Length; n++) {
				buttons += ((buttonStatus & DigitMap[n]) == DigitMap[n]) ?
					n.ToString() : "_";
				buttons += " ";
			}
			

			Debug.Print(HexStr(status) + " " + buttons);
		}

		/// <summary>
		/// Returns the number of true bits.
		/// </summary>
		static int BitCount(int data) {
			int count = 0;
			int mask = 0x01;
			for (int n = 0; n < 16; n++) {
				mask = mask << 1;
				if (mask == (data & mask))
					count++;
			}
			return count;
		}

		/// <summary>
		/// Converts a byte array to a hexidecimal string
		/// </summary>
		public static string HexStr(byte[] p) {
			char[] c = new char[p.Length * 2 + 2];
			byte b;
			c[0] = '0'; c[1] = 'x';
			for (int y = 0, x = 2; y < p.Length; ++y, ++x) {
				b = ((byte)(p[y] >> 4));
				c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
				b = ((byte)(p[y] & 0xF));
				c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
			}
			return new string(c);
		}
	}
}


#2 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 05 November 2011 - 05:19 PM

Hi Eric, That's pretty good--and very affordable. I didn't realize that SparkFun made a touch shield like that. I'm now envisioning my new microwave with "popcorn" and "1 minute" buttons :) :) Thanks for sharing! Chris

#3 Pablo

Pablo

    New Member

  • Members
  • Pip
  • 7 posts

Posted 23 June 2012 - 03:44 PM

Hi Eric, I'm working on a project with your code. I need to place the sensors behind a glass 5mm thick. You know if it will work and how I must change the setting to increase the sensitivity and detection by proximity in each sensor?. Regards, Pablo




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.