Collecting from arduino pin for specific time interval - loops

I want to run my Arduino for a specific amount of time (say 60 seconds) and collect
data from the analog pin with a specific sampling rate (say four samples a second).
I got the code working in matlab... but I want to use the arduino environment.
Please help me convert it.
a_pin = 0;
fs = 4; % sampling frequency (samplings per second)
mt = 20; % time for measurements
ind = 1;
nind = 1;
last_beep = 0;
tic;
while toc < mt
time(ind) = toc;
v(ind) = a.analogRead(a_pin);
% wait for appropriate time for next measurement
while( nind == ind )
nind = floor(toc*fs) + 1;
end
ind = nind;
end
Ok this is what i have so far in my sketch. Would this measure for 10 seconds taking
readings every 5?
int sensePin = 0;
unsigned long starttime = 0;
unsigned long endtime = 0;
int i = 0;
int n;
const int sizeofv = 50;
int v[sizeofv];
void setup(){
pinMode(sensePin, INPUT);
Serial.begin(9600);
}
void loop() {
starttime = millis();
endtime = starttime;
while ((endtime - starttime) <= 10000) // do this loop for up to 1000mS
{
i = i + 1;
v[i] = analogRead(sensePin);
endtime = millis();
delay(5000);
}
for(n=0; n < sizeofv; n++)
{
Serial.print(v[n]);
Serial.print('\n');
}
while(1) { }
}

I recommend using SimpleTimer library, it does all the work for you and is road proven.

There's one bug in your code, you're incrementing i prior to assigning the first value. So when you'll loop over the v[] array, you'll end up printing v[0] which will have an undefined value, and you'll never print the last recorded value of v (if you did not end up overflow the buffer and write outside its boundaries).
There's one glitch with your code, it's that you make a condition that you need to end it at 10000, and you make two delays of 5000. Theoretically it looks ok, but in practice, you may get a surprise having only one value. That's because code takes time to execute, and an analogRead() is particularly slow.
I think using loops within the loop() function make things more complicated, and add close to no flexibility. So here you have another take you could try, to use the loop() only by tracking states of the loop, based on some simple calculations:
#define TIME_WINDOW 10000
#define NB_STEPS 2
void setup() {
// ...
endtime = millis();
}
bool over = false;
void loop() {
if (!over) {
curtime = endtime - millis();
// get in this block for up to 1000mS
if (curtime <= TIME_WINDOW) {
v[i] = analogRead(sensePin);
// increments only once when 5000 has been reached.
if ((curtime / (TIME_WINDOW/NB_STEPS)) != i)
i = (curtime / (TIME_WINDOW/NB_STEPS));
} else {
for(n=0; n < NB_STEPS; n++)
Serial.println(v[n]);
over = true;
}
}
}
I did not test my code, so it may fail or have typos, but the idea is the following:
we define the time window and the number of measure steps
while the time window is not over:
store the measurement in the current array at current index
if integer division of spent time over time_window is different from current index
store the new value into the current index
e.g.: i = 4000/(10000/2) <=> i = 4000/5000 <=> i = 0 and i = 6000/(10000/2) <=> i = 1
when the time window is over:
print out each result
set over to true thus we're not entering the loop again
But a simpler (non flexible) solution for you would be:
void setup() {
int value1, value2, value3, value4;
value1 = analogRead(sensePin);
delay(2500);
value2 = analogRead(sensePin);
delay(2500);
value3 = analogRead(sensePin);
delay(2500);
value4 = analogRead(sensePin);
Serial.println("first value: %d", value1);
Serial.println("second value: %d", value2);
Serial.println("third value: %d", value3);
Serial.println("fourth value: %d", value4);
}
and there you got your solution!
HTH

Related

How do I use millis() in Arduino to get the time between two points in a graph?

I am writing a program where the Arduino will start a timer using millis() when the voltage on the analogue pin A2 rises and crosses a threshold and turns off the timer when threshold is crossed again (rising voltage). It will then calculate the time = t2-t1. I thought about using external interrupt and an op-amp to detect the threshold crossing but is there anyway I can accomplish this just with code, without the need for any external hardware??? An image is attached:
Thank you for helping!
Of course:
bool is_high = false;
int threshold = 600; // (or whatever)
unsigned long start_time = 0;
void loop()
{
int val = analogRead(A2);
if (!is_high)
{
if (val > threshold) {
is_high = true;
unsigned long now = millis();
if (start_time != 0) {
Serial.print("t=");
Serial.prinln(now - start_time);
}
start_time = now;
}
}
else {
if (val < threshold) {
is_high= false;
}
}

Struggle to program an LFO

based on some tutorial code I've found I coded a little synthesizer with three oscilators and four different waveform. It works well and I want to add an LFO to module the sounds. Since I didn't coded everything on my own I'm a bit confused of how I could fit the LFO formula on my code. This is more or less what I tried in order to implement the LFO formula on a sinewave.(This formula is something like this: sinewaveFormula + 0.5 * Sinefreq * sin(2pi*1) * time)
double normalize(double phase)
{
double cycles = phase/(2.0*pi);
phase -= trunc(cycles) * 2.0 * pi;
if (phase < 0) phase += 2.0*pi;
return phase;
}
double sine(double phase)
{ phase = normalize(phase); return (sin(phase));}
static void build_sine_table(int16_t *data, int wave_length) {
double phase_increment = (2.0f * pi) / (double)wave_length;
double current_phase = 0;
for(int i = 0; i < wave_length; i++) {
int sample = synthOsc(current_phase, oscNum, selectedWave, selectedWave2, selectedWave3, intensity, intensity2, intensity3) + 0.5 * ((current_phase* wave_length) / (2*pi)) * sin(2*pi*(1.0)) * wave_length;
data[i] = (int16_t)sample;
current_phase += phase_increment;
}
}
static void write_samples(int16_t *s_byteStream, long begin, long end, long length) {
if(note > 0) {
double d_sample_rate = sample_rate;
double d_table_length = table_length;
double d_note = note;
// get correct phase increment for note depending on sample rate and table length.
double phase_increment = (get_pitch(d_note) / d_sample_rate) * d_table_length;
// loop through the buffer and write samples.
for (int i = 0; i < length; i+=2) {
phase_double += phase_increment;
phase_int = (int)phase_double;
if(phase_double >= table_length) {
double diff = phase_double - table_length;
phase_double = diff;
phase_int = (int)diff;
}
if(phase_int < table_length && phase_int > -1) {
if(s_byteStream != NULL) {
int16_t sample = sine_waveform_wave[phase_int];
target_amp = update_envelope();
if(smoothing_enabled) {
// move current amp towards target amp for a smoother transition.
if(current_amp < target_amp) {
current_amp += smoothing_amp_speed;
if(current_amp > target_amp) {
current_amp = target_amp;
}
} else if(current_amp > target_amp) {
current_amp -= smoothing_amp_speed;
if(current_amp < target_amp) {
current_amp = target_amp;
}
}
} else {
current_amp = target_amp;
}
sample *= current_amp; // scale volume.
s_byteStream[i+begin] = sample; // left channel
s_byteStream[i+begin+1] = sample; // right channel
}
}
}
}
}
The code compile but there's no LFO on the sine. I don't understand how I could make this formula work with this code.
It may help to get a basic understanding of how a LFO actually works. It is not that difficult - as an LFO is just another oscillator that is mixed to the waveform you want to modulate.
I would suggest to remove your LFO formular from your call of synthOsc(), then you get a clean oscillator signal again. As a next step, create another oscillator signal for which you can use a very low frequency. Mix both signals together and you are done.
Expresssed in simple math, it is like this:
int the_sample_you_want_to_modulate = synthOsc1(...);
int a_sample_with_very_low_frequency = synthOsc2(...);
Mixing two waveforms is done through addition:
int mixed_sample = the_sample_you_want_to_modulate + a_sample_with_very_low_frequency;
The resulting sample will sweep now based on the frequency you have used for synthOsc2().
As you can see, to implement an LFO you actually do not need a separate formular. You already have the formular when you know how to create an oscillator.
Note that if you add two sine oscillators that have the exact same frequency, the resulting signal will just get louder. But when each has a different frequency, you will get a new waveform. For LFOs (which are in fact just ordinary oscillators - like in your build_sine_table() function) you typically set a very low frequency: 1 - 10 Hz is low enough to get an audible sweep. For higher frequencies you get chords as a result.

Simultaneous blinking LEDs, with separate and inconsistent patterns

I'm trying to run two "Blink"-esque functions simultaneously.
I've found some code elsewhere that lets me do that and modified it! Great.
However, what I am trying to do is have one LED turn on and off every 1000ms as per usual, but have the other blink in an odd pattern, like ON for 3000ms, OFF for 100ms, ON for 100ms, OFF for 200ms then loop back.
To make this happen I tried adding a random function to the code I found but I don't like how it looks. It looks like a blinking LED with interference or something, like on a radio transmitter or whatever. I'm trying to replicate an old flickering lightbulb, meaning it always has to be ON for longer than it is off, Essentially it needs to be ON/HIGH for a "longer" period of time and then interrupted by several short flashes of ON and OFF
So I'm looking for help in how I can orchestrate the 2nd LED to turn on and off in a more specific series of flickers.
Here's the code I'm using so far:
/* Blink Multiple LEDs without Delay
*
* Turns on and off several light emitting diode(LED) connected to a digital
* pin, without using the delay() function. This means that other code
* can run at the same time without being interrupted by the LED code.
*/
int led1 = 13; // LED connected to digital pin 13
int led2 = 12;
int value1 = LOW; // previous value of the LED
int value2 = HIGH; // previous value of the LED
long time1 = millis();
long time2 = millis();
long interval1 = 1000; // interval at which to blink (milliseconds)
void setup()
{
Serial.begin(9600);
randomSeed(analogRead(0));
pinMode(led1, OUTPUT); // sets the digital pin as output
pinMode(led2, OUTPUT);
}
void loop()
{
unsigned long m = millis();
if (m - time1 > interval1){
time1 = m;
if (value1 == LOW)
value1 = HIGH;
else
value1 = LOW;
digitalWrite(led1, value1);
}
long interval2 = random(100,1500);
if (m - time2 > interval2){
time2 = m;
if (value2 == LOW)
value2 = HIGH;
else
value2 = LOW;
digitalWrite(led2, value2);
}
Serial.println(interval2);
}
This will always take less than a second to run so you can get back to your main loop and ensure that you don't miss the 1 second on/off for the other LED:
void flicker(){
boolean state = false;
int r = random(20, 175);
for(int i = 0; i < 5; i++){
digitalWrite(led2, state);
state = !state;
delay(r);
r = random(20, 175);
}
digitalWrite(led2, HIGH);
}
Btw. I'm replacing this toggle code:
if (value2 == LOW)
value2 = HIGH;
else
value2 = LOW;
digitalWrite(led2, value2);
with this:
state = !state;
digitalWrite(led2, state);
Now, call flicker() at random intervals; maybe every 15-45 seconds or whatever you find appropriate/realistic.
Try something like this:
void setup()
{
Serial.begin(9600);
randomSeed(analogRead(0));
pinMode(led1, OUTPUT); // sets the digital pin as output
pinMode(led2, OUTPUT);
}
long interval2 = random(100,1500);
void loop()
{
unsigned long m = millis();
if (m - time1 > interval1){
time1 = m;
if (value1 == LOW)
value1 = HIGH;
else
value1 = LOW;
digitalWrite(led1, value1);
}
if (m - time2 > interval2){
time2 = m;
if (value2 == LOW) {
value2 = HIGH;
interval2 = random(100, 1500);
} else {
value2 = LOW;
interval2 = random(100, 200);
}
digitalWrite(led2, value2);
}

2 timers arduino [ 2x millis() ]

I'm having a problem with this code. I know what the problem is, but I can't find a good solution.
I have two functions using millis() - clock() and time().
The function clock() returns date and time and the function time() returns the time that another action is ON.
The problem is that I'm not able to store the time that the time() function is counting. When I call the function 2 times the time starts on 0:00.
I know it's because I'm overwriting the variable every time I call the loop, but I can't find a good solution for it. It seems stupid, but I have this problem for a while.
PS: I would like to have the time information every loop.
Expected results:
Start
2s: press 1 - clock = 2s, time = 0s.
5s: press 2 - clock = 5s, time = 3s.
15s: press 1 - clock = 15s, time = 3s.
20s: press 2 - clock = 20s, time = 8s.
My code:
void clock() {
// ... function that returns date and time;
// ... using millis();
}
void time(){
if (first == 0){
sec_aux = 0;
min_aux = 0;
UtlTime = millis();
first = -1;
}
if(millis() - UtlTime < 0){
UtlTime = millis();
}
else{
sec_aux = int((millis() - UtlTime) / 1000);
}
if(sec_aux > 59){
sec_aux = 0;
min_aux++;
UtlTime = millis();
}
sec = sec_aux;
min = min_aux;
Serial.println("TIME");
Serial.print(min); Serial.print(":"); Serial.println(sec);
}
void loop() {
if (Serial.available()) {
inChar = Serial.read();
}
switch(inChar){
case '1':
time();
clock();
break;
case '2':
clock();
first = 0;
break;
default:
clock();
}
}
Ok, if I understood correctly you want a function that
1) you call once and it resets the counter
2) you call successively and tells you how much time passed
3) you can reset sometimes
If so, you have to ask yourself "how can I reset the timer?". IMHO the best solution is using a flag passed to the function.
And... avoid using the millis function twice ;)
And, BTW, I think you want to perform an action just once when you receive the serial data, so move the switch inside the test...
Here is a sample:
void time(bool reset){
unsigned long currMillis = millis();
if (reset){
sec_aux = 0;
min_aux = 0;
UtlTime = currMillis;
}
while ((currMillis - UtlTime) > 1000)
{
UtlTime += 1000;
sec_aux++;
}
while(sec_aux > 59){
sec_aux -= 60;
min_aux++;
}
// Why do you duplicate the data?
sec = sec_aux;
min = min_aux;
Serial.println("TIME");
Serial.print(min); Serial.print(":"); Serial.println(sec);
}
void loop() {
if (Serial.available()) {
inChar = Serial.read();
switch(inChar){
case '1':
// Show time measure
time(false);
clock();
break;
case '2':
clock();
// Start time measure
time(true);
break;
default:
clock();
}
}
}
EDIT:
Ok, then you want a "stoppable" stopwatch. What I suggest you is to detach the update from the serial interface, so you always have updated values. Or at least that's the way my head works :P
I modified some things. You should
init lastMillis to millis() in the setup
init timeIsRunning to the proper value
call resetTime() inside the setup
Here is the code:
void resetTime()
{
msec = 0;
sec = 0;
min = 0;
}
void updateTime()
{
unsigned long currStep = millis() - lastMillis;
lastMillis += currStep;
if (timeIsRunning)
{
msec += currStep;
while (msec > 1000)
{
msec -= 1000;
sec++;
}
while(sec > 59){
sec -= 60;
min++;
}
}
}
void printTime()
{
Serial.println("TIME");
Serial.print(min); Serial.print(":"); Serial.println(sec);
}
void loop()
{
updateTime();
if (Serial.available())
{
inChar = Serial.read();
switch(inChar)
{
case '1':
// Show time measure
timeIsRunning = false;
printTime();
clock();
break;
case '2':
clock();
// Start time measure
timeIsRunning = true;
break;
default:
clock();
}
}
}

Arduino Due C Timer Coding (Interrupt Counting)

I have an Arduino Due that I'm doing a lot of really neat stuff with in one section of code I'm handeling a flowsensor and getting readings from it. the flowsensor is hooked up to an interrupt as it is a hallsensor device. The problem I'm having is that my math is based off of a single seconds worth of collection data, when I turn on the interrupt and sleep for a second do the calculations for flowrate in gp/m it works great. For My purposes however I can't afford to pause and collect data, so instead I calculate a change in time of greater than a thousand milliseconds. then I take the amount of time passed since the last loop, devide it by 1000 milliseconds or 1 second then I have the percentage of 1 second stored in a variable, I multiply the count by the percentage and should arrive at the number of counts per second. This however results in an ever growing number regardless of the fact that I zero the numbers prior to the next loop. Below I've included the way I formatted the expressions and the loop code for the flowsensor, I'd post the whole code but I don't want to waste space on stackoverflow and I know that portion of code already works with the sleep method.
long currentMillis = 0;
long lastMillis = 0;
int checkMillis = 0;
volatile int NbTopsFan; //measuring the rising edges of the signal
int newNbTopsFan;
float realNbTopsFan;
float realMillis;
float Calc;
float Calcd;
int Calcf;
int hallsensor = 7;
void loop()
{
if (lastMillis = 0) {
lastMillis = millis();
}
currentMillis = millis();
checkMillis = (currentMillis - lastMillis);
if (checkMillis >= 1000) {
realMillis = (checkMillis / 1000);
realNbTopsFan = (NbTopsFan * realMillis);
newNbTopsFan = realNbTopsFan;
Calc = (newNbTopsFan * 60 / 7.5); //(Pulse frequency x 60) / 7.5Q, = flow rate
Calc = (Calc / 60);
Calc = (Calc / 3.78541);
Calc = (Calc * 1.47);
Calcd = (Calc * 100);
Calcf = Calcd;
NbTopsFan = 0;
lastMillis = 0;
checkMillis = 0;
realMillis = 0;
realNbTopsFan = 0;
newNbTopsFan = 0;
}
}
Your first line should read:
if ( lastMillis == 0 ) {
lastMillis = millis();
}
You need the double = to evaluate the variable

Resources