QuickStart and Touch Button demo
ErNa
Posts: 1,752
Did anybody make use of the touch buttons on the quickstart board? In my case, there is obviously a heavy bouncing and I can not measure the pin voltage: the moment I touch the button with a scope probe, the switch is activated and so I do not have any information what really happens. The demo software (Touch Buttons LED Demo v1.0) starts sampling 100 Hz and then loops 32 times, free running and not synchronized to the sampling.
Comments
I thought the touchpads worked reasonably well with my QuickStart servo tester but there just so much overhead to monitor the pads, I don't use them often in my own projects. Buttons are really cheap and IMO work much better than the touchpads.
Kind of a shame there isn't a connector site to hook external switches to them...
When bridging the pads with a conductor, that generates a clear signal, so a switch is the best solution, but not implemented.
But the strength of the propeller is to do things differently.
I now changed the decay time to half a ms, which gives a clear decay from 2.9 to .5V when measured with the scope (as mentioned: the scope "destroys" the signal, so this is not what happens when not measured. But now I replace the wait by a loop and the input read I output on another pin, so I can see, when the input detects low or high. It turns out: when I touch the central pad, the signal is active for 4,7ms in a 20ms period. So during about 8 decay periods of 40 the signal is measured active. That means: I have to measure not faster than mains frequency and should have more than 10 % duty cycle.
That I will implement now and see, if it works stable.
So two effects are combined: EMI from mains and resistive load to the pin. The moment I wet my finger, the electrical contact is dominant and the signal comes continuously. It takes rather long to dry the finger again.
The signal definitely is pressure sensitive, the harder I push, the longer the period is. From the scope is visible, that the speed of touch can be detected! So a nice sensing device can be made this way.
But there has to be an electrical contact from the skin to the pad, the moment I insulate the pad with paper or film tape, no signal can be generated.
The outer loop emits the test pulse and Reading gets the response, that is a high or low bit for every button pushed.
The first strange appearance: one expects to have a LOW read back, when ever the finger touches the pad. But the opposite is true.
The input pins are 0-7, so 8 least significant bits have to be processed. That is done by the inner hloop.
I copy reading to Increment and mask lsBit., reading is shifted to right to prepare for the next turn.
My measurements have shown, that the result of delay varies over time with a 50Hz period, and a touched button can have a
duty cycle low/high reading from about 10 to 100%.
I am integrating the input to filter the signal and to count up/down with the same speed, high input has to count more. So I multiply the bit by 8 and subtract 1 to have now +7 for a high input and -1 for a low.
Via a RegistrPtr I address the appropriate accumulated value and add this value to the new read. Then I limit the accumulator to +-15, and that is not working properly: lower limit is not detected The first line adds to the current read the old accumulator value. The result can be any value from -16 to plus 23:
If the accumulator was at the lower limit, -15, adding -1 should result in -16. If the upper limit was reached, adding +7 gives 23.
I now add 15, so carry should be set when the value was -16 and now is -1. Then I set the value to 0.
Cmps checks for the upper limit and sets value to 32. So increment should be positive and =< 32.
In a next step I substract 15 to come back to +- value range. This value is stored to the accumulator register.
The last step isolates the sign bit and writes it to an output register, as the final result will be only a bit per pin.
In principle, that works nicely.
There is one weak point: the lower limit is not detected.
Any idea what is going wrong?
I think a common BUTTON module is a nice feature to have and more functionality could be implemented. I will now integrate the latest BUTTONS version into my shutter controller. I've already seen, that the Button state, as counting up and down creates a high load to the network and it might be better to count with less resolution, related to the fingers time slice ;-)
I could upload the latest version for Quickstart if there is interest
Rewrite it in Spin if you like.
[php]
/**
* This is a QuickStart Whack-a-Mole game.
*
* Copyright 2011 by Steve Denson.
* Rights MIT Licensed. See end of file.
*/
/**
* The Blue LED moles are eating up your QuickStart yard!
* You must get rid of them!
*
* Gameplay:
*
* All living moles will run around the QuickStart burrow during
* the game and you'll know they're alive by the dimly lit LEDs.
*
* Sometimes a mole will pop up as brighly lit LED and you must
* wack the mole pad to knock it out.
*
* When the moles are gone, your QuickStart yard will celebrate!
*
*/
#include <stdlib.h> // for rand() and seed()
#include <propeller.h> // for propeller functions.
/* game utilities */
void celebrate(void); // no more moles
int rotateLeft(int mask);
int rotateRight(int mask);
/* simple utilities */
void LEDOUT(int val); // set leds to val
void msleep(int t); // sleep for t ms
int getButton(int n); // used to get button states
int getButtons(); // used to get button states
/*
* Main program entry point
* Start with 8 moles and flick LEDs via rotating mask.
* Choose a random mole to light for fraction of a second.
* If the mole button is pushed while the LED is lit, kill the mole.
* When all moles are dead celebrate - check button press for restart.
*/
int main(void)
{
int molemask = 0xff; // live moles
int ontime = 1; // flicker on time in ms
int offtime = 80; // flicker off time
int whacked = 0; // it's whacked?
int direction = 1; // keep direction of LED mole run
int popcount = 6; // initial popcount
int countmask = 0x0700; // allow up to 7 mole run steps
int popmask = 0x7; // only 8 LEDs, choose from rand
int popupspot = 0; // show popup position
int popuptime = 500; // popup on time
/* mole run forever loop */
for(;;)
{
/* nothing whacked */
whacked = 0;
/* seed random function with Propeller CNT */
srand(CNT);
/* blank moles */
LEDOUT(0);
/* sleep a little */
msleep(offtime);
/* if all moles gone, celebrate */
while(!molemask) {
/* make LEDs dance */
celebrate();
/* if button press, restart game */
if(getButtons()) {
molemask = 0xff;
}
}
/* get popup spot */
if(popcount-- == 0) {
/* get random number */
popupspot = rand();
/* use upper bits for popup count */
popcount = (popupspot & countmask) >> 8;
/* use lower popmask bits for popup mole LED */
popupspot &= popmask;
/* show popup and check button */
if(molemask & (1<<popupspot)) {
/* set LED to show a mole to whack */
LEDOUT((1<<popupspot) & molemask);
/* single thread limit. sample twice */
msleep(popuptime>>1);
whacked = getButton(popupspot);
msleep(popuptime>>1);
whacked |= getButton(popupspot);
/* set back to mole mask */
LEDOUT(molemask);
}
}
/* mole whacked ? */
if(whacked) {
molemask &= ~(1<<popupspot);
}
/* if a random bit is set switch direction */
if(rand() & 0x20) {
direction ^= 1;
}
/* set new mole run spots */
if(direction) {
molemask = rotateRight(molemask);
}
else {
molemask = rotateLeft(molemask);
}
/* show mole run */
LEDOUT(molemask);
/* sleep a little so we can see the mole run */
msleep(ontime);
}
return 0;
}
/*
* make LEDs dance with a checker board pattern
*/
void celebrate(void)
{
int n = 16;
while(n-- > -1)
{
LEDOUT(0x55);
msleep(50);
LEDOUT(0xAA);
msleep(50);
}
LEDOUT(0);
msleep(400);
}
/*
* rotate mask left
*/
int rotateLeft(int mask)
{
int temp = mask << 1;
mask = (temp & 0x100) ? 1 : 0;
mask |= temp & 0xff;
return mask;
}
/*
* rotate mask right
*/
int rotateRight(int mask)
{
int temp = mask >> 1;
mask &= 0x01;
mask <<= 7;
mask |= temp;
return mask;
}
/*
* Set the LEDs to val
*/
void LEDOUT(int val)
{
DIRA |= 0xff << 16;
OUTA = (OUTA & ~(0xff<<16)) | (val<<16);
}
/*
* msleep makes the cog wait for about t milliseconds.
*/
void msleep(int t)
{
waitcnt((CLKFREQ/1000)*t+CNT);
}
/*
* Get a specific button number.
* buttons are enumerated from 0 to 7.
*/
int getButton(int n)
{
return (getButtons() & (1<<n));
}
/*
* Get all buttons at once
* Run this function from HUB if compiled for LMM.
*/
int getButtons()
{
int n = 16;
int result = -1;
int reading = 0;
int pins = 0xFF;
OUTA |= pins; //output high to buttons
while(n--)
{
DIRA |= pins; //output high to buttons
DIRA ^= pins; //switch to input
reading = pins;
msleep(2); //wait for RC time
reading &= INA; //return button states
result &= reading;
}
result = ~result & 0xFF;
return result;
}
/*
+
| TERMS OF USE: MIT License
+
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
*/[/php]