Hi there! I have a mega arduino and want to assign a function to one of the higher timers. I believe it has a few more compared to a normal arduino. My goal is to attach a canbus message via interrupt to a timer. Its okay to interrupt most other functions but its very very important to send messages out every 50ms or so. I think this is the proper solution to this problem? Im open to alternatives. Also im using a canbus shield and touchscreen shield. Im currently under the impression i cant make yse of the first 3 timers which prohibits use of the very well done timer3 library
For here I'm going to guess....
ISR(TIMER6_OVF_vect)
{
....
}
agentgengar:
Im open to alternatives.
50ms is a glacial time scale, slow enough that it could easily be done using millis()-based timing.
If you are doing any other CANbus I/O it is probably not safe to have an interrupt send a message in the middle of another message.
Thankfully I'm not. Its not reading anything at all. Its literally just sending messages out.
And Yes, I would use millis() except if I understand it correctly, issue is some other tasks that I have it doing sometimes take too long depending on what it has stacked up with. millis() doesnt send it out when it is up. But instead sends it out when it comes to do a check if x>y. Cases where functions take much longer such as reading GPS serial information or requesting information from a thermometer throw things out of whack
The arduino is driving an instrument panel intended for a vehicle. Its primary focus should be keeping all gauges running smoothly via pushing messages. Depending on the message, if the instrument panel doesnt see it for x amount of time it complains and throws errors. I am ok with information being delayed up to even 2000ms assuming certain functions are getting interrupted and preventing them from updating.
agentgengar:
Cases where functions take much longer such as reading GPS serial information or requesting information from a thermometer throw things out of whack.
Reading GPS data is generally done one character at a time as characters arrive. There is no need to wait. The GPS library (TinyGPS or TinyGPS++) will tell you when new data is available.
Reading a thermometer doesn't require you to wait. Request the temperature and set a timer to read it later when the data is available.
If anything you do takes more than a millisecond (16000 instruction cycles) then you are likely doing it wrong.
This is how I am currently fetching GPS data. But it doesnt seem to wait, it seems to just constantly spit out data and I have to "Catch" the first serial coming out otherwise it doesnt register it correctly. I'm assuming Im doing this wrong?
while (GPSSerial.available())
gps.encode(GPSSerial.read());
if (gps.time.isUpdated())
{
//serial.println("GPS update stored!");
GPSUpdated = true;
break;
}
And this is how I'm requesting for thermometer data. Where would I break it like you're suggesting? and return later to capture the prepared data?
Also, Thank you very much for your advice. I suspected I might be doing things wrong but I've struggled pinpointing what exactly needed improving.
byte i;
byte present = 0;
byte type_s;
byte data[12];
float celsius, fahrenheit;
long start = millis();
ds.reset();
ds.select(ThermometerSensor);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
present = ds.reset();
ds.select(ThermometerSensor);
ds.write(0xBE); // Read Scratchpad
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x00);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
void loop()
{
while (GPSSerial.available())
gps.encode(GPSSerial.read());
if (gps.time.isUpdated())
{
//serial.println("GPS update stored!");
GPSUpdated = true;
break;
}
}
One possible change is to change the 'while' to an 'if' so that only one character is processed per loop(). You also don't check the result of gps.encode(). It returns 'true' if that character completed a message. If it returns 'false' there has been no new message so there is no need to call gps.time.isUpdated(). You also have a 'break;' that is not inside the 'while' so I don't think it does anything.
I think you want something like this:
void loop()
{
// Note: A feature of C/C++ is that if the left side of an '&&' is 'false', the right side won't be evaluated
// In this case, GPSSerial.read() won't get called unless GPSSerial.available() returns != 0 (a.k.a. 'true')
if (GPSSerial.available() && gps.encode(GPSSerial.read()))
{
// We have received a full message so there MIGHT be updates.
if (gps.time.isUpdated())
{
//serial.println("GPS update stored!");
GPSUpdated = true;
break;
}
}
}
Note: For the DS18B20 One-Wire temperature sensors there is a 3/4-second delay between the time you request a conversion and the time the data is available. I would use a millis() timer to fetch the temperature at some interval greater than 750 milliseconds. After reading the scratchpad you can then request another conversion and the new data will be ready the next time you go to read the scratchpad.
There is no TIMER6. You get timer0 through timer5...
Problem I think I'm having with GPS is that the .encode function is looking for a full message perhaps by itself? Unfortunately I dont understand much how the tinygps++ library operates. I know when I make more frequent requests the success goes up. I tried reading the reliable serial communications for beginners and couldnt come to a simple conclusion on how to reliably clip the serial data coming in. First character is always $ but it has a checksum at the end that I dont understand how its totaled. If the serial.encode sees what it thinks is corrupt GPS data it tosses it out (Correct me if I'm wrong this is all just what I've attempted to learn myself).
The clip of code is part of a slightly bigger piece of code where I wrote in a millis() break away. Fetching GPS data was so unreliable, the best way I personally could solve it was by allowing it to loop and attempt how ever many times it could. Loop was controlled by a millis() operation as not to lock up the arduino incase the GPS failed for any reason and allow it to return to other operations. My apologies, I know its generally bad practice to not post the entire code, But I felt for purposes of going for the "one shot one kill" method of reading the serial it wasnt important. My apologies if it causes any frustration.
And I see! Is that where the large delay is coming from on the thermometer? I managed to get the timing down to about 20ms for a request with my clip of code there. But 20ms is still a large amount of time (Im assuming this is request being sent, thermometer preparing data, and sending request back and not actually any arduino processing/looping issues)
And @westfw My bad! Thats correct. I forgot it starts at 0. I just remembered that Mega has a total of 6 timers. Thank you for the correction