This sketch will be used to steer a dish using servo's either manual(by keyboard) or by a program. To enable manual opperation I am looking for a 'special charracter' in this code section:
if (saByte == CTRL1 || saByte == CTRL2 ) {
// is special character sequence(1B5B41 - 1B5B44)
Serial.println("Manual enabled");
num_keypad = true;
}
if (num_keypad == true) {
switch (saByte) {
but this if (num_keypad == true) doesnt work
Total code:
/*-----( Import needed libraries )-----*/
#include <LiquidCrystal.h>
#include <HCPCA9685.h>
#define I2CAdd 0x40 // default HCPCA9685 address
/*-----( Declare objects )-----*/
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
HCPCA9685 servo(I2CAdd);
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
servo.Init(SERVO_MODE);
servo.Sleep(false);
lcd.clear();
delay(150);
// 12345678901243456
lcd.print("Start Callibrate");
refresh_output();
}
#define strMAX_LEN 12 //max. nbr characters from Xtrack
int SERVONBR = 0; // servo accessed in manual opperation
int MAXSERVO = 15; // Nbr outputs hcpca9685
int SERVOMINPOS = 110;
int SERVOMAXPOS = 590;
float SERVOPOS = (SERVOMAXPOS - SERVOMINPOS) / 2;
char saByte; // save inByte
char MESSAGE[17];
char MESGLCD[17];
char MESGTMP[6];
char STRVALUE[strMAX_LEN];
bool num_keypad = false; // becomes true after a CTRL1 or CTRL2 character
// define characters used in manual opperation
#define CTRL1 0x1B
#define CTRL2 0x5B
#define UP 0x41 // Pos+1
#define DOWN 0x42 // Pos-1
#define RIGHT 0x43 // Servo+1
#define LEFT 0x44 // Servo-1
#define PGUP 0x39 // pos+10
#define PDWN 0x33 // pos-10
void loop() {
while (Serial.available() > 0) {
char inByte = Serial.read();
saByte = inByte;
Serial.print("Received 0x");
Serial.println(saByte, HEX);
if (saByte == CTRL1 || saByte == CTRL2 ) {
// is special character sequence(1B5B41 - 1B5B44)
Serial.println("Manual enabled");
num_keypad = true;
}
if (num_keypad == true) {
switch (saByte) {
case UP:
SERVOPOS++;
if (SERVOPOS > SERVOMAXPOS) {
SERVOPOS = SERVOMINPOS;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
num_keypad = false;
break;
case PGUP:
SERVOPOS += 10;
if (SERVOPOS > SERVOMAXPOS) {
SERVOPOS = SERVOMINPOS;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
num_keypad = false;
break;
case DOWN:
SERVOPOS--;
if (SERVOPOS < SERVOMINPOS) {
SERVOPOS = SERVOMAXPOS;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
num_keypad = false;
break;
case PDWN:
SERVOPOS -= 10;
if (SERVOPOS < SERVOMINPOS) {
SERVOPOS = SERVOMAXPOS;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
num_keypad = false;
break;
case RIGHT:
SERVONBR++;
if (SERVONBR > MAXSERVO) {
SERVONBR = 0;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
num_keypad = false;
break;
case LEFT:
SERVONBR--;
if (SERVONBR < 0) {
SERVONBR = MAXSERVO;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
num_keypad = false;
break;
default:
// Serial.print("Not decoded: 0x");
// Serial.println(saByte, HEX);
num_keypad = false;
break;
}// end switch
}
// Run this in 'normal' opperation mode
// receiving a command sequence eg. 123.4,123.5\n
if (!num_keypad == false && saByte == ',' || saByte == '.' || saByte >= '0' && saByte <= '9') {
Serial.println("proccess command sequence");
Serial.print("Received 0x");
Serial.println(saByte, HEX);
}
}// end while
}// end loop
void refresh_output() {
dtostrf(SERVOPOS, 3, 1, MESGTMP);
sprintf(MESSAGE, "S: %-2d P: %s \0", SERVONBR, MESGTMP);
Serial.println(MESSAGE);
lcd.setCursor(0, 1);
lcd.println(MESSAGE);
}
void refresh_servo(int srv, int pos) {
// servo.Servo(srv, pos);
}
void makePosition() {
Serial.print("Nbr decoded: 0x");
Serial.println(saByte, HEX);
}
It looks like the only place you turn on 'num_keypad' is when saByte is CTRL1 or CTRL2. You then drop into "switch (saByte)" because num_keypad is true. There is no case in that switch for CTRL1 or CTRL2 so the 'default' case is used. The default is "num_keypad = false;".
One fix would be to have do-nothing cases for CTRL1 and CTRL2:
You test the following condition saByte == CTRL1 || saByte == CTRL2 and if true you set num_keypad to true. Then in the following conditional you test num_keypad == true and if so you have a switch (saByte) in which you could not possibly match any of the cases except default since that conditional would only be entered if saByte is equal to CTRL1 or CTRL2.
Hi @gharryh, I was thinking about your code structure last night and your original loop() function would work quite well with the following simple mods:
Replace while with if and let loop() do the looping
Use else if instead of sequential if statements. This will solve the problem of unnecessarily executing the switch right after setting the num_keypad flag.
inByte is not needed
In the num_keypad == true block in all cases you set num_keypad = false. I removed it from all cases and set it one time in the code block.
Untested but it should work.
void loop() {
if (Serial.available() > 0) {
saByte = Serial.read();
Serial.print("Received 0x");
Serial.println(saByte, HEX);
if (saByte == CTRL1 || saByte == CTRL2 ) {
// is special character sequence(1B5B41 - 1B5B44)
Serial.println("Manual enabled");
num_keypad = true;
}
else if (num_keypad) {
switch (saByte) {
case UP:
SERVOPOS++;
if (SERVOPOS > SERVOMAXPOS) {
SERVOPOS = SERVOMINPOS;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
break;
case PGUP:
SERVOPOS += 10;
if (SERVOPOS > SERVOMAXPOS) {
SERVOPOS = SERVOMINPOS;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
break;
case DOWN:
SERVOPOS--;
if (SERVOPOS < SERVOMINPOS) {
SERVOPOS = SERVOMAXPOS;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
break;
case PDWN:
SERVOPOS -= 10;
if (SERVOPOS < SERVOMINPOS) {
SERVOPOS = SERVOMAXPOS;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
break;
case RIGHT:
SERVONBR++;
if (SERVONBR > MAXSERVO) {
SERVONBR = 0;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
break;
case LEFT:
SERVONBR--;
if (SERVONBR < 0) {
SERVONBR = MAXSERVO;
}
refresh_output();
refresh_servo(SERVONBR, SERVOPOS);
break;
default:
// Serial.print("Not decoded: 0x");
// Serial.println(saByte, HEX);
break;
}// end switch
num_keypad = false;
}
// Run this in 'normal' opperation mode
// receiving a command sequence eg. 123.4,123.5\n
else if (saByte == ',' || saByte == '.' || saByte >= '0' && saByte <= '9') {
Serial.println("proccess command sequence");
Serial.print("Received 0x");
Serial.println(saByte, HEX);
}
}// end if
}// end loop