Arduino for loop completely not functional - arduino

I am trying to send data from an accelerometer to Java from an Arduino. I am using delta time to limit it to sending only every 250 ms.
The problem is that all the Java program is reading is the first message sent in the setup() over and over.
I added a test Serial.write to check if the program is ever entering the delta time block, and it seems to be sending (or at least, reading) the first 2 characters of that message. The Arduino code is below.
#include <SparkFun_MMA8452Q.h>
int sleepPin = 7;
int stepPin = 6;
int buttonPin = 8;
int stepCount = 0;
boolean stepMode = true;
int delTime = 5000;
MMA8452Q accel; //accelerometer
void setup() {
Serial.begin(9600);
while (millis() < 4000); //wait so I can start java program
Serial.write("Connected");
//set pins
pinMode(sleepPin, OUTPUT);
pinMode(stepPin, OUTPUT);
pinMode(buttonPin, INPUT);
digitalWrite(stepPin, HIGH); //starts in step mode
delTime = millis() + 250;
}
void loop() {
if (digitalRead(buttonPin) == HIGH) stepMode = !stepMode;
if (millis() > delTime) {
Serial.write("delTime"); //test case
//set led's according to mode
if (stepMode) {
digitalWrite(stepPin, HIGH);
digitalWrite(sleepPin, LOW);
} else {
digitalWrite(stepPin, HIGH);
digitalWrite(sleepPin, LOW);
}
//create string to store data
String data = "";
if (stepMode) data += "s"; //s is step mode key
else data += "z"; //z is sleep mode key
//add actual reading stuff
data += String(accel.getX()) + "," + String(accel.getY());
Serial.write(data.c_str()); //send the lad over
}
}
The Java side is nearly identical (sans the conditions of an if statement, but it doesn't matter because if it doesn't meet the statement it just prints what it sees) to a functional program for serial communication that I've used before. I can include it if necessary though.
The Java console output appears as:
Connected
de
Connected
de
Connected
de
where a new iteration appears about once a second. What am I doing that prevents the Arduino from sending the data?

Not a proper answer yet, more of a test, but I couldn't fit it in a comment.
Changes made:
delTime is now an unsigned long int;
delTime is now reset at the end of the loop();
String object and manipulations were replaced by heap-friendlier code.
Added accel.begin();
Let me know if this works for you, and if not, where it complains. Haven't fully tested the code. You could also try replacing accel.getX() and accel.getY() with numbers; they return short ints, I think.
BTW the button needs debouncing.
#include <SparkFun_MMA8452Q.h>
int sleepPin = 7;
int stepPin = 6;
int buttonPin = 8;
boolean stepMode = true;
unsigned long int delTime = 0;
MMA8452Q accel; //accelerometer
void setup(){
Serial.begin(9600);
while(millis() < 4000); //wait so I can start java program
Serial.write("Connected");
//set pins
pinMode(sleepPin, OUTPUT);
pinMode(stepPin, OUTPUT);
pinMode(buttonPin, INPUT);
accel.begin();
digitalWrite(stepPin, HIGH); //starts in step mode
delTime = millis() + 250;
}
void loop() {
char str[15];
if (digitalRead(buttonPin) == HIGH)
stepMode = !stepMode;
if (millis() > delTime) {
//set led's according to mode
if (stepMode) {
digitalWrite(stepPin, HIGH);
digitalWrite(sleepPin, LOW);
Serial.write('s');
} else {
digitalWrite(stepPin, HIGH);
digitalWrite(sleepPin, LOW);
Serial.write('z');
}
sprintf(str, "%d", accel.getX());
Serial.write(str);
Serial.write(',');
sprintf(str, "%d", accel.getY());
Serial.write(str);
Serial.write('\n');
delTime = millis() + 250;
}
}

Related

How can I make an LED blink every n seconds without developing a lag?

I'm using an Arduino Uno to control LED. I want the LED to turn on every m seconds and remain ON for n seconds.
I've tried this code using the delay() function (by adding delays after LED is turned ON and OFF) and also using the millis() function (by keeping a track of the time passed since the previous event - ON/OFF). However, in both the approaches, the LED develops a lag of ~1 second after a few (!10) iterations of the ON-OFF cycle. What can I do to increase the accuracy of the time at which the events occur?
int led = 13;
long experimentTime = 240000;
long ledOFFDuration = 8000;
void setup() {
pinMode(led, OUTPUT);
pinMode(button, INPUT);
}
void loop() {
for (int i = 0; i < 100; i++){
digitalWrite(led, HIGH);
delay(10000);
digitalWrite(led, LOW);
delay(10000);
}
}
I've also tried using the watchdog timer (shown below). However, it has the same issue:
#include <avr/wdt.h>
int led = 13;
volatile byte watchDogState = 0b01000000;
volatile int counter = 0;
int counterMax = 5;
bool state = 1;
void setup() {
// put your setup code here, to run once:
wdt_disable();
pinMode(led, OUTPUT);
digitalWrite(led, 1);
setWDT(watchDogState);
}
void loop() {
// put your main code here, to run repeatedly:
// if (time_elapsed == 40){
//state = !state;
//}
}
void setWDT(byte sWDT){
WDTCSR |= 0b00011000;
WDTCSR = sWDT | WDTO_2S;
wdt_reset();
}
ISR (WDT_vect){
counter++;
if (counter >= counterMax){
state = !state;
digitalWrite(led, state);
counter = 0;
}
}
I tried using the port registers directly to avoid using digitalWrite completely. But that doesn't work either. There's a lag of ~5s after 20 minutes using the following code:
int led = 13;
int m = 10;
int n = 10;
boolean on;
long change;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
long now = millis();
if (!on && change < now) {
on = true; //led is now on
change = now + n*1000; //turn off in <n> seconds
PORTB |= B00100000;
}
else if (on && change < now){
on = false; //led is now off
change = now + m*1000; //turn on in <m> seconds
PORTB &= B11011111; // Set pin 4 to 0
}
}
The lag is caused by the digitalWrite-calls. Your processing application waits until digitalWrite has finished and this may take 0.05 seconds or so. To fix your problem I would save the current time in milliseconds.
int led = 13;
int m = 24;
int n = 8;
boolean on;
long change;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
long now = System.currentTimeMillis();
if (!on && change < now) { //led is off and time for change has come
on = true; //led is now on
change = += n*1000; //turn off in <n> seconds
digitalWrite(led, HIGH); //turn on led
} else if (on && change < now) { //led is on and time for change has come
on = false; //led is now off
change = += m*1000; //turn on in <m> seconds
digitalWrite(led, LOW); //turn off led
}
}
the lamp will now instantly turn on on startup, wait n seconds, turn off, wait m seconds and restart from the beginning.
If you want to create a delay at the beginning so that the lamp doesn't get turned on immediately you can simply add this to your setup-function:
change = now + SECONDS*1000;
EDIT
You pointed out that it still gives you lag.
One problem might be that loop() is not run every millisecond. So I maybe got a solution for you.
Replace the following two lines:
change = now + n*1000; //turn off in <n> seconds
...
change = now + m*1000; //turn on in <m> seconds
to this:
change += n*1000; //turn off in <n> seconds
...
change += m*1000; //turn on in <m> seconds
Now it won't take the current time anymore which means that even if loop is only run every second or two it should still not cause any lag.
If this won't work I'm afraid it looks like the timer on the arduino might not be the most precise one. If this is the case try to measure the exact offset and then create a miltiplicator for the time.

Arduino: Pin time inactivity/activity

The purpose of the following Arduino code is to interface with the high and low signals sent from a Raspberry Pi; the full explanation is rather complex so I'll spare you the waste in time. The signals sent from the Pi (pins 10 and 11) turn a stepper motor connected to an A4988 driver clockwise or counterclockwise. The pins that dictate this out of the Arduino are the step and direction pins (9 and 8). What I am trying to accomplish is to enable the sleepPin after 60 seconds of pin 10 and 11 inactivity.
Likewise, in the same fashion, I want to stop accepting input from pin 10 and 11 if they both read the same input signal for more than 3 seconds. I've looked up methods on how to incorporate time into Arduino script but do not know how to incorporate it in this instance.
byte directionPin = 9;
byte stepPin = 8;
byte sleepPin = 12;
byte buttonCWpin = 10;
byte buttonCCWpin = 11;
boolean buttonCWpressed = false;
boolean buttonCCWpressed = false;
long previousMillis = 0;
long interval = 1000;
void setup() {
//determines length of stepper movement
pinMode(directionPin, OUTPUT);
pinMode(stepPin, OUTPUT);
//moves motors clockwise or counterclockwise
pinMode(buttonCWpin, INPUT_PULLUP);
pinMode(buttonCCWpin, INPUT_PULLUP);
}
void loop() {
readButtons();
actOnButtons();
}
void readButtons() {
buttonCCWpressed = false;
buttonCWpressed = false;
if (digitalRead(buttonCWpin) == LOW) {
buttonCWpressed = true;
}
if (digitalRead(buttonCCWpin) == LOW) {
buttonCCWpressed = true;
}
}
void actOnButtons() {
if (buttonCWpressed == true) {
digitalWrite(directionPin, LOW);
for(int x = 0; x < 1; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(515);
digitalWrite(stepPin,LOW);
delayMicroseconds(515);
}
}
if (buttonCCWpressed == true) {
digitalWrite(directionPin, HIGH);
for(int x = 0; x < 1; x++) {
digitalWrite(stepPin,HIGH);
delayMicroseconds(515);
digitalWrite(stepPin,LOW);
delayMicroseconds(515);
}
}
}
Any help would be greatly appreciated along with any tips or concerns.
Thank You.
If you have the luxury to use pins 2 and 3 rather than pins 10 and 11 (assuming you have an Arduino Uno for instance), it could be useful to work with external interrupts.
As a solution for your first problem, here's a minimal code that should put the sleep pin high after 60 seconds of inactivity on both direction pins 2 & 3:
volatile long int last_activity;
void setup(){
attachInterrupt(2, tstamp, CHANGE);
attachInterrupt(3, tstamp, CHANGE);
pinMode(2, INPUT); // your new CW pin
pinMode(3, INPUT); // your new CCW pin
pinMode(12, OUTPUT);
digitalWrite(12, LOW);
last_activity = millis();
}
void loop(){
if (millis() - last_activity > 60e3) {
digitalWrite(12, HIGH);
// do some other things...
}
}
void tstamp(){
last_activity = millis();
}
Now for your second problem, what exactly do you mean by "stop accepting input from pins 10 and 11"? If you only need to check that their state is the same, adding volatile long int last_common_state; in the preamble and checking for digitalRead(2) == digitalRead(3); in tstamp()'s body to update last_common_state should get you on the right track.

Reading and transferring encoder data from slave Arduino to master Arduino over SPI

My goal is to transfer a speed value from an encoder from a slave Arduino to a master Arduino via SPI. I am currently getting zeros on the master side serial print and I'm not sure what I am doing wrong. I have increased the amount of time to wait several times to see if it was a processing time issue but I had it waiting for 100mS with still no change. I know an unsigned int is 4 bytes and I am unsure if a union is the best option in this case seeing I might be overwriting my data due to the separate interrupts but I am unsure. I thought to use a struct since I'll have to move to transferring an array of floats and ints over SPI from various sensors including this encoder later. Below is my code and thank you for any help received:
Slave
#include "math.h"
#define M_PI
byte command = 0;
const int encoder_a = 2; // Green - pin 2 - Digital
const int encoder_b = 3; // White - pin 3 - Digital
long encoder = 0;
int Diameter = 6; // inches
float previous_distance = 0;
unsigned long previous_time = 0;
void setup (void)
{
Serial.begin(115200);
pinMode(MOSI, INPUT);
pinMode(SCK, INPUT);
pinMode(SS, INPUT);
pinMode(MISO, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
pinMode(encoder_a, INPUT_PULLUP);
pinMode(encoder_b, INPUT_PULLUP);
attachInterrupt(0, encoderPinChangeA, CHANGE);
attachInterrupt(1, encoderPinChangeB, CHANGE);
}
// SPI interrupt routine
ISR (SPI_STC_vect)
{
union Data{
float f;
byte buff[4];}
data;
byte c = SPDR;
data.f = assembly_speed();
command = c;
switch (command)
{
// no command? then this is the command
case 0:
SPDR = 0;
break;
// incoming byte, return byte result
case 'a':
SPDR = data.buff[0];
break;
// incoming byte, return byte result
case 'b':
SPDR = data.buff[1];
break;
// incoming byte, return byte result
case 'c':
SPDR = data.buff[2];
break;
// incoming byte, return byte result
case 'd':
SPDR = data.buff[3];
break;
}
}
void loop (void)
{
// if SPI not active, clear current command
if (digitalRead (SS) == HIGH)
command = 0;
}
void encoderPinChangeA()
{
encoder += digitalRead(encoder_a) == digitalRead(encoder_b) ? -1 : 1;
}
void encoderPinChangeB()
{
encoder += digitalRead(encoder_a) != digitalRead(encoder_b) ? -1 : 1;
}
float distance_rolled()
{
float distance_traveled = (float (rotation()) / 8) * PI * Diameter;
return distance_traveled;
}
int rotation()
{
float eigth_rotation = encoder / 300;
return eigth_rotation;
}
float assembly_speed()
{
float current_distance = (float (rotation()) / 8) * PI * Diameter;
unsigned long current_time = millis();
unsigned long assemblySpeed = (((current_distance - previous_distance) /
12) * 1000) / (current_time - previous_time); // gives ft/s
previous_distance = current_distance;
previous_time = current_time;
return assemblySpeed;
}
Master
#include <SPI.h>
void setup (void)
{
pinMode(MOSI, OUTPUT);
pinMode(MISO, INPUT);
pinMode(SCK, OUTPUT);
pinMode(SS, OUTPUT);
Serial.begin (115200);
Serial.println ();
digitalWrite(SS, HIGH);
SPI.begin ();
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
byte transferAndWait (const byte what)
{
byte a = SPI.transfer (what);
delayMicroseconds(10000);
return a;
}
union Data
{
float f;
byte buff[4];
}
data;
void loop (void)
{
digitalWrite(SS, LOW);
transferAndWait ('a');
data.buff[0] = transferAndWait ('b');
data.buff[1] = transferAndWait ('c');
data.buff[2] = transferAndWait ('d');
data.buff[3] = transferAndWait (0);
digitalWrite(SS, HIGH);
Serial.print("data.f = ");Serial.print(data.f);Serial.println(" Ft/s");
delay(200);
}

How do I receive a HIGH or LOW signal from an IR sensor on an Arduino?

I'm trying to use an IR sensor with my Arduino Uno and only want a HIGH or LOW signal without decoding making any IR signal turn the state to a 1 or 0. There is also a motion sensor but that code has been removed.
int ledPin = 13; // choose the pin for the LED
int inputPin = 2; // choose the input pin (for PIR sensor)
int pirState = LOW; // we start, assuming no motion detected
int val = 0; // variable for reading the pin status
int relayPin = 4; //PIN FOR RELAY OPERATION
int irPin = 7; //IR Sensor pin
int lightState = 0;
int irVal = 0;
void setup() {
pinMode(ledPin, OUTPUT); // declare LED as output
pinMode(inputPin, INPUT); // declare sensor as input
pinMode(relayPin, OUTPUT);
pinMode(irPin, INPUT);
Serial.begin(9600);
}
void loop() {
irVal = digitalRead(irPin);
if (irVal == HIGH) {
lightState = 1;
Serial.println("IR received");
while(irVal == HIGH) {
irVal = digitalRead(irPin);
if(irVal == HIGH) {
irVal = LOW;
} else {
irVal = HIGH;
}
}
}
Are you trying to say that the input is not working correctly? Maybe try INPUT_PULLUP instead of INPUT in the setup loop.
For example:
pinMode(inputPin, INPUT_PULLUP);
Information about this principle you can find here:
https://www.arduino.cc/en/Tutorial/InputPullupSerial

How to add a time delay when reading a sensor - arduino

I am making a project that has to sense ambient light with a LDR. The idea is, that when the value of the LDR is low for 3 seconds, the led turns on. Also when the value of that LDR gets higher again, and stays high for 3 seconds, the led should turn of. This is so I can avoid that just a cloud or somebody waving over the sensor turns the led on immediately.
I know that I can use the mills() function here like in the blink without delay tutorial. But it doesn't seem to work....
this is my code so far:
#define ledPin 2
#define ldrPin A0
int daylight = 430;
int night = 150;
int ledState = 0;
int lightState = 0;
const long timeOut = 2000;
unsigned long previousMillis = 0;
unsigned long previousMillis2 = 0;
unsigned long tNow = 0;
void setup() {
// put your setup code here, to run once:
pinMode(ledPin, OUTPUT);
pinMode(ldrPin, INPUT);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
tNow = millis();
int value = analogRead(ldrPin);
switch (lightState) {
case 0:
ledState = 0;
if (value <= 200 && (tNow - previousMillis) >= timeOut)
{
previousMillis = tNow;
lightState = 1;
}
break;
case 1:
ledState = 1;
if (value >= 300 && (tNow - previousMillis2) >= timeOut)
{
previousMillis2 = tNow;
lightState = 0;
}
break;
}
switch (ledState) {
case 0:
digitalWrite(ledPin, LOW);
break;
case 1:
digitalWrite(ledPin, HIGH);
break;
}
Serial.println(value);
Serial.println(ledState);
}
You could try using smoothing to read a running average from the sensor. That way you'll have a smoothed average instead of an immediate value, so a short spike (like a hand) won't change the value if you keep the window long enough.
There is a tutorial on the arduino website explaining how to do this. Basically you store multiple previous values and keep track of the average.

Resources