Arduino: Pin time inactivity/activity - arduino

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.

Related

Arduino send bad signal to interrupt pin

I have connected coin hopper and coin acceptor to one arduino uno, coin acceptor connected to pin 2, coin hopper to pin 3 - sensor and pin 7 - relay. When coin hopper switch relay, it is executing coininterrupt
for coin hopper I am using this script link
coin acceptor script: link
I need this 2 scripts working on 1 arduino
my code:
#define SENSOR 3
#define RELAY 7
#define ACCEPTOR 2
volatile boolean insert = false;
int pulse=0,count;
char sen;
int temp=0;
unsigned long int timer;
void setup()
{
Serial.begin(9600);
pinMode(SENSOR,INPUT_PULLUP);
pinMode(RELAY,OUTPUT);
sen=digitalRead(SENSOR);
digitalWrite(RELAY, HIGH);
attachInterrupt(digitalPinToInterrupt(ACCEPTOR), coinInterrupt, RISING);
}
void loop()
{
if (insert) {
insert = false;
Serial.println("coin");
delay(1000);
}
if(Serial.available())
{
timer=millis();
// temp is amount to dispense send to arduino
temp=Serial.parseInt();
if(temp>0){
digitalWrite(RELAY,LOW);}
}
sen=(sen<<1)|digitalRead(SENSOR);
// if hopper sensor read drop coin
if(sen==1)
{
timer=millis();
pulse++;
sen&=0x03;
Serial.println("out 1");
//if dispensed coins equal with coins to dispense stop engine
if(pulse==temp)
{
digitalWrite(RELAY,HIGH);
pulse=0;
temp=0;
}
}
// if amount dispensed is not equal with amount to dispense and engine running, stop
if((digitalRead(RELAY)==LOW)&(millis()-timer>2000))
{
digitalWrite(RELAY,HIGH);
pulse=0;
temp=0;
}
}
void coinInterrupt() {
insert = true;
}
I was trying to change pins (arduino uno support interrupts on pin 2 and 3 only) but problem still appears so I guess there is issue in the code
your sketch does not run in this state :
first fix errors :
declare insert as volatile
remove cpulse (not used anywhere)
change 'if()' to (I suppose) 'if (insert) ....'
remove stuff with 'sen' var : simply use if(digitalRead(SENSOR)) or if(!digitalRead(SENSOR))
except if you need to store relay state.
use logical operators like || or && unless you really need bitwise operations
example of result sketch :
#define SENSOR 3
#define RELAY 7
volatile boolean insert = false;
byte amountToDispense = 0;
int pulse = 0;
int temp = 0;
unsigned long int timer;
void setup()
{
Serial.begin(9600);
pinMode(SENSOR, INPUT_PULLUP);
pinMode(RELAY, OUTPUT);
digitalWrite(RELAY, HIGH);
attachInterrupt(digitalPinToInterrupt(2), coinInterrupt, RISING);
}
void loop()
{
if (insert ) {
insert = false;
Serial.println("coin");
delay(1000);
}
if (Serial.available())
{
timer = millis();
temp = Serial.parseInt();
if (temp > 0) {
//amountToDispense = Serial.read() - 48;
digitalWrite(RELAY, LOW);
}
}
if (digitalRead(SENSOR))
{
timer = millis();
pulse++;
Serial.println("out 1");
if (pulse >= temp)
{
digitalWrite(RELAY, HIGH);
pulse = 0;
temp = 0;
}
}
if (!digitalRead(RELAY) && (millis() - timer > 2000))
{
digitalWrite(RELAY, HIGH);
pulse = 0;
temp = 0;
}
}
void coinInterrupt() {
insert = true;
}
What is this supposed to do?
sen=(sen<<1)|digitalRead(SENSOR);
You init sen with digitalRead(SENSOR);
Assuming that pin is LOW when you start the sketch and turns HIGH, sen will become 1.
Next you do sen &= 0x03 so sen is still 1.
Again sen=(sen<<1)|digitalRead(SENSOR); , sen will either be 2 or 3.
Next loop run sen=(sen<<1)|digitalRead(SENSOR); sen is now 4 or 6. and so on...
I don't have time to think about what you want to achieve but this is definitely a problem as you'll only enter if (sen == 1) once and never again.
If this is not sufficient you should probably improve your post as it is unclear what arduino sends bad signal to interrup pin is supposed to mean. That doesn't make sense. Explain the expected behaviour of your program and how it behaves instead. add more comments so it becomes clear what you intend to do with each block of code so we don't have to interpret

Using a Arduino Mega instead of a Uno for a capacitive sensor

I was trying to use a Arduino Mega to substitute a Arduino Uno. The folliwing code works fine in Uno but doesn't work on Mega (I already changed the ports to it). It is used for a Capacitive touchsensor:
#define resolution 8
#define mains 60 // 60: north america, japan; 50: most other places
#define refresh 2 * 1000000 / mains
void setup() {
Serial.begin(9600);
// unused pins are fairly insignificant,
// but pulled low to reduce unknown variables
for(int i = 2; i < 14; i++) {
pinMode(i, OUTPUT);
digitalWrite(i, LOW);
}
for(int i =22; i < 53; i++){
pinMode(i, OUTPUT);
digitalWrite(i, LOW);
}
pinMode(8, INPUT);
startTimer();
}
void loop() {
Serial.println(time(8, B00100000), DEC);
}
long time(int pin, byte mask) {
unsigned long count = 0, total = 0;
while(checkTimer() < refresh) {
// pinMode is about 6 times slower than assigning
// DDRB directly, but that pause is important
pinMode(pin, OUTPUT);
PORTH = 0;
pinMode(pin, INPUT);
while((PINH & mask) == 0)
count++;
total++;
}
startTimer();
return (count << resolution) / total;
}
extern volatile unsigned long timer0_overflow_count;
void startTimer() {
timer0_overflow_count = 0;
TCNT0 = 0;
}
unsigned long checkTimer() {
return ((timer0_overflow_count << 8) + TCNT0) << 2;
}
I would like to know what I need to change on the Timer interrupt stuff to make it work properly.

Arduino for loop completely not functional

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;
}
}

How to light up multiple lines on an LED display?

I am working on an LED display project and trying to show some words on the display, though I can't get continuous lines to light up. Below is the code.
int greenPin = 7;
int redPin = 6;
int stbPin = 2;
int clkPin = 3;
int aPin = 4;
int bPin = 5;
int delayTime = 1;
int i = 0;
void setup() {
pinMode(greenPin, OUTPUT);
pinMode(redPin, OUTPUT);
pinMode(stbPin, OUTPUT);
pinMode(clkPin, OUTPUT);
pinMode(aPin, OUTPUT);
pinMode(bPin, OUTPUT);
digitalWrite(aPin, LOW);
digitalWrite(bPin, LOW);
digitalWrite(stbPin, HIGH);
digitalWrite(clkPin, LOW);
}
void loop() {
digitalWrite(stbPin, LOW);
digitalWrite(aPin, HIGH);
digitalWrite(bPin, LOW);
twoLines(B11111111, B11111111, B00000000, B00000000, B11111111, B11111111, B00000000, B00000000);
digitalWrite(aPin, LOW);
digitalWrite(bPin, LOW);
delayMicroseconds(delayTime);
digitalWrite(stbPin, HIGH);
delayMicroseconds(delayTime);
}
void twoLines( byte br, byte dr, byte ar, byte cr, byte bg, byte dg, byte ag, byte cg) {
byte Garr[] = { ag, bg, cg, dg };
byte Rarr[] = { ar, br, cr, dr };
for ( int i = 0; i < 4; i++ ) {
for (byte mask = 11111111; mask > 0; mask >>= 1) {
digitalWrite(clkPin, LOW); // delayMicroseconds(delayTime);
if (Rarr[i] & mask) {
digitalWrite(redPin, HIGH);
} else {
digitalWrite(redPin, LOW);
}
if (Garr[i] & mask) {
digitalWrite(greenPin, HIGH);
} else {
digitalWrite(greenPin, LOW);
}
delay(2);
digitalWrite(clkPin, HIGH);
delay(2);
}
}
}
Right now, I can at most only light up two rows, but I want the capability to be able to light up three rows at once to create letters. Help of any kind is appreciated. Below is also how the LED display looks like.
For things like this first thing you do, read the data sheet of your LED and see how much current they draw. If you got like 100 LED and each draw 20 mA, that would be 2 Amps and not only Arduino can not supply it, you are risking burning your Arduino. After you figured out how much current your system needs, you gotta use a power source that can handle it. You got several options, for example a BJT is a current amplifier but it complicates the design and needs some background in electrical engineering. The other option would be using external power sources such as batteries or wall plugs. Then, you just need to buy a good adapter or voltage regulator that can handle your current need. Also, in that case you will need some sort of relay to control the leds with your Arduino. What Relay does is that it lets you turn it on and off with micro controller logic, but when it is on it uses an external power source.

LED stays on even when digitalRead is low

I am just creating a simple basic program, but I can't figure out what's going wrong.
I have set three pins as output and three pins as input. When those three pins digitalRead == HIGH they will set an LED to HIGH, but instead my LED is always staying high.
Here is my Arduino code:
int LED_Low = 4; // Red LED
int LED_Avg = 3; // Yellow LED
int LED_High = 2; // Green Led
int WaterLow = 7;
int WaterAvg = 8;
int WaterHigh = 9;
void setup() {
// Put your setup code here, to run once:
pinMode(LED_Low, OUTPUT);
pinMode(LED_Avg, OUTPUT);
pinMode(LED_High, OUTPUT);
pinMode(WaterLow, INPUT);
pinMode(WaterAvg, INPUT);
pinMode(WaterHigh, INPUT);
}
void check(){
if(digitalRead(WaterLow) == HIGH){ // If Water level is low
digitalWrite(ledLow, HIGH); // Turn on red LED indication water level is low
}
else{
digitalWrite(ledLow, LOW);
}
if(digitalRead(WaterAvg) == HIGH){ // If water level is medium
digitalWrite(ledAvg, HIGH); // Turn on yellow LED indicating water level is average
}
else{
digitalWrite(ledAvg, LOW);
}
if(digitalRead(WaterHigh) == HIGH){ //
digitalWrite(ledHigh, HIGH); //
}
else{
digitalWrite(ledHigh, LOW);
}
}
void loop() {
// Put your main code here, to run repeatedly:
check();
}
In the above image I have connected led on pin 2, 3, and 4 with 1.5 kilohm resistor and three wires in pin 7, 8, and 9 which will receive input from the 5 volt pin and turn on the LED. Accordingly, the 5 volt pin is connected to the positive terminal on the power bus and with 9.1 *2 resistors in series and then this wire connect with pin 2, 3, and 4.
I found the issue. My code was OK. It was my circuit.
The pins I declared to receive input were not connected to ground.
You can make that with the help of two cases
Define the delay
if (digitalRead(WaterLow) == HIGH) // If Water level is low
{
digitalWrite(ledLow, HIGH); // Turn red LED indication water level is low
delay(2000);
}
else
{
digitalWrite(ledLow, LOW);
}
Make a condition like this
int stateled = LOW;
int previous = LOW;
long time = 0;
long debounce = 200;
void loop()
{
stateButton = digitalRead(WaterLow);
if (stateButton == HIGH && previous == LOW && millis() - time > debounce)
{
if(stateLED == HIGH)
{
stateLED = LOW;
}
else
{
stateLED = HIGH;
}
time = millis();
}
digitalWrite(ledlow, stateLED);
previous == stateButton;
}

Resources