Using NeoKey touch to control what Button does

Adafruit's tiny microcontroller platform. Please tell us which board you are using.
For CircuitPython issues, ask in the Adafruit CircuitPython forum.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
earthstephen
 
Posts: 9
Joined: Tue Dec 05, 2017 9:13 pm

Using NeoKey touch to control what Button does

Post by earthstephen »

Using the NeoKey Trinkey and programing in the Arduino IDE v2.0.3

I am trying to use the capacitive touch pad of the board to toggle between two modes. Each mode is indicated by a different color from the neopixel. In each mode I want to execute a USB keyboard command but only if the board's button switch is pressed. Basically, use the touch pad to toggle between two different USB keyboard outputs when the button is pressed.

I can get parts of the code to work but can't get it to work together. I can use the touch pad to toggle between modes. I can get USB keyboard output when the button is pressed. But when I put it together as shown in the attached code, toggling the mode works but getting output when the key is pressed does not.

One clue, if I quickly cycle between the modes with the touch pad and repeatedly push the button, occasionally I get the desired output but only the first case (Alt + Keypad 0176 = ° the degree symbol)

I have been coding in the Arduino IDE for a while but still have a lot to learn and getting the braces right is one of my weak points.

Any Ideas?

Code: Select all

#include <Adafruit_NeoPixel.h>
#include <Adafruit_FreeTouch.h>
#include <Keyboard.h>
#include <Bounce2.h>
#define BUTTON_PIN PIN_SWITCH
//Bounce debouncedSwitch = Bounce();
Bounce2::Button debouncedSwitch = Bounce2::Button();

// Create the neopixel strip with the built in definitions NUM_NEOPIXEL and PIN_NEOPIXEL
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_NEOPIXEL, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);

// Create the touch pad
Adafruit_FreeTouch qt = Adafruit_FreeTouch(PIN_TOUCH, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE);

int16_t neo_brightness = 20; // initialize with 20 brightness (out of 255)

bool oldState = HIGH;
int     mode     = 0;
int switchClosed = LOW;
//bool switchClosedSetup;

void setup() {
  Serial.begin(9600);
  //while (!Serial);
  strip.begin();
  strip.setBrightness(neo_brightness);
  strip.show(); // Initialize all pixels to 'off'

  if (! qt.begin())
  Serial.println("Failed to begin qt");
  debouncedSwitch.attach(BUTTON_PIN, INPUT_PULLDOWN);
  debouncedSwitch.interval(5);
  debouncedSwitch.setPressedState(LOW);  
  Keyboard.begin();
}

uint8_t j=0;
void loop() {
  bool newState = HIGH;
  // measure the captouches
  uint16_t touch = qt.measure();
  // If the pad is touched, turn on neopix!
	if (touch > 500) {newState = LOW;}
	if((newState == LOW) && (oldState == HIGH)) {
		// Short delay to debounce button.
		delay(50);
		uint16_t touch = qt.measure();
		if (touch > 500) {newState = LOW;}
		if(newState == LOW) {      // Yes, still low
			if(++mode > 1) mode = 0; // Advance to next mode, wrap around after #1
			// Update the Bounce instance :
			switch(mode){ 
				{case 0:
					Serial.println("Case 0");
					// check mechswitch
					strip.setPixelColor(0, strip.Color(255,0,0));
					strip.show();
					debouncedSwitch.update();
					// Get the updated value :
					if (debouncedSwitch.pressed() ) {
						Keyboard.press(KEY_LEFT_ALT);
						Keyboard.press(KEY_KP_0);
						Keyboard.press(KEY_KP_1);
						Keyboard.press(KEY_KP_7);
						Keyboard.press(KEY_KP_6);
						Keyboard.releaseAll();
					}
					break;
				}
				{case 1:
					Serial.println("Case 1");
					strip.setPixelColor(0, strip.Color(0,255,0));
					strip.show();
					debouncedSwitch.update();
					// Get the updated value :
					if (debouncedSwitch.pressed() ) {
						Keyboard.press(KEY_LEFT_ALT);
						Keyboard.press(KEY_KP_0);
						Keyboard.press(KEY_KP_1);
						Keyboard.press(KEY_KP_5);
						Keyboard.press(KEY_KP_0);
						Keyboard.releaseAll();
					}
					break;
				}
			}
		}
	}
  oldState = newState;
}

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using NeoKey touch to control what Button does

Post by adafruit_support_mike »

Your code is so deeply nested that you're probably getting unwanted interaction between the control conditions.

The first step would be to separate checking the capacitive touch sensor from checking the mechanical key button. Do one, then do the other.

Personally, I'm not fond of the 'compare old value to new value' version of switch debouncing. I find it easier and more powerful to use a shift register:

Code: Select all

    void loop () {
        static uint8_t touch_register = 0;
    
        touch_register <<= 1;
        touch_register += ( 500 > qt.measure() ) ? 0 : 1;
    
        delay( 50 );
    }
Each pass through loop() shifts the bits in the register left one position, then adds the most recent reading as the lowest bit. In effect, the bits in touch_register act like a slow, low-resolution oscilloscope trace of the switch voltage. The register holds the most recent 8 readings, so you get tracking over time for free.

Better yet, all the possible 'scope traces' are numbers, so you can select various conditions by value:

Code: Select all

    1111 1111   // (0xff) switch is being held open
    1000 0000   // (0x80) properly debounced keypress
    0000 0000   // (0x00) switch is being held low
    0111 1111   // (0x7f) properly debounced release
and use those values to control your code:

Code: Select all

        if ( 0x80 == touch_register ) {
            if ( 0 == mode ) {
                mode = 1;
                strip.setPixelColor(0, strip.Color(255,0,0));
            } else {
                mode = 0;
                strip.setPixelColor(0, strip.Color(0,255,0));
            }
            strip.show();
        }
And then you can check the mechanical switch:

Code: Select all

        debouncedSwitch.update();

        if (debouncedSwitch.pressed() ) {
            switch ( mode ) {
                case 0 : mode_0_press();  break;
                case 1 : mode_1_press();  break;
            }
        }
The switch() statement gives you the flexibility to cycle through more than two states if you want.

In terms of code style, switch() statements are always more readable if you move the switched behavior out to separate functions. The compiler will eliminate the function calls automatically, so there's no effect on performance.

That way of writing the code has much less conditional nesting, making the code's behavior much easier to predict.

User avatar
earthstephen
 
Posts: 9
Joined: Tue Dec 05, 2017 9:13 pm

Re: Using NeoKey touch to control what Button does

Post by earthstephen »

Thanks for the feedback. Cool technique with the shift register. I'll have to explore that further. I never was really happy with the performance of the other code for the touch pad. It is far to fiddly to get the mode you want. It wants to skip the desired mode and go back to the one it was in.
Also interesting idea about moving the switch cases out to separate functions. Anything that makes the code easier to read and trace is a good thing.

I was finally able to get the code to work. One problem was I was using INPUT_PULLUP on the switch but should have been using INPUT_PULLDOWN. I also figured out before your post that one of my problems was I needed to to separate out the two control conditions so you are spot on there. I had tried that before but went back because it hadn't helped. The issue was other problems though. I ended up going with an interrupt for the key button. Might not be necessary but it works.

I will keep on polishing the code to get it to work better but here is my current working version:

Code: Select all

#include <Adafruit_NeoPixel.h>
#include <Adafruit_FreeTouch.h>
#include <Keyboard.h>

// Create the neopixel strip with the built in definitions NUM_NEOPIXEL and PIN_NEOPIXEL
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_NEOPIXEL, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);

// Create the touch pad
Adafruit_FreeTouch qt = Adafruit_FreeTouch(PIN_TOUCH, OVERSAMPLE_4, RESISTOR_50K, FREQ_MODE_NONE);

int16_t neo_brightness = 20; // initialize with 20 brightness (out of 255)

bool oldState = HIGH;
int     mode     = 0;
volatile int switchClosed = LOW;

void setup() {
  Serial.begin(9600);
  //while (!Serial);
  strip.begin();
  strip.setBrightness(neo_brightness);
  strip.show(); // Initialize all pixels to 'off'

  if (! qt.begin())
  Serial.println("Failed to begin qt");
  Keyboard.begin();
  pinMode(PIN_SWITCH, INPUT_PULLDOWN);
  attachInterrupt(digitalPinToInterrupt(PIN_SWITCH), Button, RISING);
}

uint8_t j=0;
void loop() {
  bool newState = HIGH;
  // measure the captouches
  uint16_t touch = qt.measure();
  // If the pad is touched, turn on neopix!
	if (touch > 500) {newState = LOW;}
	if((newState == LOW) && (oldState == HIGH)) {
		// Short delay to debounce button.
		delay(50);
		uint16_t touch = qt.measure();
		if (touch > 500) {newState = LOW;}
		if(newState == LOW) {      // Yes, still low
			if(++mode > 1) {mode = 0;} // Advance to next mode, wrap around after #1
		}
  }
  oldState = newState;
  switch(mode){ 
		{case 0:
			strip.setPixelColor(0, strip.Color(255,0,0));
			strip.show();
			if (switchClosed == HIGH) {
				Keyboard.press(KEY_LEFT_ALT);
				Keyboard.press(KEY_KP_0);
				Keyboard.press(KEY_KP_1);
				Keyboard.press(KEY_KP_7);
				Keyboard.press(KEY_KP_6);
				Keyboard.releaseAll();
			}
      switchClosed = LOW; 
			break;
    }
		{case 1:
			strip.setPixelColor(0, strip.Color(0,255,0));
			strip.show();
			if (switchClosed == HIGH) {
				Keyboard.print("Hello World");
			}
      switchClosed = LOW;          
			break;
		}
	}
}
void Button(){
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > 200) 
  {  
  switchClosed = HIGH;
  }
  last_interrupt_time = interrupt_time;  
}
Thanks again for your input!

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Using NeoKey touch to control what Button does

Post by adafruit_support_mike »

Glad to hear you got it working. Happy hacking!

Locked
Please be positive and constructive with your questions and comments.

Return to “Trinket ATTiny, Trinket M0”