Multi-touch force & position sensing with Arduino
Implementing the optimizations discussed in the previous section, we'll write a revised Arduino sketch and attempt to scan the MatrixArray at maximum speed.
Note that we've sacrificed some portability (due to direct port manipulation), code is now specific to the Arduino Uno and boards with compatible port / header mappings. We've also eliminated output spacing and line breaks, so we'll have to create a new receiving application (in Part 8) to make sense of the data being sent.
Performance improvement results are shown on the next page.
Here is the optimized version incorporating the improvements described above:
⬇ Download FastMatrixArray.zip (Arduino Project)
/**********************************************************************************************************
* Project: FastMatrixArray.ino
* By: Chris Wittmier @ Sensitronics LLC
* LastRev: 04/22/2014
* Description: Optimized for faster scan rate. Uno-specific.
**********************************************************************************************************/
#define BAUD_RATE 115200
#define ROW_COUNT 10
#define COLUMN_COUNT 16
#define PIN_ADC_INPUT A0
#define PIN_SHIFT_REGISTER_DATA 2
#define PIN_SHIFT_REGISTER_CLOCK 3
#define PIN_MUX_CHANNEL_0 4
#define PIN_MUX_CHANNEL_1 5
#define PIN_MUX_CHANNEL_2 6
#define PIN_MUX_INHIBIT_0 7
#define PIN_MUX_INHIBIT_1 8
#define SET_SR_DATA_HIGH() PORTD|=B00000100
#define SET_SR_DATA_LOW() PORTD&=~B00000100
#define SET_SR_CLK_HIGH() PORTD|=B00001000
#define SET_SR_CLK_LOW() PORTD&=~B00001000
#define ROWS_PER_MUX 8
#define MUX_COUNT 2
#define CHANNEL_PINS_PER_MUX 3
#define PACKET_END_BYTE 0xFF
#define MAX_SEND_VALUE 254
#define COMPRESSED_ZERO_LIMIT 254
#define MIN_SEND_VALUE 1
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
int current_enabled_mux = MUX_COUNT - 1;
int compressed_zero_count = 0;
void setup()
{
Serial.begin(BAUD_RATE);
pinMode(PIN_ADC_INPUT, INPUT);
pinMode(PIN_SHIFT_REGISTER_DATA, OUTPUT);
pinMode(PIN_SHIFT_REGISTER_CLOCK, OUTPUT);
pinMode(PIN_MUX_CHANNEL_0, OUTPUT);
pinMode(PIN_MUX_CHANNEL_1, OUTPUT);
pinMode(PIN_MUX_CHANNEL_2, OUTPUT);
pinMode(PIN_MUX_INHIBIT_0, OUTPUT);
pinMode(PIN_MUX_INHIBIT_1, OUTPUT);
sbi(ADCSRA,ADPS2);
cbi(ADCSRA,ADPS1);
cbi(ADCSRA,ADPS0);
}
void loop()
{
compressed_zero_count = 0;
for(int i = 0; i < ROW_COUNT; i ++)
{
setRow(i);
shiftColumn(true);
for(int j = 0; j < COLUMN_COUNT; j ++)
{
int raw_reading = analogRead(PIN_ADC_INPUT);
byte send_reading = (byte) (lowByte(raw_reading >> 2));
shiftColumn(false);
sendCompressed(send_reading);
}
}
if(compressed_zero_count > 0)
{
Serial.write((byte) 0);
Serial.write((byte) compressed_zero_count);
}
Serial.write((byte) PACKET_END_BYTE);
}
void setRow(int row_number)
{
if((row_number % ROWS_PER_MUX) == 0)
{
digitalWrite(PIN_MUX_INHIBIT_0 + current_enabled_mux, HIGH);
current_enabled_mux ++;
if(current_enabled_mux >= MUX_COUNT) { current_enabled_mux = 0; }
digitalWrite(PIN_MUX_INHIBIT_0 + current_enabled_mux, LOW);
}
for(int i = 0; i < CHANNEL_PINS_PER_MUX; i ++)
{
if(bitRead(row_number, i)) { digitalWrite(PIN_MUX_CHANNEL_0 + i, HIGH); }
else { digitalWrite(PIN_MUX_CHANNEL_0 + i, LOW); }
}
}
void shiftColumn(boolean is_first)
{
if(is_first) { SET_SR_DATA_HIGH(); }
SET_SR_CLK_HIGH();
SET_SR_CLK_LOW();
if(is_first) { SET_SR_DATA_LOW(); }
}
void sendCompressed(byte value)
{
if(value < MIN_SEND_VALUE)
{
if(compressed_zero_count < (COMPRESSED_ZERO_LIMIT - 1))
compressed_zero_count ++;
else
{
Serial.write((byte) 0);
Serial.write((byte) COMPRESSED_ZERO_LIMIT);
compressed_zero_count = 0;
}
}
else
{
if(compressed_zero_count > 0)
{
Serial.write((byte) 0);
Serial.write((byte) compressed_zero_count);
compressed_zero_count = 0;
}
if(value > MAX_SEND_VALUE) Serial.write((byte) MAX_SEND_VALUE);
else Serial.write((byte) value);
}
}