I need a function which returns the number of pulses during a specified time, on arduino.This is the partial code I'm using, but the function isn't retuning anything ( isn't returning even 0 )
...
long Itime = 0;
int Dtime = 25;
...
int Counter() {
unsigned long Ftime = millis();
int c = 0;
int i = 0;
while ( Ftime - Itime < Dtime ) {
if ( digitalRead(PSPin) == HIGH ) {
i=i+1;
while ( digitalRead(PSPin) == HIGH) { // delays the function until
c=c+1; // the next cycle
c=c-1;
}
}
}
Itime = Ftime;
return i;
}
I really don't understand why the function isn't returning 'i'.I'd be happy if someone could help.Thanks
edit:
The signal on PSPin is a 150hz square signal, which means that the period is approximately 6ms, and since my time is 25ms it should return at least 3 pulses..
I called this function for testing purposes only, since I also think my program gets stuck on the Counter() function, but I can't figure out why.
void loop() {
if ( Counter() == 0 )
digitalWrite(TestPinA, HIGH);
if ( Counter() > 0 )
digitalWrite(TestPinB, HIGH);
}
But both pins never return HIGH.
I really appreciate your help.
You are stuck in the
while ( Ftime - Itime < Dtime )
as the code never actually update either of Ftime or Dtime, while in the WHILE loop. Try the following:
int PSPin = 13;
int DurationTime = 25; // best to have same type as compare or cast it later, below.
int Counter() {
int i = 0;
unsigned long StartTime = millis();
unsigned long PrvTime = StartTime ;
while ( PrvTime - StartTime < (unsigned long) DurationTime ) {
if ( digitalRead(PSPin) == HIGH ) {
i=i+1;
while ( digitalRead(PSPin) == HIGH); // BLOCK the function until cycles
}
PrvTime = millis();
}
return i;
}
Use Interrupts to make the work easy.
volatile int IRQcount;
int pin = 2;
int pin_irq = 0; //IRQ that matches to pin 2
void setup() {
// put your setup code here, to run once:
attachInterrupt(pin_irq, IRQcounter, RISING);
delay(25);
detachInterrupt(pin);
Serial.print(F("Counted = ");
Serial.println(IRQcount);
}
void IRQcounter() {
IRQcount++;
}
void loop() {
// put your main code here, to run repeatedly:
}
And if you wanted to use a pin other than INT0/1. You can use PinChangeInt Libray to use any pin.
Related
I have effectively replicated the "no delay blink" example on my Arduino Mega2560 to send pulses to a stepper motor driver. I included a for loop to increment the number of "pulses" given to achieve a single rotation (800 pulses), then delay for a moment and repeat.
I find that the motor is only rotating a fraction of a revolution. It would seem that the micros() running faster than the for loop resulting in missed pulses. I would greatly appreciate if someone could point out why this may be, and how to work around it.
#include <Wire.h>
const int Pul_OUT = 9;
unsigned long previousMicros = 0;
unsigned long Pul_Interval = 100;
int setPosition = 800;
void setup()
{
pinMode(Pul_OUT, OUTPUT);
digitalWrite(Pul_OUT, LOW);
}
void loop()
{
no_delay_Position();
delay(100);
}
int no_delay_Position()
{
for (int i = setPosition; i >= 0 ; i--)
{
unsigned long currentMicros = micros();
if (currentMicros - previousMicros > Pul_Interval)
{
previousMicros = currentMicros;
PulState = !PulState;
digitalWrite(Pul_OUT, PulState);
}
}
}
delay() is measured in milliseconds, microseconds are just a fraction of this.
From the micros() reference:
There are 1,000 microseconds in a millisecond and 1,000,000
microseconds in a second.
Adding the delay(100) in your main loop will also stop the arduino from doing most things. If for some reason you need to use millis() in the outer loop and micros() in the set position loop you could do something like this
#include <Wire.h>
const int Pul_OUT = 9;
unsigned long previousMicros = 0;
unsigned long previousMillis = 0;
int Pul_Interval = 100;
int Main_Interval = 100;
int setPosition = 800;
void setup()
{
pinMode(Pul_OUT, OUTPUT);
digitalWrite(Pul_OUT, LOW);
}
void loop()
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > Main_Interval)
{
previousMillis = currentMillis;
no_delay_Position();
}
}
void no_delay_Position()
{
for(int i = setPosition; i >= 0 ; i--)
{
unsigned long currentMicros = micros();
if (currentMicros - previousMicros > Pul_Interval)
{
previousMicros = currentMicros;
PulState = !PulState;
digitalWrite(Pul_OUT, PulState);
}
}
}
The call to no_delay_Position() looks to be set to return an int did you mean to be able to pass in an integer to set the position?
void loop()
{
no_delay_Position(500);
}
void no_delay_Position(int setP)
{
setPosition = setP;
for(int i = setPosition; i >= 0 ; i--)
{
//rest of your code
}
}
Your for loop in no_delay_Position() will decrement i whether a pulse is sent or not (because that is determined by Pul_interval), so i will reach 0 before i pulses are sent.
Also, no_delay_Position() will not return until its for loop is done, and during that time, loop() is blocked.
Also, your Pul_Interval is only 100µs which is 0.1ms. You may want to replace micros() with millis() and see what happens.
BTW 100ms is still fairly quick for pulsing a stepper motor, you could try a larger Pul_Interval if the above is still too fast. There's nothing wrong with testing with a step every second or so, just to see if the algorithm works as expected.
I needed to make a meters counter for a work thing, so I decided to just Arduino for it. I found an old encoder, found/wrote a simple code and hacked it all together and encountered a unexpected problem.
For some reason my counter won't count past around 8 meters or 31991 encoder pulses. Once it reaches this 8m limit, the number turns negative and starts counting backwards like -7.9 > -7.8 (i.e. continues counting upward towards 0).
Then it reaches zero and again counts to 8...
This is very strange to me and my limited coding knowledge can't fix it.
Does anyone know how to fix this or what I could do to make it work?
#include <LiquidCrystal.h>
#define inputA_in 6
#define inputB_in 7
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int inputA_V = 0;
int inputB_V = 0;
int inputA = 0;
int inputB = 0;
int counter = 0;
// smeni vrednost tuka pred run
int console_frequency_milliseconds = 200; /// edna sekunda
int aLastState = 0;
int bLastState = 0;
float meters = 0.0;
unsigned long lasttime = 0;
int move_positive = 0;
int move_negative = 0;
int maximum_input_digital_v = 300; //treba da citash od konzola i da gi setirash max i min
int minimum_input_digital_v = 0;
int logical_threshold_v = 150; //brojkive se random staveni
void setup() {
pinMode (inputA_in, INPUT);
pinMode (inputB_in, INPUT);
Serial.begin (9600);
lcd.begin(16, 2);
// Print a message to the LCD
lcd.print("Metraza [m]");
aLastState = inputA;
bLastState = inputB;
lasttime = 0;
}
void loop () {
inputA = digitalRead(inputA_in);
if (inputA != aLastState) {
if (digitalRead(inputB_in) != inputA) {
counter ++;
aLastState = inputA;
} else {
counter --;
aLastState = inputA;
}
}
if (millis() - console_frequency_milliseconds > lasttime)//Detect once every 150ms
{
meters = 0.50014 * counter / 2000;
Serial.print("Position: ");
Serial.println(meters);
lasttime = millis();
lcd.setCursor(0, 1);
//Print a message to second line of LCD
lcd.print(meters);
}
}
Your counter is a simple int,
int counter = 0;
It seems that on your system they are only 16bit wide (with a maximum value of 32767), not surprising.
Use
long int counter = 0;
to get wider variables.
You might also want to change the calculation from
meters = 0.50014 * counter / 2000;
to
meters = 0.50014 * counter / 2000.0;
to avoid losing precision and range. Even with an int that would extend your range from 31991 encoder pulses to 32757 encoder pulses; and analog for the wider range.
You might also like to try changing the counter to an unsigned int or unsigned long int. I did not analyse your whole code, but I think you do not have anything which relies on representation of negative numbers. So you probably could double the range again. But no guarantees, subject to testing.
I need a little help trying to make a timer a little fuzzy. I want to use a fixed interval of timing like this:
____|_______|____|_____|_________|_____|___|_______|
where the pipe is the event occurrence and the underscore is the delay in an array like this:
int myIntervals = { 1000, 2000, 750, 850, 1200, 850, 500, 1000};
but the values are arbitrary.
I would like to create a slight randomness to the event, but not allow the randomness to affect the overall timing:
___*|*_____*|*__*|*___*|*_______*|*___*|*_*|*_____*|
where the randomness is described as the time contained by asterisks.
So the event always happens at the interval +- a random delay:
int fuzzyPeriod = random(-75, 75);
I've experimented around this but to no avail... I'm finding myself in a recursion when the fuzzy period is negative, or like this I get a millis() overflow problem, obviously.
int sequence[] = {1000, 750, 950, 1150, 1200, 1500, 1000, 1900, 2000};
unsigned int index;
unsigned long startMillis = 0;
unsigned int fuzzy = sequence[0];
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop()
{
if (startMillis < millis()) // will have rollover issues <<<<<<<
{
if (millis() - startMillis >= fuzzy)
{
digitalWrite(13, !digitalRead(13));
startMillis += sequence[index]; // advance startMillis by the last interval used
index++;
if (index >= sizeof(sequence) / sizeof(sequence[0]))
{
index = 0;
Serial.println("Restarted Sequence");
}
fuzzy = sequence[index] + random(-75, 76); // arbitrary offset needs to be positive or negative
Serial.print("fuzzy = ");
Serial.println(fuzzy);
}
}
}
I hope I've done a good job explaining... I cannot for the life of me get this done and I know I'm to the point where I need a little help!
Something like this:
unsigned int index;
unsigned long nextMillis;
int prevFuzzy = 0;
int fuzzy = 0;
void setup()
{
//...
nextMillis = millis();
}
void loop()
{
if (millis() >= nextMillis)
{
fuzzy = random(-75, 76);
// compensate for previous deviation and add new one
nextMillis += sequence[index] - prevFuzzy + fuzzy;
fuzzy = prevFuzzy;
// or just:
// fuzzy = random(-75, 76) - fuzzy
// nextMillis += sequence[index] + fuzzy;
index++;
if (index >= sizeof(sequence) / sizeof(sequence[0]))
{
index = 0;
}
// Do stuff
}
}
First you have to use unsigned long for milliseconds to properly account for the overflow.
Then I also initialized the variables at different places and startMillis with a different value
int sequence[] = {1000, 750, 950, 1150, 1200, 1500, 1000, 1900, 2000};
unsigned int index = 0;
unsigned long startMillis;
unsigned int fuzzy = sequence[0] + random(-75, 76);
#include <limits.h>
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
randomSeed(analogRead(0));
startMillis = millis();
}
void loop()
{
long MilliDiff;
if (startMillis <= millis())
MilliDiff = millis() - startMillis;
else
MilliDiff = ULONG_MAX - startMillis + millis();
if (MilliDiff >= fuzzy)
{
digitalWrite(13, !digitalRead(13));
startMillis += sequence[index]; // advance startMillis by the last interval used
index++;
if (index >= sizeof(sequence) / sizeof(sequence[0]))
{
index = 0;
Serial.println("Restarted Sequence");
}
fuzzy = sequence[index] + random(-75, 76); // arbitrary offset needs to be positive or negative
Serial.print("startMillis = ");
Serial.print(startMillis);
Serial.print(", sequence = ");
Serial.print(sequence[index]);
Serial.print(", fuzzy = ");
Serial.println(fuzzy);
}
}
This code seems to be working on my Uno
I wrote this code and I don't know what to do to change that. This code I want to use in my Raspberry pi with sonars - hc sr 04 to measure a distance. Please do you know how to fix my code? :) before this I wrote a code for-example. This is my real code. So please check it again :) thanks!
int zmeratSonar1() {
int smer = 0;
printf("meram sonar1");
digitalWrite(TRIGsonar1, HIGH);
delayMicroseconds(20);
digitalWrite(TRIGsonar1, LOW);
while (digitalRead(ECHOsonar1)==LOW);
long zaciatok = micros();
while (digitalRead(ECHOsonar1)==HIGH);
long cas = micros() - zaciatok;
int vzdialenost = cas/58;
if(vzdialenost < 100) {
smer = zmeratSonar28(); // <----here is my problem
}
else if(vzdialenost > 100) {
zmeratSonar1();
}
return smer;
}
int zmeratSonar28(){
int smer = 0;
printf("meram sonare 2 a 8");
//------------SONAR 2---------------------
digitalWrite(TRIGsonar2, HIGH);
delayMicroseconds(20);
digitalWrite(TRIGsonar2, LOW);
while (digitalRead(ECHOsonar2)==LOW);
long startTime2 = micros();
while (digitalRead(ECHOsonar2)==HIGH);
long travelTime2 = micros() - startTime2;
int distance2 = travelTime2/58;
//------------SONAR 8----------------------
digitalWrite(TRIGsonar8, HIGH);
delayMicroseconds(20);
digitalWrite(TRIGsonar8, LOW);
while (digitalRead(ECHOsonar8)==LOW);
long startTime8 = micros();
while (digitalRead(ECHOsonar8)==HIGH);
long travelTime8 = micros() - startTime8;
int distance8 = travelTime8/58;
//porovnanie vzdialenosti
if(distance2 > 100 || distance8 > 100) {
if(distance2 > distance8) {
smer = 2;
}
else {
smer = 8;
}
}
else{
smer = 0;
}
return smer;
}
You are using the function sum before you have declared it. You could either move the function sum above the use, or you could forward declare it:
int sum(); // Forward declared
int number = 0;
int a() {
for(int i = 0; i < 20; i++) {
if((i % 2) == 1) {
number = sum();
}
}
return number;
}
int sum() {
number = number + 100;
return number;
}
Further explanation of the this problem, can be found elsewhere on Stack Overflow, such as the answers to this question: Why do functions need to be declared before they are used?
Note: I never thoroughly tested your code, which I guess you never did either, so as LogicStuff pointed out it didn't even compile, I've made a few changes to make the code compile, as few changes as possible so that the original code should still be visible from it. Thanks for pointing it out LogicStuff.
I suppose your problem is that you have a compilation error. You use sum in place where it is not yet visible. Either move sum above a(), or forward declare it with int sum(); above a().
Another problem is that:
if(i % 2 = 1) {
should be:
if((i % 2) == 1) {
^~~~~ !!
Whoo, I found third problem :)
You try to use variable number inside int sum() which is declared inside of a(), you simply cannot do it. You should pass number to sum by reference (no need for return value, you return it in number parameter):
void sum(int& number) {
and call it:
sum(number); // this is in place of `number = sum();`
in a()
There are a number of errors in your code which will cause compiler errors:
If you're using the sum() function in int a(), then you need to forward-declare it.
int sum();
int add() {
//
}
int sum() {
//
}
All sum() really does however, is add 100 to a variable. This can be incorporated into the add() function very easily via the += operator, meaning your code is equivalent to this:
int a() {
int number = 0; //Added a necessary ';'
for(int i = 0; i < 20; i++) {
if(i % 2 == 1) { //Corrected this from if(i % 2 = 1)
number += 100; //No need for the sum() function
}
}
return number;
}
The crucial aspect:
There are a lot of additional optimizations you could perform on your setup; Essentially, int a() could be simplified to
int a() {
return 1000;
}
So, you could just as easily not have a() be a function at all:
#define a() 1000
Or, (probably better):
const int a = 1000;
EDIT :
For your updated code you need to write int zmeratSonar28(); before int zmeratSonar1() starts:
int zmeratSonar28();
int zmeratSonar1() {
//Sonar code stuff
}
int zmeratSonar28() {
//Other sonar code stuff
}
I would like to know how to stop music with a push button (to stop it exactly at the moment you press the button). Because at the moment my code does what I want(stop the music and turn on a light when I press the press button, but it waits untill the end of the song to stop.
There is my code:
int buttonState = 0;
int speakerOut = 10;
int buttonPin= 7;
int frequency = 500;
int ledPin = 13;
int length = 17; // the number of notes
char notes[] = "gcefgcefgcefgcefga "; // a space represents a rest
//int beats[] = {2,2,1,1,2,2,1,1,2,2,1,1,2,2,1,1};
//int tempo = 250;
int DEBUG = 1;
#define c 3830
#define d 3400
#define e 3038
#define f 2864
#define g 2550
#define a 2272
#define b 2028
#define C 1912
#define R 0
void setup() {
// put your setup code here, to run once:
pinMode(ledPin, OUTPUT);
pinMode(buttonPin,INPUT);
pinMode(speakerOut, OUTPUT);
if (DEBUG) {
Serial.begin(9600); // Set serial out if we want debugging
}
}
// MELODY and TIMING =======================================
// melody[] is an array of notes, accompanied by beats[],
// which sets each note's relative length (higher #, longer note)
int melody[] = { C, b, g, C, b, e, R, C, c, g, a, C };
int beats[] = { 16, 16, 16, 8, 8, 16, 32, 16, 16, 16, 8, 8 };
int MAX_COUNT = sizeof(melody) / 2; // Melody length, for looping.
// Set overall tempo
long tempo = 10000;
// Set length of pause between notes
int pause = 1000;
// Loop variable to increase Rest length
int rest_count = 100; //<-BLETCHEROUS HACK; See NOTES
// Initialize core variables
int tone_ = 0;
int beat = 0;
long duration = 0;
// PLAY TONE ==============================================
// Pulse the speaker to play a tone for a particular duration
void playTone() {
long elapsed_time = 0;
if (tone_ > 0) { // if this isn't a Rest beat, while the tone has
// played less long than 'duration', pulse speaker HIGH and LOW
while (elapsed_time < duration) {
digitalWrite(speakerOut,HIGH);
delayMicroseconds(tone_ / 2);
// DOWN
digitalWrite(speakerOut, LOW);
delayMicroseconds(tone_ / 2);
// Keep track of how long we pulsed
elapsed_time += (tone_);
}
}
else { // Rest beat; loop times delay
for (int j = 0; j < rest_count; j++) { // See NOTE on rest_count
delayMicroseconds(duration);
}
}
}
void loop() {
// put your main code here, to run repeatedly:
buttonState = digitalRead(buttonPin);
if (buttonState==HIGH){
digitalWrite(ledPin, HIGH);
noTone(speakerOut);
}else {
digitalWrite(ledPin, LOW);
digitalWrite(speakerOut,HIGH);
for (int i=0; i<MAX_COUNT; i++) {
tone_ = melody[i];
beat = beats[i];
duration = beat * tempo; // Set up timing
playTone();
// A pause between notes...
delayMicroseconds(pause);
}
}
}
You have 2 options, before playTone() check button and, if pressed, end the for loop.
for (int i=0; i<MAX_COUNT; i++) {
tone_ = melody[i];
beat = beats[i];
duration = beat * tempo; // Set up timing
if (digitalRead(buttonPin)==LOW){
playTone();
} else {
break; //End for loop
}
// A pause between notes...
delayMicroseconds(pause);
}
Or the same but using void loop() as a for loop. A global variable, count between 0 and MAX_COUNT and do the same check. If pressed, count=0; and if not, continue playing the next note. Now, I can't code write this but has no difficult.