Button Press to Trigger Event
Hi Everyone,
So I think I'm oversimplifying how to use a button on the Propeller Professional Development Board to trigger an event. The idea is to press a button to start a block of code with that block of code lighting an LED and sending a binary number to an SPI to then be outputted to the board. Then, ideally, press that same button that started the block of code to end the process, turning off the LED that was initially lit. This would then repeat with that same button being used to trigger another block of code that would light a different LED and output a different binary number.
Currently I'm side stepping the use of one button for all of this (but please let me know if you have a suggestion on how to make it all work with just one button) and using two buttons. One button starts the block of code and the other ends it.
I'm having trouble getting that first button to actually trigger the event the way I would like. As it is now, using the button connected to pin 8, I have to hold pin 8 down while the code is being loaded to RAM in order to trigger the event. If I don't hold it down, the code doesn't get triggered. I understand that the ina[] function returns the current state of the pin, so do I have to put in some sort of wait time during which I can trigger the condition? Ideally I'd like the button to be pressed at any time to trigger the code.
The repeat until command for pin 7 works well to end the block.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR byte Data long atten long decimal long dec long Response OBJ SPI : "SPI_Spin" ''The Standalone SPI Spin engine PUB LED_On_Auto | P8Flag SPI.Start(15000, 1) 'HIGH(8) if ina[8] == 0 Data := %00000001 LOW(2) SPI.SHIFTOUT(0, 1, SPI#LSBFIRST, 8, Data) LED(3) { if ina[8] == 0 Data := %00000010 LOW(2) SPI.SHIFTOUT(0, 1, SPI#LSBFIRST, 8, Data) dira[4] := 1 outa[4] := 1 repeat until ina[7] == 0 } PUB HIGH(Pin) dira[Pin]~~ outa[Pin]~~ PUB LOW(Pin) dira[Pin]~~ outa[Pin]~ PUB LED(Pin) dira[Pin]~~ outa[Pin]~~ repeat until ina[7] == 0
Any thoughts?
Thanks for the help!
Zach
Comments
You might want to create a debounce function; doing a simple one-time check of a button -- even with a slow processor -- is not a good idea. Here's a simple bit of code that will test the state of a pin and verify that it remained in that state for a specified period (milliseconds).
I have a constant called MS_001 in my files -- this is the number of system ticks in one millisecond. For your convenience, I've attached my template; you might find parts of it helpful.
If I may... embedding pin numbers -- what we call "magic numbers" into your code is a habit you may come to regret later. It takes very little time to create named pin constants (I have one or two CON blocks devoted to IO pins (depending on the Propeller platform I use) . To give you a real-world example, ATM I'm working on a gaming device that is built using the EFX-TEK HC-8+ (a P1 board I designed for EFX-TEK several years ago). The HC-8+ has fixed IO pins, so you'll see that I define those, then create a block of application IO pins built on that. This doesn't take long to do, makes the code easier to read, and it's definitiely easier to troubleshoot.
Hi Jon,
Thank you for the debounce function and the tips. I now have that bit working so that when I press the button, the block of code executes until the other button is pressed. Now my question is, how do I then use that same button that started that code block to trigger another code block? I was wondering if I'll need a separate method/object that monitors the number of times that button is pressed with each press moving the program to the next block of code.
Thanks,
Zach
In the FWIW category.... After looking at spi_spin I decided to update it to the way I would code it (had I been the original author). My version assumes that the data out, data in, and clock pins are shared with one or more devices (which means the clock idle state must be the same for all). I can pass -1 for the data out or data in pin when it is not needed (e.g., I'm connecting to a device that only needs shiftin or only needs shiftout).
Beau's version has been around a while and allows you to slow the clock -- I have never needed this in all my years of Propeller programming. The advantage of SPI is that it's fast and many advanced programmers who have written SPI routines in assembly have come up with ways to get more speed out of the P1 (e.g., creative use of the counters). The goal of my version is to share pins and be faster, even in Spin. In a quick test I found that new new version using SHIFTOUT was about twice as fast as the order version )when the older version had no clock delay).
Anyway, you may find this helpful, and it will give you a bit of a speed boost while still using very simple code.
Are you wanting the button to control the state of a program? I'm not sure I understand exactly how you want the program to behave vis-a-vis button input(s). The hardest part of getting help is describing what you want so that others understand it (been there many times). Maybe a flow-chart would be helpful.
Here's another kind of debounce routine -- this will block program flow until a pin is at a desired state for a minimum number of milliseconds. This can be used to debounce press and release events from your button.
Zack, reading your first paragraph at the top of the page, it sounds like you want to make a state machine, where the button advances to the next state. Then each state would do what you need (light an LED, send info over SPI, etc.)
Take a look at the CASE statement - see the Propeller manual (in the Propeller tool, this is on the Help menu). One approach is to set up a variable that increments each time you press the button, then evaluate the variable and proceed to the next state.
That's a good call, Jeff.
Zach: State machines are very useful. Here's a very simple example of what Jeff was referring to:
In this case the program can have three possible states (defined by N_STATES). The case structure will call the code that runs the current state. If the state control variable is global, the state can modify that variable to modify the order of operation.
You wait until the button is released and then check again for a button press.
Here a possible code that looks a bit more like Spin and not PBASIC (not tested):
Andy
Hi Jon, Jeff, and Andy,
Yes Jeff, that is what I was attempting to describe to Jon initially. I'm working on creating a test box that will use a P1 chip. The idea is to use one button for everything in the process I'm describing. When the test box is turned on, pressing the button will do two things: one, it will illuminate a series of LED's to represent the starting binary number (through the program it will go from 00000001 to 011111111 in sequential order); and two, it will send out that binary number to a connected part using the SPI.
My issue, mostly due to my inexperience with SPIN and the P1 chip, at the moment is writing the program so that the button does all of that. So far, I have a decent idea of how to write it so that within each state the LED's light up and the binary gets sent using the SPI, it's just how to go from state to state using one button.
Thank you Jon and Andy for the pieces of code! I will play around with those to see how they work out.
Zach
Hi Andy,
I was able to adapt/build off the code you sent and it works really well. Thank you for the help.
Zach