Serial setup input parameters

Complete novice here. After 40 years in IT, time to actually code something. The project is a distributor simulator for testing ignition amplifiers. Basically, I want to be able to generate a pulse stream with a specific on and off time. Easy enough. Got that working as my first scheme, but with embedded parameters. I want to be able to set the parameters from the Serial Console. I got a couple schemes working for reading the USP port.

Here is where I get stuck. Both functions work within loop(). What approach will let me input two parameters through the console using one loop, then switch to a loop that generates the pulse stream. Unlike some of the signal generator projects out there, I need to enter specific exact values, not just use a couple of pots. I only need it to run once, as I can use the NMI button when I want to enter new values.

Yes, I could stack them both in one loop, poll the port, generate a pulse, poll, etc. Not the way to get the precision needed. I found the scheduler library, but not sure that is what I am looking for.

In other words, run one loop() to get the parameters, break out and run the generator loop() until I either hit NMR or maybe add a button on a interrupt.

What approach is recommended?

Go to Google and search for "Ardustim". It is a sketch specifically made for this purpose. It will output crank and cam signals at the same time. Also has a GUI which makes setup a lot easier.

I see he did this in real C, not Arduino. That may be a big hint.
I know how many digits I will accept, so if I make the input two digits for dwell and four for rpm requires, I can parse the string to get both parameters and use the /n as the trigger to exit the loop. That is the issue' how to get out of one loop and into another. I can do one or the other, not one and then the other.

const int ledPin = 10;
int param1 = 0;
int param2 = 0;
void test() {
  while (1) {
    analogWrite(ledPin, param1);
    delay(1000);
    analogWrite(ledPin, param2);
    delay(1000);
  }
}
void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  analogWrite(ledPin, 0);
}
void loop() {
  while (Serial.available() > 0) {
    param1 = Serial.parseInt();
    param2 = Serial.parseInt();
    test();
  }
}

You may find something useful in Serial Input Basics - simple reliable ways to receive data. There is also a parse example.

Also have a look at Planning and Implementing a Program which illustrates multiple activities alongside the serial input.

...R

Here is what I came up with so far. I am trying to get the Vertronix simulator to work as it lets me single step. Not sure it is working correctly with the serial monitor. Yes, I used that ugly "goto". 40 years ago when I took half a semester of FORTRAN, it was not looked down upon. :slight_smile:

Again, the goal is to get initialization parameter from the serial port, then move to the loop() to do the outputting. Just reading the serial port in the loop() is not the problem.
This seems to work logically, but does not capture the serial.

/*Capture serial input in setup. Then exit to loop().
Idea is to look for serial input until it gets a new line,
print the string and then break which should exit to loop()
*/
//Global
String inString = ""; //set string to null

void setup() {
Serial.begin (9600);
while (!Serial) {
}
; //wait for serial to connect

Serial.println ("Key input in setup"); // print welcome
Tag:
while (Serial.available()>0) {
int inChar = Serial.read();
if (isDigit (inChar)) {
inString += (char) inChar;
}
if (inChar == '\n') {
Serial.print ("Entered : ");
Serial.println (inString);

break;
}
}
else {
goto Tag;
}
}
}

void loop() {
// put your main code here, to run repeatedly:
Serial.println ("Woo_Woo"); //show I exited
delay (3000);
}

tvrgeek:
Again, the goal is to get initialization parameter from the serial port, then move to the loop() to do the outputting. Just reading the serial port in the loop() is not the problem.

There is no need to get the initialization data within setup(). It could be more easily done in loop() where you can take account of the ordinary repetition. Just have a variable that gets set when the initialization completes. The rest of your program will know not to do anything until that variable is set.

Have you looked at the user input part of Planning and Implementing a Program?

Your use of GOTO in your example should not present any problem because it is all happening within the setup() function. When people use it to jump between functions it can cause problems. However you can get the same effect using WHILE without any need for GOTO and the code will probably be easier to understand and to debug. Perhaps something like

int inChar;
while (inChar != '\n') {
  if (Serial.avaliable > 0) {
     inChar = Serial.read();
     // etc
  }
}

but while that sort of blocking code is OK in setup() if you really want nothing else to happen, it is not appropriate more generally when serial input must happen alongside other activities.

...R

The implementing a program thread is quite useful. The books I have found all are about how to hook up led's and just copy code. The process of coding has changed since I was in school. ( flow charts and coding forms, keypunch). I watch my guys at work. I give them a simple needs statement and out comes horribly complex and thought out systems.

Some reading. Good tips. More coffee and back at it!

I don't mind blocking code. Actually, it is good as I don't want the eventual pulse stream to do anything until it has a valid parameter. The flow is: Get parameters, then do something endlessly until NMI. Lots of little things to do in between as I need to do some floating point math and take into account the system timing, but that is the kind of detail I can work out. I was looking to avoid polling the serial in the same loop as the "do something" as it makes the critical timing more difficult. The reliability of the timing is why I don't just read a couple of pots, though by displaying their value, they might be stable enough if I use precision 10 turn pots, each of which costs several times the price of a Uno!

The flag idea sounds good, as that test timing will be consistent.

Random thought while getting a refill: I bet someone has done the code to replace a processor in a Kureg.

Sort of got it working but really ugly. Timing is unknown, but it basically runs. Strange how it prints the serial input multiple times. So it is not what I really want, but will do for now.

/* Pulse generator to simulate ignition igniter output for coil testing

  • Take input of dwell and RPM as a single 6 digit string
  • Parse into separate parameters
  • Do timing modifications
  • Print both the input dwell and RPM as well as the calculated mS pulse width
  • Output pulse of known up and down times on pin 13 to external buffer amplifier
  • TVRGEEK Code public if you are fool enough to copy it.
    */
    //Global
    String inString = "";
    int upTime =0;
    int downTime = 0;
    int gotParam = 0;

void setup() {
Serial.begin (9600);
while (!Serial) {
}
; //wait for serial to connect

Serial.println ("Enter 6 digits, two for dwell and four for RPM"); // print welcome
}

void loop() {

String GetParameters (); // wind up with inString containing setup parameters

int inChar = ""; // put it in it's own loop
if (gotParam == 0) {
while (inChar != '\n') {
if (Serial.available() >0) {
inChar = Serial.read();
if (isDigit (inChar)) {
inString += (char) inChar;
}
}
if (inString !=""){ // don;t endlessly print "Entered"
Serial.print ("Entered : ");
Serial.println (inString);
gotParam ++;
}
}
}
void CalculateValues(); { // parse inString and calculate upTime and downTime;
if (inString !=""){
Serial.print ("made it to calc with:");
Serial.println (inString);
inString = "";
} // clear the string for next input. Dont' care if this is null as I;ll have the actual time values saved
delay (2000);
}

void GeneratePulse(); { // output on pin 13
Serial.println ("made it to generate");
delay (2000);
}
}

Success. Backed up to basics. Lot's more reading. So, I get my two parameters before I go to loop().
Found out a few details on the built in and hidden main(). Some of the documentation sure is thin.

/*Capture serial input in setup. Then exit to loop().
Idea is to look for serial input until it gets a new line.
tvrgeek Code public if you dare.

*/
//Global

int upTime =0;
int downTime = 0;
int gotParam = 0;
int inDwell = 0;
int inRPM = 0;

void setup() {
Serial.begin (9600);
delay (2000);

Serial.println ("Enter 6 digits, comma seperated. Two for dwell and four for RPM"); // print instructions

while (gotParam ==0) {
inDwell = Serial.parseInt(); //parse the first intiger up to a comma
inRPM = Serial.parseInt();
if (Serial.read() == '\n') { // Exit after new line
gotParam ++; // update the flag ( yea, should change toa boolean)
Serial.print ("Dwell: "); // Print for verification
Serial.println (inDwell);
Serial.print ("RPM: ");
Serial.println (inRPM);
}
}
}

void loop() {
// put your main code here, to run repeatedly:
Serial.println ("Woo_Woo"); //show I exited to loop()
delay (3000);
}