Go Down

Topic: Freq Generator Not Reaching Required Freq & Continuing At That Freq (Read 439 times) previous topic - next topic

George-Mathieson

Jun 18, 2019, 07:20 pm Last Edit: Jun 18, 2019, 07:47 pm by George-Mathieson Reason: (I forgot to add some information)
Hi!

I have an Uno board with a motor control shield. I am using the Arduino IDE 1.8.9. Each of the four motor outputs has an LED connected for prototyping reasons. My hardware arrangement is completely deliberate, so nothing much will be changed with that. The LEDs blink in sequence to create an almost circular pattern, and I was able to make the sequence accelerate gradually using delays and pre-set variables. What I would like to do, is have the user input the Hertz that they want to produce using the serial monitor with a float input. The program should divide 1 by that input to create the time delay value for the sequence. For some reason, I can't figure out why the time delay doesn't stop at the frequency that the user has requested. Instead, it continues to accelerate until the time delay is 0. At one point, the time delay eventually went past 0, and into negative numbers. What should happen is: it should accelerate until the frequency that the user has requested, and then continue to run at that frequency forever (unless the power is cut of course). The result I am looking for is: the user inputs a frequency for the sequence, the sequence starts at a preset value of maybe 500ms, the speed of the sequence increases until the frequency of the sequence matches what the user requested, the sequence then continues at this frequency forever. I need this code to run as efficiently as possible by the way, and it needs to be able to run upto really high frequencies (and the frequency needs to be to at least 2 decimal places). Sorry about the ameature approach with this code. This is my first time doing anything like this, and I am learning as I go along. I've definately thrown myself in the deep end.

This is my first post on a forum, so I am not completely familiar with how to format this topic. For that reason, I've just attached the code below as well.

Any help is greatly appreciated.

Code: [Select]

#include <AFMotor.h>
AF_DCMotor A(1);
AF_DCMotor B(2);
AF_DCMotor C(3);
AF_DCMotor D(4);
float timer;
float userTimer;
float accelleration;
float spd;
float userInput;

//float spd = Serial.read();

void setup()
{
  Serial.begin(9600);
  spd = Serial.println("Please Enter Speed (Hz)");
  spd = Serial.read();
  userTimer = (1 / (spd));
  accelleration = (0.0001);
  timer = (1);
  A.setSpeed(255);
  B.setSpeed(255);
  C.setSpeed(255);
  D.setSpeed(255);
}

void loop()
{
  if (Serial.available())
  {
    if (timer > userTimer)
    {
      Serial.print(timer);
      Serial.print('\n');
      timer = timer - accelleration;
        A.run(FORWARD);
          delay(timer);
        A.run(BACKWARD);
      Serial.print(timer);
      Serial.print('\n');
      timer = timer - accelleration;
        B.run(FORWARD);
          delay(timer);
        B.run(BACKWARD);
      Serial.print(timer);
      Serial.print('\n');
      timer = timer - accelleration;
        C.run(FORWARD);
         delay(timer);
        C.run(BACKWARD);
      Serial.print(timer);
      Serial.print('\n');
      timer = timer - accelleration;
        D.run(FORWARD);
          delay(timer);
        D.run(BACKWARD);
    }
    else if (timer <= userTimer)
    {
      Serial.print(userTimer);
      Serial.print('\n');
        A.run(FORWARD);
          delay(userTimer);
        A.run(BACKWARD);
      Serial.print(userTimer);
      Serial.print('\n');
        B.run(FORWARD);
          delay(userTimer);
        B.run(BACKWARD);
      Serial.print(userTimer);
      Serial.print('\n');
        C.run(FORWARD);
          delay(userTimer);
        C.run(BACKWARD);
      Serial.print(userTimer);
      Serial.print('\n');
        D.run(FORWARD);
          delay(userTimer);
        D.run(BACKWARD);
    }
    else
    {
      Serial.print(userTimer);
      Serial.print('\n');
        A.run(FORWARD);
          delay(userTimer);
        A.run(BACKWARD);
      Serial.print(userTimer);
      Serial.print('\n');
        B.run(FORWARD);
          delay(userTimer);
        B.run(BACKWARD);
      Serial.print(userTimer);
      Serial.print('\n');
        C.run(FORWARD);
          delay(userTimer);
        C.run(BACKWARD);
      Serial.print(userTimer);
      Serial.print('\n');
        D.run(FORWARD);
          delay(userTimer);
        D.run(BACKWARD);
    }
  }
}

UKHeliBob

Code: [Select]
 spd = Serial.read();
Reads 1 byte from the Serial monitor.  Have you tried printing spd to ensure that it is the value that you expect ?

Why does all of the code in loop() depend on serial data being available even though you never read it ?

What have you got the line ending set to in the Serial monitor, bearing in mind that your code only ever reads 1 byte ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

George-Mathieson

I do apologise, the code isnt working at all suddenly. The error message im recieving is:




Arduino: 1.8.9 (Mac OS X), Board: "Arduino/Genuino Uno"

*location*: In function 'void setup()':
Code1:16:6: error: redefinition of 'void setup()'
 void setup()
      ^
*location*:16:6: note: 'void setup()' previously defined here
 void setup()
      ^
*location*: In function 'void loop()':
Code1:39:6: error: redefinition of 'void loop()'
 void loop()
      ^
*location*:30:6: note: 'void loop()' previously defined here
 void loop()
      ^
exit status 1
redefinition of 'void setup()'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.




I can' t check spd until this is now fixed. I expect spd will not give what I expected. I thought that the single character from serial will be one of the problems. The reason I used serial available to start the loop, is to see if that was a problem. I thought maybe it is because I might be sending data before serial is available (this can't do any harm though right?). I haven't set a line ending for the serial. If the serial is such a problem, is there any easier way of inputting a value to the Arduino whilst it is running?

UKHeliBob

My guess would be that you have code in 2 tabs in the IDE unless you really do have 2 loop() and setup() functions in your sketch
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

George-Mathieson

So what would I have in each tab if I was to try that? Also, what would the benefit be? And will they both run at the same time (will that decrease the reliability/ speed of it, or will one run before the other?)

AWOL

The compiler is telling that you cannot have two setups and two loops, so how they might perform is moot.
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

George-Mathieson

Why does it think that I have two setups & two loops? There's only one as far as I can see. Also, is there any simple way of reading a multiple digit float from serial?

AWOL

The compiler can see two.
That's why it is bitching.

I can't see any.
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

UKHeliBob

Why does it think that I have two setups & two loops? There's only one as far as I can see. Also, is there any simple way of reading a multiple digit float from serial?
How many tabs have you got open in the IDE ?

Search for loop in the IDE and click "Search all Sketch Tabs" in the find dialogue.  How many does it find and where are they ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

George-Mathieson

Right, so I was rather daft. There were indeed two tabs open (both running the exact same code). That error is now gone, but the other problems still occur of course. When I ask it to print spd in serial, it prints the value "-1.0" before I have even inputted a value. I assume it is taking that value from the "P" in "Please Enter Speed (Hertz)". Any ideas?

I should be able to enter the value "2" (this should now be spd) into the serial monitor, and it should divide 1 by 2 to make 0.5 (that should now be the value of userTimer in seconds). To print the value of spd, I added this to line 26 (in the setup void):

Code: [Select]

Serial.println(spd);

George-Mathieson

I've just read - on another Arduino topic - that a union structure should be used to read multiple bytes of data from a serial input. It apparently combines the serial data into a single integer (I assume I would be able to turn it into a float as well). What I would really like, is for the user to input a float such as 44.7 (Hz) for the Arduino to convert into the time delay. That should then make the 4 LED sequence run at 44.7Hz. Do you know anything about a union structure because he didn' go into much detail on the one that I have just read. Google doesn't seem to find any relevant and easier to understand results either. I believe that if I sort out the serial input, the spd should correct itself. If possible, I wouldn't want any serial end character (for ease of use). The user should just be able to input a float and hit enter.

AWOL

You can't use a union to convert ASCII input like "44.7" to the equivalent float.

That approach is a dead-end.

Quote
I wouldn't want any serial end character (for ease of use). The user should just be able to input a float and hit enter.
In which case, the "enter" is the "serial end character"
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

George-Mathieson

Of course! I'll use the enter key as the serial end. Could you send me some example code for me to implement to mine using this, please?

UKHeliBob

Quote
When I ask it to print spd in serial, it prints the value "-1.0" before I have even inputted a value.
Here is your setup() function
Code: [Select]

void setup()
{
  Serial.begin(9600);
  spd = Serial.println("Please Enter Speed (Hz)");
  spd = Serial.read();
  userTimer = (1 / (spd));
  accelleration = (0.0001);
  timer = (1);
  A.setSpeed(255);
  B.setSpeed(255);
  C.setSpeed(255);
  D.setSpeed(255);
}

The Serial.read() will occur within microseconds of the program starting and there will, therefore, be no opportunity for the user to enter a value.  When there is nothing available to read then Serial.read() returns -1, which is what you are seeing.

One way way to get round this is to do something like this in setup()
Code: [Select]

while (Serial.available() == 0);  //wait for serial input
spd = Serial.read();
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

George-Mathieson

Ah, Perfect! So that would be at the start of my void loop, then when an input is entered, the if loops start?

Go Up