It is possible to serial print how milliseconds every output high. Let say i write an code analogRead. If analogread bigger than 600, then digitalwrite 13, high. If output pin 13 high, then capture how millisecond until the pin 13 goto low.
I try millis() but it cannot reset back to zero... It there anyway to reset millis() to zero?
You need a variable to keep track of your millis() count between events, kind of like a stop watch: you need to remember you started counting, so you can measure the difference when you stop.
Here's a quick sketch to illustrate the idea. Code isn't tested on an Arduino, but you should be able to understand the concept from the comments:
long lastTime;
int ledState = 0;
void setup() {
Serial.begin(115200);
pinMode(13,OUTPUT);
}
void loop() {
int analogValue = analogRead(0);
int newLedState = (analogValue > 600);//need to check, hoping boolean will evaluat to 1 when true
if(ledState == 0 && newLedState == 1){//if the led was of, but will be turned on, start the stop watch
lastTime = millis();//store the current time
ledState = newLedState;
}
if(ledState == 1 && newLedState == 0){//if the led was on, but will be turned off, get the difference between the last time we started counting time
long difference = millis() - lastTime; //get the current time, but subtract the last stored time
ledState = newLedState;
Serial.println(difference);
}
digitalWrite(13,ledState);
}
Okay so I think I understand what you want here. You want to capture the time difference between 2 pins changing their electrical state. To do this you can use pulseIn().
Using your example in your question we get...
if (13 == HIGH) {
millis = pulseIn(13, LOW);
}
That will give you the duration between the pin going high and then going low, stored in the variable millis. It's good practice to store it in a long.
Related
I am working on a school project for which I rotate a servo after a cable disconnects and a specific delay is over. This is my current code. We are using an Arduino Uno powered from the USB port
#include <Servo.h>
int reader=4;
int servo1Pin=8;
Servo servo1;
int value;
int pos=10;
int wacht=5000;
void setup() {
pinMode(reader, INPUT);
servo1.attach(servo1Pin);
}
void loop() {
value = digitalRead(reader);
servo1.write(pos);
if (value == LOW) {
delay(wacht);
pos=180;
}
else {
pos=10;
}
}
wacht is the specific delay. When we disconnected pin 4 to break that circuit we don't have a consistent time between the interruption of the power flow and the opening of the servo. It seems to vary from anywhere between 5 to 40 seconds of delay after triggering. Does anyone have any ideas to solve this issue?
try change
pinMode(reader, INPUT);
to
pinMode(reader, INPUT_PULLUP);
And for clarification delay don't use timer.
The order of your instructions seem strange. the usual order is:
Read
Decide
Act
Also, you may want to avoid sending useless instructions to the servo. For example, when you know the servo is already in the correct position. You should not rely on eternal code to do the right thing. In other terms, you have no idea how long servo1.write() takes to execute.
Which would give for your loop()
void loop()
{
if (digitalRead(reader) == LOW)
{
if (pos != 180)
{
delay(wacht); // delay() is only called once, when circuit breaks.
// this guarantees immediate response when circuit
∕/ closes again.
pos = 180;
servo1.write(pos);
}
}
else if (pos != 10)
{
pos = 10;
servo1.write(pos);
}
}
Also, have a look and implement Peter Plesník's answer. This will probably solve some of your problems. You input will definitely still have a random lag of up to 5 seconds when closing the circuit, though.
I need to check if a LED is blinking every 2 seconds...is it possible? I am using Arduino Mega 2560. Thank you.
There are multiple options, depending on the LED itself.
If you have access to the wiring of the LED (I assume 5V !) you can connect a interrupt Pin of the Arduino with it and a common GND. Now you can count the "Turn Ons" and devide it by the Time, to get an average value, which should be equal to two.
Example Code would be (NOT tested!):
#define MEASUREPIN 2 // Watch https://www.arduino.cc/en/Reference/AttachInterrupt for infos
long measureStartTime{0}; // ms since start of first blink
long runTime{0}; // [ms]
long avgTime; // [ms]
volatile long cycles{0};
void setup() {
pinMode(MEASUREPIN, INPUT);
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(MEASUREPIN), countCycles, RISING);
}
void loop() {
if(measureStartTime == 0 && cycles == 0){
Serial.println("Blink not started");
}else{
if(measureStartTime == 0){
measureStartTime == millis();
}else{
runTime = millis()-measureStartTime;
avgTime = runTime/cycles;
Serial.print("Average blink interval: ");
Serial.print(avgTime);
Serial.println("ms");
}
}
}
void countCycles(){
cycles++;
}
If you haven't access to the wiring you can use a lightsensor, to generate a similar signal.
I hope that fits your needs, because i am not allowed to comment, so i couldn't get further infos.
I need help with debounce of push button. Sometimes it send twice same string to serial link, and I don't know why. Could someone help me, where is a problem?
int reading;
int exbutton= LOW;
unsigned long ddelay= 200;
unsigned long last= 0;
void loop(){
reading= digitalRead(prkgbrake);
if (reading== HIGH && exbutton == LOW && millis() - last> ddelay){
if (brake == 0){
Serial.write("brake:1\n");
while( digitalRead(prkgbrake) == HIGH){
}
}
else{
Serial.write("brake:0\n");
while( digitalRead(prkgbrake) == HIGH){
}
}
last = millis();
}
Thank you in advance.
I hope you didn't copy this code from somewhere, some of the code doesn't make sense.
For instance, what is 'prkgbrake'? What is 'brake'? They are not declared. Why don't you have a 'setup()' function?
Nevertheless, debouncing can be achieved in many ways. I will just fix your code. That way you will understand what you did wrong.
int exbutton = LOW;
unsigned int _delay = 200;
int pushButton = 2;
void setup()
{
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
pinMode(pushButton, INPUT_PULLUP);
}
void loop()
{
while (digitalRead(pushButton) == LOW && exbutton == LOW)
{
if((millis() - last) > _delay)
{
Serial.println("Button Pressed");
while(digitalRead(pushButton) == LOW);
}
}
last = millis();
}
Explanantion: Assuming your pushbutton is connected with digital pin 2. When you use a digital pin with a button it is better to use pullup/pulldown. You can use external resistor or the internal resistor for that. The internal resistor only supports Pull-up.
To know more about pull-up/-down checkout this Arduino page. The bottom line is when you use a pin as input it acts like an antenna and can capture signals from surroundings, known as floating state. So it is better to keep the pin in a known state. If you use internal pull-up, the pin will be always HIGH. So the button configuration has to be in a way so that when it is pressed the pin should go LOW.
Pull Up Configuration
The code pinMode(pushButton, INPUT_PULLUP); enables the digital pin 2 as input with pull-up enabled.
the loop() should work like this:
1) Check if the button is pressed (i.e. if it is LOW).
2) If not update the last variable.
3) If yes then DONT update last, and enter the while loop.
4) Now keep checking if millis()-last is greater than _delay. If not it will go back to while loop and check if the button is still pressed or not. If yes then it will come back and check if millis()-last is more than _delay or not. It will continue to do so until it passed the mentioned amount of debounce delay.
5) If button get depressed (i.e. goes to HIGH) before the '_delay' time then it will update the last and will check if button is pressed or not and will start counting the delay time.
N.B. Play with the _delay variable. It will define the responsiveness of your button.
Im an artist, not a programmer. But i'm making a pinball game with an Arduino, and I do not have a programmer, so I'm learning what I can to make this work.
I'm trying to write a code that does this:
- 3 targets (buttons) that when hit, they give points, and light an LED.
- If the same button is hit a second time, it will still give points, and the LED stays lit.
- If ALL 3 lights are lit at the same time, there is a bonus score given, and ALL 3 lights turn off.
I tried using the Arduino forums but the best advice I could get out of them was "Go learn to code."
I have been told to learn about 'arrays' and I have tried but I'm having some serious trouble wrapping my head around it. If it is possible to do this with just 'IF' and 'ELSE' statements I would really prefer to do things the long and inefficient way.
Here is my current code. Currently I have 4 lights on my breadboard. Light #4 (D) is lit right away for debug reasons. Each of the other 3 lights (ABC) will light when their button is pushed. When All 3 lights are lit, (D) light will go out, but (ABC) remain lit. I need them to go out when (D) does. and I don't know why they wont. I know the code recognizes that all 3 are HIGH. Because (D) goes LOW. I don't know why (ABC) won't go LOW as well.
// 3 TARGET SCORE FUNCTION.
// WHEN A TARGET IS HIT IT LIGHTS UP AND PROVIDES POINTS.
// IF A TARGET IS HIT AGAIN WHILE IT IS ALREADY LIT, IT STILL SCORES POINTS AND STAYS LIT.
// WHEN ALL 3 TARGETS ARE LIT THEY FLASH AND PROVIDE A JACKPOT
// WHEN JACKPOT IS PROVIDED ALL LIGHTS TURN OFF. READY TO BE ACTIVATED AGAIN.
int dropButtonA = 2; // the number of the input pin
int dropButtonB = 3;
int dropButtonC = 4;
int dropLightA = 11; // the number of the output pin
int dropLightB = 12;
int dropLightC = 13;
int dropLightD = 10;
int stateA = LOW; // the current state of the output pin
int stateB = LOW;
int stateC = LOW;
int stateD = LOW;
int readingA; // the current reading from the input pin
int readingB;
int readingC;
int previousA = LOW; // the previous reading from the input pin
int previousB = LOW;
int previousC = LOW;
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers
void setup()
{
pinMode(dropButtonA, INPUT);
pinMode(dropButtonB, INPUT);
pinMode(dropButtonC, INPUT);
pinMode(dropLightA, OUTPUT);
pinMode(dropLightB, OUTPUT);
pinMode(dropLightC, OUTPUT);
pinMode(dropLightD, OUTPUT);
}
void loop()
{
//droptarget_01//
readingA = digitalRead(dropButtonA);
if (readingA == HIGH && previousA == LOW && millis() - time > debounce) {
stateA = HIGH;
time = millis();
}
digitalWrite(dropLightA, stateA);
previousA = readingA;
//droptarget_02//
readingB = digitalRead(dropButtonB);
if (readingB == HIGH && previousB == LOW && millis() - time > debounce) {
stateB = HIGH;
time = millis();
}
digitalWrite(dropLightB, stateB);
previousB = readingB;
//droptarget_03//
readingC = digitalRead(dropButtonC);
if (readingC == HIGH && previousC == LOW && millis() - time > debounce) {
stateC = HIGH;
time = millis();
}
digitalWrite(dropLightC, stateC);
previousC = readingC;
//RESET TARGETS - BONUS SCORE
if (digitalRead(dropLightA)==HIGH && digitalRead(dropLightB)==HIGH && digitalRead(dropLightC)==HIGH)
{
digitalWrite(dropLightA, LOW);
digitalWrite(dropLightB, LOW);
digitalWrite(dropLightC, LOW);
digitalWrite(dropLightD, LOW);
}
else
{
digitalWrite(dropLightD, HIGH);
}
}
The problem is that the variable named "stateX" does not change when ABC goes LOW. You need to add these statements to the "//RESET TARGETS - BONUS SCORE" loop when the condition is true:
stateA = LOW;
stateB = LOW;
stateC = LOW;
stateD = LOW;
IMHO you do not need to use arrays when there are only four items- clarity of code (esp. to the author) has value. However, I think that the variables "stateX" and "previousX" are redundant; if you did not have both you would not have this bug.
Also, I would recommend using the previously read value of the pins for the loop test at "//RESET TARGETS - BONUS SCORE":
if (readingA == HIGH && readingB == HIGH && readingC == HIGH)
With your current code you read the values of the pins twice during the loop. In this case there is a chance the value of the pins could change during the loop and you could get really confusing results.
I am new to Arduino programming and trying to use the arduino uno as a high resolution timer. I would like to be able to count clock cycles at the full 16MHz rate between two rising edge interrupts. I have some code that is functional using the micros() function which has 4 microsecond resolution, and I need better than that. Here is an example code where I am trying to use micros() for the timing:
volatile int k = 0;
volatile float t1 = 0;
volatile float t2 = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(2), ISR1, RISING);
attachInterrupt(digitalPinToInterrupt(3), ISR2, RISING);
}
void ISR2()
{
k = 1;
t1 = micros();
Serial.println(1);
}
void ISR1()
{
k = 2;
t2 = micros();
Serial.println(2);
}
void loop()
{
if (t1 != 0 && t2 != 0) {
if (t2 - t1 < 0) {
t1 = 0;
t2 = 0;
}
else {
Serial.print("tdelta ");
Serial.print(t2 - t1);
t1 = 0;
t2 = 0;
Serial.println(0);
}
}
}
I realize that my micros timing is probably getting a bit offset by the interrupts, which may be an issue.
Can anyone point me in the right direction?
I think I want to use timer1 since it is 16 bit and my events should be fast enough to be completed before any overflow occurs. I am hoping to find a simple way to set up tcnt1 to be 0 with the first interrupt and then count tcnt1 clock cycles until the second interrupt. I don't really even know how to read the values from tcnt1 though, so I have a ways to go.
I have searched for examples, but haven't really found one that seems appropriate. Everything seems to be geared towards timer interrupts which I don't think is quite what I'm after.
I am probably lacking a lot of needed understanding to use this tcnt1 counter, but any help to point me in the right direction would be greatly appreciated!
Thanks
You can try to work with timer registers directly. Look at manual for CPU which is used on your particular board. For mega it is ATmega2560-16AU. Timer register's name is TCNT1. You can store its value:
int t1;// declare global variable somewhere
t1 = TCNT1; //save timer value in ISRx interrupts
Be sure to setup prescaler value TCCR1B.CSn and handle timer overflow interrupt, else you will lose time data: ISR(TIMER1_OVF_vect)
As you can read here here precision of <1 uS can be reached.
More info of how to work directly with CPU timers registers.