I am new to coding and embedded systems and I wanted to make a button that turns off and on a LED and at the same time turn off all other futures in the system.
So far I had the button turn off and on but I cant seem to get it to also update the Potentiometer. For some reason the code would check if the button is pressed and if so then the LED would turn on and then check if the LED is on and if so then turn on the other LEDs but when I change the value of the Potentiometer( which should switch to other LEDs) it would not update and stay on the same LED. So my question is how can I put another if statement that would keep updating in the while loop?
the code that I wanted to keep updating while the first LED is on is the "else if code" Hope that made sense. :)
note: I don't know if my approach is right as I am looking at the LED and not the button it self, as my code checks if the LED is on rather then if the button is pressed.
(btw its not a switch which would have made my life a lot easier :( )
#include "mbed.h"
DigitalIn userButton (PC_10);
DigitalOut led (PC_0);
bool buttonDown = false;
BusOut leds_bus (PC_1, PB_0, PA_4);
AnalogIn pot1 (PA_5);
void init_leds ();
int cntl_val = 0;
int main ()
{
cntl_val = pot1.read_u16 () / 32768;
while (true)
{
// run forever
if (userButton.read () == true)
{
// button is pressed
if (!buttonDown)
{
// a new button press
led = !led; // toogle LED
buttonDown = true; // record that the button is now down so we don't count one press lots of times
ThisThread::sleep_for (100);
}
else if (led.read () == true)
{
if (cntl_val < 1 / 3)
{
leds_bus.write (4);
}
if (cntl_val > (1 / 3) && cntl_val < (2 / 3))
{
leds_bus.write (2);
}
if (cntl_val > (2 / 3))
{
leds_bus.write (1);
}
}
}
else
{
// button isn't pressed
buttonDown = false;
}
}
}
CodePudding user response:
You need to fix your math. int cntl_val
is an integer so comparing it with the fractions 1/3 and 2/3 is not going to do what you expect. And cntl_val = pot1.read_u16()/32768;
can set cntl_val
to only 0 or 1. If the max value returned by pot.read_u16()
is less than 32768 then cntl_val
will only be 0.
You could maybe change cntl_val
to a float but that's probably not the best option.
Instead, try setting cntl_val = pot1.read_u16();
(don't divide by 32768). And then compare cntl_val
with (32768/3) and (32768*2/3). That's still ugly but better.
CodePudding user response:
It is not clear from your description, but I am assuming that you have:
- An on/off indicator LED
- A three-LED level indicator
- A momentary action button for on/off control
- A potentiometer to control the input level.
And that when the system is in the "on" state you wish to indicate the potentiometer level on the level indicator? That being the case, I suggest:
- Deal with button input/debounce separately from LED state determination.
- Simplify the level setting; you have a level 0, 1 or 2 which you can calculate by
unsigned level = (InputLevel * 3) / 32768 ;
. You can then use that level value in a bit-shift(1 << level)
to determine the LED to be set. Note that you had the low level set the high bit in your LED level indicator - that would require(4 >> level)
, which is somewhat clumsy if you were to ever increase the number of LEDs. It is easier to reverse the order of the GPIO in theBusOut
object.
Additional advice:
- Apply the rule of "minimal scope", localising variables to the minimum necessary scope (you have a number of unnecessary globals.
- In "big-loop" scheduling, avoid thread delays during which useful work might otherwise be done. Your debounce delay unnecessarily determines the rate at which other work can be done in the loop. The advice would be different if you were polling the button and setting the LEDs in separate threads.
For example (not this is coded blind/untested - treat it as illustrative of the general principles - it may need debugging):
#include "mbed.h"
int main ()
{
static const unsigned DEBOUNCE_MS = 20u ;
static const unsigned NUMBER_OF_LEVELS = 3u ;
DigitalIn OnOffButton( PC_10 ) ;
DigitalOut OnOffLed( PC_0 ) ;
BusOut LevelIndicator( PA_4, PB_0, PC_1 ) ;
AnalogIn InputLevel( PA_5 ) ;
bool isOn = false ;
int previous_button_state = OnOffButton ;
std::uint64_t button_change_time = 0 ;
for(;;)
{
// If debounce time expired check for button state change
if( Kernel::get_ms_count() - button_change_time > DEBOUNCE_MS )
{
int current_button_state = OnOffButton ;
// If button state changed
if( current_button_state != previous_button_state )
{
// If button-down
if( current_button_state != 0 )
{
// Toggle isOn
isOn = !isOn ;
}
// Change of state and debounce update
previous_button_state = current_button_state ;
button_change_time = Kernel::get_ms_count() ;
}
}
// Set the LEDs depending on On/Off state and input level
if( isOn )
{
OnOffLed = 1 ;
// Set level indicator
LevelIndicator = 1 << (InputLevel.read_u16() * NUMBER_OF_LEVELS / 32768u) ;
}
else
{
// System inactive (Off)
LevelIndicator = 0 ;
OnOffLed = 0 ;
}
}
}
You might also consider separating out the button and indicator processing into separate functions to increase cohesion, minimise coupling, simplify testing and improve maintainability and comprehensibility.
#include "mbed.h"
void updateIndicators( bool isOn ) ;
bool getOnOffState() ;
int main ()
{
for(;;)
{
updateIndicators( getOnOffState() ) ;
}
}
bool getOnOffState()
{
static const unsigned DEBOUNCE_MS = 20u ;
static DigitalIn OnOffButton( PC_10 ) ;
static bool state = false ;
static int previous_button_state = OnOffButton ;
static std::uint64_t button_change_time = 0 ;
// If debounce time expired check for button state change
if( Kernel::get_ms_count() - button_change_time > DEBOUNCE_MS )
{
int current_button_state = OnOffButton ;
// If button state changed
if( current_button_state != previous_button_state )
{
// If button-down
if( current_button_state != 0 )
{
// Toggle isOn
state = !state ;
}
// Change of state and debounce update
previous_button_state = current_button_state ;
button_change_time = Kernel::get_ms_count() ;
}
}
return state ;
}
void updateIndicators( bool isOn )
{
static const unsigned NUMBER_OF_LEVELS = 3u ;
static DigitalOut OnOffLed( PC_0 ) ;
static BusOut LevelIndicator( PA_4, PB_0, PC_1 ) ;
static AnalogIn InputLevel( PA_5 ) ;
// Set the LEDs depending on On/Off state and input level
if( isOn )
{
OnOffLed = 1 ;
// Set level indicator
LevelIndicator = 1 << (InputLevel.read_u16() * NUMBER_OF_LEVELS / 32768u) ;
}
else
{
// System inactive (Off)
LevelIndicator = 0 ;
OnOffLed = 0 ;
}
}