Creating a switch statement with multiple digital inputs? (c++, mbed, nucleo) - c++

I am trying to compile a switch statement to create a combination lock of sorts from a nucleo board. At first I tried to tackle using multiple digital inputs in a switch statement by creating a bit mask and assigning integers, this seems to have gone alright however when I try to get my switch statement running it is stuck on case 0.
For a start case 0 should be no buttons pressed however it only activates once I press switch 1.
My second problem is that no other cases in my statement will activate at all.
I have no access to a debugger as mbed is not compatible with my nucleo board and I cannot get Keil Studio working so I am pretty stumped. Does anyone what is wrong with my statement or if there is an alternate way to refer to my digital inputs within the switch statement that may make it easier?
I am a coding n00b and have struggled to find much reference to my problem, any sample code I have looked at seems to work no problem and I cannot see where I have deviated from that code.
Code is below:
// You are to use these ojects to read the switch inputs
DigitalIn SW1(USER_BUTTON);
DigitalIn SW2(BTN1_PIN);
DigitalIn SW3(BTN2_PIN);
DigitalInOut SW4(BTN3_PIN, PIN_INPUT, PullDown, 0);
DigitalInOut SW5(BTN4_PIN, PIN_INPUT, PullDown, 0);
// You are to use this object to control the LEDs
BusOut leds(TRAF_RED1_PIN, TRAF_YEL1_PIN, TRAF_GRN1_PIN);
// Use this to sound an error
Buzzer alarm;
int main()
{
while (true)
{
leds = 0;
// Beep
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
// Wait for the blue button using a while loop
while (SW1==0) { };
// For full marks, debounce the switches with suitable delays
// This is a "combination lock" activity. Write some code to detect the following sequence of press-and-release inputs
// SW1, SW2, SW5, SW3 and SW4, SW2 and SW3
// If the full sequence is entered, correctly, the green LED should flash 3 times
// If a sequence of inputs was entered incorrectly, the red LED should light and the buzzer should sound for 5 seconds
// For full marks, debounce the switches and use flow control structures and arrays to avoid deep nesting of code
// ***** MODIFY THE CODE BELOW HERE *****
// ***** MODIFY THE CODE ABOVE HERE *****
int Inputs = (SW1==0) << 0 | (SW2==1) << 1 | (SW3==1) << 2 | (SW4==1) << 3 | (SW5==1) << 4;
int i;
switch (Inputs) {
case 0:
printf("Please Enter Combination\n");
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
break;
case 1:
printf("Input 1 is Correct\n");
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
break;
case 2:
printf("Input 2 is Correct\n");
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
break;
case 16:
printf("Input 3 is Correct\n");
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
break;
case 12:
printf("Input 4 is Correct\n");
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
break;
case 6:
printf("Combination is Correct!\n");
for (int i = 0; i < 3; i = i +1)
{
leds = 1;
wait_us(1000000);
leds = 0;
wait_us(1000000);
}
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}

You can make a bitmask integer where each bit corresponds to the state of one button like this:
unsigned int inputs = (SW1==0) << 0 | (SW2==0) << 1 | (SW3==0) << 2 | (SW4==0) << 3 | (SW5==0) << 4;
If you haven't seen those operators before, << is a left shift operator and | is a logical OR operator and you can look them up in any decent C++ book or introductory resource.
Your switch statement might look like this:
switch(inputs) {
case 0: // No buttons pressed
break;
case 1: // SW1 pressed (bit 0 is 1)
break;
case 2: // SW2 pressed (bit 1 is 1)
break;
case 4: // SW3 pressed (bit 2 is 1)
break;
case 6: // SW2 and SW3 pressed
break;
case 8: // SW4 pressed (bit 4 is 1)
break;
// ...
case 31: // All switches pressed
break;
}

Related

Reading CAN Bus bitmask

I have a netgain hyper9 motor and controller. Controller is hooked up to CAN bus. I am using an esp32 with mcp2515 to read the data. The format is as in the image here.
I can read a byte ok and get a number but can not correctly read the word (2bytes) nor can I get the correct bitmap.
I am using esphome to read this through a lambda function.
Are there any c++ / esphome lambda people that could help?
WORD FORMAT: All words are sent in Little-endian format which reverses the order and stores the least significant byte at the lower memory address with the most significant byte being stored at the highest memory address.
byte word format:
reading a bitmask:
reading rpm through 2 byte word:
canbus:
- platform: mcp2515
id: my_mcp2515
spi_id: McpSpi
cs_pin: GPIO14
can_id: 2
use_extended_id: false
bit_rate: 250KBPS
clock: 8MHZ
mode: NORMAL
on_frame:
- can_id: 0x301 #[canbus:066]: received can message std can_id=0x301 size=8
use_extended_id: false
then:
- lambda: |-
//State of Charge - works ok
int soc = x[2];
id(motor_battery_soc).publish_state(soc);
//RPM - word format
std::string r1 = to_string(x[0]);
std::string r2 = to_string(x[1]);
std::string rpmString = r2 + r1;
id(motor_rpm).publish_state(rpmString);
//System flags
ESP_LOGD("system_flags x3: ", "%d", x[3] );
ESP_LOGD("system_flags x4: ", "%d", x[4] );
std::string sf1 = to_string(x[3]);
std::string sf2 = to_string(x[4]);
std::string sfString = sf2 + sf1;
std::string sflag = " ";
ESP_LOGD("main", "sfString: %s", sfString);
// *** I know this is not correct because should search for a true/false flag on the bitmask ***
int sfInt = atoi(sfString.c_str());
ESP_LOGD("sfInt: ", "%d", sfInt);
switch(sfInt) {
case 0:
sflag = "SoC is Low For Traction";
id(motor_system_flags).publish_state("SoC is Low For Traction");
break;
case 1:
sflag = "SoC is Low For Hydraulic";
id(motor_system_flags).publish_state("SoC is Low For Hydraulic");
break;
case 2:
sflag = "Reverse Direction Active";
id(motor_system_flags).publish_state("Reverse Direction Active");
break;
case 3:
sflag = "Forward Direction Active";
id(motor_system_flags).publish_state("Forward Direction Active");
break;
case 4:
sflag = "Park Brake Active";
id(motor_system_flags).publish_state("Park Brake Active");
break;
case 5:
sflag = "Pedal Brake Active";
id(motor_system_flags).publish_state("Pedal Brake Active");
break;
case 6:
sflag = "Controller is in Overtemperature";
id(motor_system_flags).publish_state("Controller is in Overtemperature");
break;
case 7:
sflag = "Key Switch Overvoltage";
id(motor_system_flags).publish_state("Key Switch Overvoltage");
break;
case 8:
sflag = "Key Switch Undervoltage";
id(motor_system_flags).publish_state("Key Switch Undervoltage");
break;
case 9:
sflag = "Vehicle is Running";
id(motor_system_flags).publish_state("Vehicle is Running");
break;
case 10:
sflag = "Traction is Enabled";
id(motor_system_flags).publish_state("Traction is Enabled");
break;
case 11:
sflag = "Hydraulic is Enabled";
id(motor_system_flags).publish_state("Hydraulic is Enabled");
break;
case 12:
sflag = "Powering is Enabled";
id(motor_system_flags).publish_state("Powering is Enabled");
break;
case 13:
sflag = "Powering is Ready";
id(motor_system_flags).publish_state("Powering is Ready");
break;
case 14:
sflag = "Powering is Precharging";
id(motor_system_flags).publish_state("Powering is Precharging");
break;
case 15:
sflag = "Main Contactor Closing";
id(motor_system_flags).publish_state("Main Contactor Closing");
break;
default:
sflag = "No System Flag";
break;
}
id(motor_system_flags).publish_state(sflag);
//Fault code
int fault_code = x[5];
id(motor_fault_code).publish_state(fault_code);
//Motor Temp
int temp = x[6] - 40;
id(motor_temp).publish_state(temp);
text_sensor:
- platform: template
id: motor_system_flags
name: "Motor System Flags"
- platform: template
id: motor_rpm
name: "Motor RPM"
sensor:
- platform: template
id: motor_battery_soc
name: "Motor Battery SoC"
accuracy_decimals: 0
- platform: template
id: motor_fault_code
name: "Motor Fault Code"
- platform: template
id: motor_temp
name: "Motor Temp"
accuracy_decimals: 0

Understanding a function that reads data from a serial port

I'm struggling to understand what is happening in part of an Arduino program I wrote, I copied the switch in processInput from another post about reading data from serial ports but have changed it a bit since then.
To me it seems like the output to the LCD screen should always be 0 since recievedNumber is set to 0 at the beginning of the function, it does output the data from the serial port correctly though. I'm also not sure what is happening on the line "receivedNumber += b - '0';" inside the last case.
Any advice or a breakdown of the logic would be appreciated, I intended to replace the last case with an if statement to learn how to do it without using the GNU extension but I just don't understand what is happening.
An example of data in the serial port:
<45,56><55,54>
Sorry if this is the wrong place but it felt too related to programming to post on the Arduino StackExchage.
const char startOfNumberDelimiter = '<';
const char middleOfNumbersDelimiter = ',';
const char endOfNumberDelimiter = '>';
void processNumberC (const long c)
{
lcd.setCursor(10,0);
lcd.print(c);
lcd.print("C");
}
void processNumberG (const long g)
{
lcd.setCursor(10,1);
lcd.print(g);
lcd.print("C");
}
void processInput ()
{
static long receivedNumber = 0;
byte b = Serial.read ();
switch (b)
{
case middleOfNumbersDelimiter:
processNumberC (receivedNumber);
receivedNumber = 0;
break;
case endOfNumberDelimiter:
processNumberG (receivedNumber);
break;
case startOfNumberDelimiter:
receivedNumber = 0;
break;
case '0' ... '9':
receivedNumber *= 10;
receivedNumber += b - '0';
break;
} // end of switch
} // end of processInput
void loop()
{
while (Serial.available ())
processInput ();
}

Why does my switch/case default when using enums?

I have the following switch/case statement in Arduino 1.8.7 where the variable led is an integer:
switch (led) {
case ALL: {
/* do stuff */
break;
}
case LED1: {
/* do stuff */
break;
}
case LED2: {
/* do stuff */
break;
}
case LED3: {
/* do stuff */
break;
}
case LED4: {
/* do stuff */
break;
}
default: {
break;
}
}
I also have the following enum:
enum LED_References_e
{
ALL = 0,
LED1 = 1,
LED2 = 2,
LED3 = 3,
LED4 = 4
};
When using the enumerated values as cases to the statement, the statement always hits the default clause. If I substitute the enumerated values for the integers that they represent (i.e.case 0: ... case 1: ...) then the statement functions as expected.
I have tried, when using the enumerated values within the statement, to reference the enumerator as the value that the switch is performed on:
switch ((LED_References_e)led)
But this also defaults every time.
I am using another enumerator within my program and this functions correctly, however it is conditionally tested using if/else as opposed to switch/case.
My question is twofold:
Why does the switch/case statement seemingly not work with enumerated values?
What fundamental difference am I missing between if/else and switch/case?
Assuming Max Langhof is correct and there are other names ALL, LED1, etc... in scope at the switch so that the LED_References_e ones are shadowed, this should help:
I'm not 100% certain about the differences between standard C++ and Arduino C++, but you should be able to do the following:
enum LED_References_e
{
ALL = 0,
LED1 = 1,
LED2 = 2,
LED3 = 3,
LED4 = 4
};
switch (led) {
case LED_References_e::ALL: {
/* do stuff */
break;
}
case LED_References_e::LED1: {
/* do stuff */
break;
}
case LED_References_e::LED2: {
/* do stuff */
break;
}
case LED_References_e::LED3: {
/* do stuff */
break;
}
case LED_References_e::LED4: {
/* do stuff */
break;
}
default: {
break;
}
}
What this does is it tells the compiler you explicitly want LED1...LED4 from the LED_References_e enum.
If there are other LEDxes in the same scope, this should disambiguate.

Printing out selected items from an enum flag

I have the following enum (which later will grow larger!):
enum TrainingFilters {
NONE = 0,
GAUSS = 1,
SOBEL = 2,
FEATURE = 4
};
I have to print out string representation of the all possible combination. For now, a not-leangthy switch statement works fine, but if I add more items it will be disaster!
void Manager::setFilters(int filters)
{
QString what("Selected filters:");
switch (filters) {
case 0:
what.append(" NONE ");
break;
case 1:
what.append(" GAUSS ");
break;
case 1 | 2:
what.append(" GAUSS SOBEL ");
break;
case 2:
what.append(" SOBEL ");
break;
case 2 | 4:
what.append(" SOBEL FEATURE ");
break;
case 4:
what.append(" FEATURE ");
break;
case 1 | 4:
what.append(" GAUSS FEATURE ");
break;
case 1 | 2 | 4:
what.append(" GAUSS SOBEL FEATURE ");
break;
default:
qDebug() << "Invalid FILTERS enum received!";
return;
}
qDebug() << what;
mFilters = static_cast<TrainingFilters>(filters);
}
P.S: I have a few checkbox items in the user interface, and I should do some stuff according to the checked checkboxes. I use it like this:
var a, b,c;
cbGauss.checked ? a = 1 : a = 0;
cbSobel.checked ? b = 2 : b = 0;
cbFeat.checked ? c = 4 : c = 0;
cpManager.setFilters(a | b | c);
So my qustion is what is the best/easiest/smartest way to achieve this?
You could simply do
if (filters & 1)
what.append("GAUSS ");
if (filters & 2)
what.append("SOBEL ");
if (filters & 4)
what.append("FILTER ");
And so on. This way you can easily add new ones. Of course you have to check for zero and then add NONE.

How to write nested if or case to make a prompted input menu?

I'm working on an experience design project for one of my classes using a rotary phone and arduino kit to create a game based on automated phone menus. Serial input from the rotary dial is running through arduino and now I am using processing to write the menu.
I have an outline of actions and have started to code some if then statements to get going but now I have stumbled upon case and switch.
I am completely new to this but have learned a lot in class.
My question is how do I make a continuous set of nested if/then statments OR use case and switch to move through a series of prompts and inputs?
Here is my sketch so far:
import processing.serial.*;
Serial port; // Create object from Serial class
float val; // Data received from the serial port
boolean task1prompted;
boolean task1;
boolean task2;
boolean dialed;
PFont font;
void setup() {
size(800, 400);
background(0, 0, 0);
smooth();
// IMPORTANT NOTE:
// The first serial port retrieved by Serial.list()
// should be your Arduino. If not, uncomment the next
// line by deleting the // before it. Run the sketch
// again to see a list of serial ports. Then, change
// the 0 in between [ and ] to the number of the port
// that your Arduino is connected to.
//println(Serial.list());
String arduinoPort = Serial.list()[0];
port = new Serial(this, arduinoPort, 9600);
task1 = false;
task2 = false;
task1prompted = false;
font = createFont("Arial", 32);
textFont(font, 32);
textAlign(CENTER);
}
void draw() {
if (port.available() > 0) { // If data is available,
val = port.read(); // read it and store it in val
if (val >= 48 && val <= 57) {
val = map(val, 48, 57, 0, 9); // Convert the value
}
println(val);
}
if (val == 97) {
println("dialing");
}
if (val == 98){
println("dialed");
dialed = true;
}
/// switch will activate the task1 variable.
// Play sound file for the prompt.
if (task1prompted == false){
delay(1000);
println("for spanish, press one. for french, press 2...");
task1prompted = true;
}
task1 = true;
if (task1 == true && dialed == true) {
///play sound file
if (val == 5) {
println("Thank you for playing... Blah blah next prompt.");
dialed = true;
task1=false;
task2=true;
} else
if (val != 5) {
println("We're sorry, all of our international operators are busy");
task1 = true;
task2 = false;
dialed = false;
}
}
else
if (task2 == true){
delay(1000);
println("task2 start");
}
}
My instructor helped me to get this far and I have been scouring for answers on how to keep going on to the next task/prompt. Would it be easier to use case and switch? And am I even doing nested if statements the right way?
Well I just tried this out with sketch and case commands as follows:
/// Switch will activate the task1 variable.
// Play sound file for the prompt.
if (task1prompted == false){
delay(1000);
println("for spanish, press one. for french, press 2...");
task1prompted = true;
}
task1 = true;
if (task1 == true && dialed == true) {
///Play sound file
int lang = (int)(val+0);
switch(lang) {
case 1:
case 2:
case 3:
case 4:
println("sorry no international operators"); // If 1-4 go back to choices
task1 = true;
task2 = false;
dialed = false;
break;
case 5:
println("thank you, move to next prompt"); // If 5 go to next prompt
task1=false;
task2=true;
dialed = true;
break;
case 6:
case 7:
case 8:
case 9:
case 0:
println("not a valid option, you lose"); // If not 1-5 go back to beginning
task1=false;
task2=false;
dialed = true;
break;
}
if (task2prompted == false){
delay(1000);
println("please listen while we test the line");
task2prompted = true;
}
task2 = true;
if (task2 == true && dialed == true) {
} ///Play sound file
int tone = (int)(val+0);
switch(tone) {
case 1:
case 2:
case 3:
case 5:
case 6:
case 7:
case 8:
case 9:
case 0:
println("not a valid connection, you lose"); // If not 4 go back to beginning
task2 = false;
task3 = false;
dialed = false;
break;
case 4:
println("thank you, move to next prompt"); // If 4 move to next prompt
task2=false;
task3=true;
dialed = true;
break;
}
}
}
I'm still confused on how to make this have levels and not all happen simultaneously.
You might want to look up finite state machines. It's a pretty common approach to dealing with event driven user interfaces.
I'm not entirely sure what your question is but maybe something here will answer it, if not just clarify what you're looking for
With case statements you don't need to make a case for every single output that can happen. the way you can avoid doing that is by using a default statement
Example:
switch(tone) {
case 4:
println("thank you, move to next prompt"); // If 4 move to next prompt
task2=false;
task3=true;
dialed = true;
break;
default:
println("not a valid connection, you lose"); // If not 4 go back to beginning
task2 = false;
task3 = false;
dialed = false;
}
The default case doesn't need a break because it is at the end. But essentially it is the catch all case if nothing else is hit.
Also in some of your code above
if (val == 97) {
println("dialing");
}
if (val == 98){
println("dialed");
dialed = true;
}
it is better to use an "else if" to make it not have to check through both if one is correct
if (val == 97) {
println("dialing");
}
else if (val == 98){
println("dialed");
dialed = true;
}