For some reason the millis() function does not give me a output when called in a header file. I tried to print it out on the serial monitor but it gives me a blank output, even though when called in the main file it works just fine. I'm trying to create a IR decoding library from scratch as a learning exercise and and using the millis() and micro() functions to decode the signials, but as stated earlier its not working.
unsigned long RUNTIM = millis();
Serial.println(RUNTIM);
which outputs a blank line.
Heres the all of the code:
main fill:
#include <Arduino.h>
#include <decode.h>
const int RECV_PIN = 2;
REC RCVPIN(RECV_PIN);
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
REC::begin();
}
void loop() {
// put your main code here, to run repeatedly:
delay(5000);
Serial.println(millis());
}
// put function definitions here:
decoding libary (called decode.h, not in the same directory as main file):
#include <Arduino.h>
unsigned long PREVTIM;
unsigned long RUNTIME;
const long NECTIME = 9000;
const long NECWAIT = 4500;
byte inPin;
class DECODE {
public:
static void DECSTART() { //turns off inturputs and starts the start process
noInterrupts();
RUNTIME = millis();
Serial.println("MADE IT");
start();
}
private:
static void start(){ // decdies if its NEC or not if it is it goes on to decode
PREVTIM = millis();
while(RUNTIME - PREVTIM < 9){
Serial.print("Made it to while");
if(digitalRead(inPin) == 1 && RUNTIME - PREVTIM >=8 && RUNTIME - PREVTIM <=9) { //NEC has a intial pulls of 9mil second makes sure that true
NECDEC();
PREVTIM = millis();
}
}
}
static void NECDEC()
{
RUNTIME = millis();
if(RUNTIME - PREVTIM <= 4550 && RUNTIME - PREVTIM >= 4450)
{
Serial.println("start decode");
}
}
};
class REC {
public:
REC(const int a) {
inPin = a;
}
static void begin() {
Serial.println("Began");
attachInterrupt (digitalPinToInterrupt(inPin), DECODE::DECSTART, LOW) ;
if (inPin >=8){
PCICR |= B00000001;
}
}
};
It gets to the while loop and stops, and it wont print out any variables related to the runtime so its incredibly hard to debug. Anyone know why the runtime functions aren't working?
EDIT:
For any future readers of this forum using micros() was no the whole solution. The micros() function still uses interrupts and will stop working 1-2ms after you enter a ISR (interrupt service routine) since it prevents other interrupts so the correct solution was to not do the signal processing in the ISR since it would take around 4.5ms on the first initial pulse, rather record time, then check them off of the previous interrupt times taking the ISR's runtime down to a couple of microseconds which prevents most of the issues I had as of yet. Ill post the whole solution when it is finished through a GitHub link.
tldr; Keep ISR runtimes very short, and don't turn off global interrupts bad things start happening.
Placing serial print statements @9600 might not be the wisest thing to do when clocking data.
Did something similar a while back:
#include "IRremoteNEC.h"
//=============================================================================
//IR remote
//NEC - IR code
//By: LarryD, Huge thanks to Jack Christensen
//
//For the remote control, see: http://goo.gl/nvDuhD
//
//"IRremoteNEC.cpp IRremoteNEC.h"
// PERMISSION TO DISTRIBUTE
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software
// and associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// LIMITATION OF LIABILITY
// The software is provided "as is", without warranty of any kind, express or implied,
// including but not limited to the warranties of merchantability, fitness for a particular
// purpose and noninfringement. In no event shall the authors or copyright holders be liable
// for any claim, damages or other liability, whether in an action of contract,
// tort or otherwise, arising from, out of or in connection with the software
// or the use or other dealings in the software.
//
//IRremoteNEC.cpp(.h) - A class to retrieve IR commands from 44/17 Button IR Remote
//Tested with Arduino IDE 1.06 on an UNO
//
// Rev 1.00 January 25, 2015 functional code
// Rev 1.01 February 1, 2015 created the library files IRremoteNEC.cpp and .h
//
//=============================================================================
//*****************************************************************************
void irISR(void);
//======== VARIABLES USED BY THE ISR -- Must be accessed atomically!
volatile byte irFlag; //a flag stating we have seen an edge
volatile unsigned long thisMicros; //time the current edge happened
//======== LOCAL COPIES OF ISR VARIABLES ========
unsigned long thisMicrosLocal;
//
//*****************************************************************************
// c l a s s I R r e m o t e N E C
//*****************************************************************************
//Constructor
IRremoteNEC::IRremoteNEC(byte IRpin)
{
IRpin_ = IRpin;
} // END of IRremoteNEC()
//**********************************************************
//Initialization
void IRremoteNEC::beginIR()
{
pinMode(IRpin_, INPUT_PULLUP);
counter = 0;
validStart = false;
thisMicrosLocal = micros();
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
thisMicros = thisMicrosLocal;
}
irFlag = 0;
//We must convert the pin # to the interrupt # (i.e. 2-2=0 or 3-2=1)
attachInterrupt (IRpin_ - 2, irISR, FALLING); // attach IR interrupt handler using D2 or D3
} // END of beginIR()
//**********************************************************
//Return the current state of the interrupt flag.
byte IRremoteNEC::getIRflag()
{
return irFlag;
} // END of getIRflag()
//**********************************************************
//Reset the state of the interrupt flag.
void IRremoteNEC::resetIRflag()
{
irFlag = 0;
} // END of resetIRflag()
//**********************************************************
//Handle falling edge detection, return IR code if a valid one exists.
//NOTE: IR remote "repeat" codes are ignored and not returned.
byte IRremoteNEC::checkCode()
{
byte byteRecived = 0; //returned variable to the CALLing code
byte rxBit = 0; //the value of the received bit
//Calculate the time between the last two falling edges.
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
thisMicrosLocal = thisMicros;
}
unsigned long temp = thisMicrosLocal - lastMicros;
//For the next iteration, save the edge time, which just happened.
lastMicros = thisMicrosLocal;
//Are we over the start bit upper limit of 13.8mS for the 44/17 button IR remote code?
if (temp > 13800)
{
//There must have been quite some time since the last falling edge.
//Save the current time (beginning time) as the starting edge for this message.
startMillis = millis();
}
//One complete message is (measured 67.5mS) ~75mS long.
//If we go over this, reset things i.e. get ready for the next message.
//As a benefit this removes (ignores) any repeat codes that come in.
else if(millis() - startMillis > 75)
{
//Too much time has elapsed since the first edge of the message.
//Start over.
validStart = false;
}
//Are we inside the limit of the start bit: (measured 13480) 13200uS to 13800uS
else if((validStart == false) && (temp > 13200))
{
//This is a valid start time
counter = 0;
validStart = true;
//4 bytes are coming, initialize their storage.
data[0] = 0;
data[1] = 0;
data[2] = 0;
data[3] = 0;
}
//Are we into data bits: (measured 1130) 900 to 1300uS is a 0 bit,
//(measured 2250), 2000 to 2500uS is a 1 bit.
else if((validStart == true) && (temp > 900) && (temp < 2500))
{
//Is this bit a 1?
if(temp > 2000)
{
rxBit = 1;
}
//Is this bit a 0?
else if(temp < 1300)
{
rxBit = 0;
}
//Timing was not valid!
else
{
//The bit width was not within the above range, start over.
validStart = false;
counter = 0;
}
//Put this bit in the correct position in the current byte.
//example: let us say we are doing bit 19
// data[19/8 is byte 2] |= rxBit << (19%8 gives a shift of 3))
// data[2] = data[2] | rxBit << 3
data[counter/8] |= (rxBit << (counter%8));
//Have we received all the bits yet? (0-31 is 32 bits)
if(counter >= 31)
{
//This remote always sends: 0x00 as Address and 0xFF as ~Address
//Example: 0x00 0xFF 0x04 0xFB would be a valid message
//Was this a valid IR code? i.e. Address = ~Address && Data = ~Data
if((data[0] == (~data[1] & 0xFF)) && (data[2] == (~data[3] & 0xFF)))
{
//data[2] contains the valid IR button code
byteRecived = data[2];
}
//We are now finished with this IR code, get ready for the next valid start.
validStart = false;
} //END of if(counter >= 31)
//Get ready for the next bit.
counter++;
} //END of if(validStart == true && (temp > 900) && (temp < 2500))
return byteRecived; //If zero (0) there is no valid IR button code
} // END of checkCode()
//=============================================================================
// H E L P E R F U N C T I O N S
//=============================================================================
//*****************************************************************************
// Interrupt Service Routine (ISR)
void irISR()
{
thisMicros = micros(); //record the time the edge happened
irFlag = 1; //Flag that we have seen a falling edge
} // END of irISR()
//*****************************************************************************
millis() uses interrupts, so you cannot use it for timing when you have interrupts disabled.
Serial itself will operate without interrupts, but usually not recommended.
How are you using millis() and Serial.print() in the header file? Serial.begin() needs to be called before you can use Serial, and millis() itself may not yet be initiated.
I see. So instead of using regular interrupts I should use pin change interrupts? Dunno how its working without serial.begin(), but it does work and its only there for debbuging atm. I'm not sure what to use for decoding them besides the millis and micros function unless i write my own runtime function I don't have many options to my knowledge.
no, you just shouldn't turn off interrupts.
Anyway, switching off interrupts for long time is not a good idea.
In your code you turn off interrupts in the DECSTART() routine and never turn it on again.