Sorry if this is the wrong place to post this, I couldn't see a specific place to ask about this library?
I am building a CAN bus system and need to check for data and add it to a temporary buffer every 100ms and then every 1000ms read the buffer, decode the data into usable information and update a display.
I am currently using a hardware interrupt from the CAN controller to tell the Arduino when the data is there and then millis() to create a software timer for all my other routines.
The issue I am having is that the ECU I am reading from is broadcasting far too quickly (like every 5-10ms) for me to run all my tasks, so it literally just keeps interrupting everything!
So my thinking is I can use this library to automate the process instead of relying on hardware interrupts, but what I am trying to figure out is what happens when using two (or more) timers, when the timers come together? I.e., the first timer has an interval of 100ms and the second has a interval of 1000ms..
When the first timer gets to its 10th run, the second timer is on its first, will the order of the timers be such that the first timer runs its code, then the second timer, or will the first interrupt trigger, then will the second interrupt interrupt the first or vice versa - if there is a slight discrepancy or overlap in the code?
If the first scenario is the case then it will probably work fine, if the second scenario happens then it may or may not update the screen / read the CAN data?
I don't want to rewrite everything if this will cause me other issues! I had thought about using 101ms and 999ms but you still get a mathematical overlap!
As professional, working, now retired, the CAN bus was used in a highly safety depending environment. It can be well compared with the control of autonomous vehicles on public roads.
The central unit, the main computer issued PDO, Periodic Data Object to, f ex., drive motor, hydraulic motor. Then those motors were running for some 250 mS. If no further run message arrived, they would stop.
The central unit also used SDO, Special(?) Data object requesting data like temperature, RPM, amps, You name it.
The situation You describe is like the central unit is spammed. It sounds very confusing to me.
It's a large mobile diesel compressor. It's using a Cummins engine and ecu. It's broadcasting its data using J1939. The ecu is sending out approximately 50 PGNs on a loop, some are faster repeating that others, but the repeat time is around every 10ms for the fastest. I dont need the data this fast as I'm just monitoring the data to display on an LCD screen for the operator.
Maybe set up a 1000ms millis() timer and have the interrupt disabled most of the time. When one second is up enable interrupt, get data, reset timer, disable interrupt. Lather, rinse, repeat.
Or, just have the ISR count interrupts. On the nth one, process the interrupt, reset the counter.
Dougp, thanks for the suggestion, I have tried this method, or at least a slight variation.
#define CAN0_INT 2
int CANLoops = 100;
volatile int CANCounter = 0;
unsigned long CANFinished = 0;
unsigned long CANDelay = 1000;
void setup() {
// put your setup code here, to run once:
pinMode(CAN0_INT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CAN0_INT), InteruptCan, LOW);
}
void loop() {
// put your main code here, to run repeatedly:
if (CANCounter==101 && CANFinished+CANDelay>millis())
{
//The delay is still running, so do nothing
}
else if (CANCounter==101 && CANFinished+CANDelay<millis())
{
//The delay has completed
CANCounter=0;
CANFinished=0;
interrupts();
}
else
{
}
}
void InteruptCan()
{
if (CANCounter < CANLoops)
{
CheckCan(); //Go and run the CAN bus routine
CANCounter++ //Incremement the counter after running
}
else if (CANCounter == CANLoops)
{
noInterrupts();
CANFinished=millis()+600;
CANCounter++;
}
else
{
//Do nothing
//Shouldnt need the else, but in case!
}
}
void CheckCan()
{
/*
* Code here to read the CAN Bus
* Takes apx 600ms
*/
}
The only issue is that because I disable the interrupt in the interrupt when it exits it re-enables it automatically!!
I cant disable the interrupt in the Loop as the can data is coming in that fast that it basically never gets change to go back.
Because it takes apx 600ms to run the code to retrieve, process and store the J1939 data and each frame is coming in every 6ms it never gives it chance to stop.
So I then did this code:
#define CAN0_INT 2
int CANLoops = 100;
volatile int CANCounter = 0;
unsigned long CANFinished = 0;
unsigned long CANDelay = 1000;
void Setup()
{
}
void Loop()
{
while (digitalRead(CAN0_INT)==LOW && CANCounter<CANTrip)
{
CAN_Check();
}
}
void CAN_Check()
{
if (CANCounter < CANLoops) //If the CAN interrupt has run less than X times - gives us enough chance to capture all the data!
{
J1939_Retrieve(); //Run the code
CANCounter++; //incremement the counter
DEBUG_PRINTLN("CAN Run"); //CAN is running
}
else if (CANCounter == CANLoops)
{
CANFinished = millis(); //set the time so we know how long to pause for.
CANCounter++; //incremement the counter again so we dont keep setting the time to now!
DEBUG_PRINTLN("CAN Stopped");
}
else if (CANCounter > CANLoops && (CANFinished + CANDelay) > millis()) //now the counter is at X+1 and the current time is less than the delay time, we do nothing until after a delay
{
DEBUG_PRINTLN("CAN Wait");
}
else if (CANCounter > CANLoops && (CANFinished + CANDelay) < millis()) //now the is at X+1 and the current time is greater than the delay time, we reset the counter and we can resume
{
CANCounter = 0;
DEBUG_PRINTLN("CAN Resume");
}
}
Now it seems to be working nicely!
Obviously interrupts are no good for the task I was trying to accomplish because of how long my task takes!