teknomage:
@ edugimeno: Thank you for replying, even it's been a while since this topic came up. I did try out calling Time Interrupt clear and enable within the ISR but it just doesnt work. Bummer though, it would've been useful to have seen your code. Oh well..
@ zhomeslice: Yes, that would be great, except that in my project, I'm trying to call an I2C DAC like MCP4725 from within the Timer ISR, so that I can generate accurate sinewaves (right now, it's just sines for testing purposes). The ISR code works alright if I send the DAC output directly to Ports D & B, i.e., IF I use a Parallel DAC like DAC0808 or AD7541.. but fails miserably when using ANY form of I2C or Serial calls from within the ISR.. so, Serial or I2C DACs are out of the question?
Sorry am new here, so I guess I should post this up as a new thread maybe?
The biggest difficulty with using any of the communication requests is they need interrupts also, and so you would need to free up and allow additional interrupts to be used before leaving the current interrupt call. if your interrupt triggers again during the communication process the interrupt would create a second call to the same process.
I have created a library that uses interrupts on any port on the Arduino. This code may help answer your questions.
My example code prints within the callback. Most consider this a big no-no but it what you are asking for.
This code uses "Lambda" Anonymous Functions extensively sorry if it is confusing.
Lambda functions are being sent to callback variables which hold the pointer to the function in a variable instead of a name as we are used to. Lambda functions start with [] or [=] instead of a name and then you have the variables you wish to receive within ( ) and then the function as normal within { }
So the first callback onInterrupt is called on each and every pin change that has been enabled on any pin on the Arduino. This stores the time and checks for pin changes then calls a Lambda function which receives the time, what pins changed and all the pin states at that moment in time.
We have captured all the information needed and so we can allow additional interrupts:
sei ( ); // re-enable other interrupts at this point
****** Now we can use Serial.print() *******
Then we execute callbacks for every pin that has changed with the PinCallBack function.
Interrupt.onInterrupt([ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
sei(); // re enable other interrupts at this point,
Interrupt.PinCallBack(Time, PinsChanged, Pins);
});
More details on how to use my code below if you would decide to use it:
How does it configure the pin?
To set pins active and give them a function to use in the startup we assign a Lambda function to that pins callback
Interrupt.onPin(4, INPUT_PULLUP, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
if (Interrupt.CheckPin(4)) { // rising
Serial.println(" Pin 4 Rising \t");
} else { // Falling
Serial.println(" Pin 4 Falling \t");
}
});
The onPin function does all the work sets the pin enables the pullup if needed and assigns it a function to trigger when the callback occurs similar to the attachInterrupts() function.
If you hate lambda functions or if they are confusing you, you could easily create a function to insert it into the spot
void MyFunction (uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
if (Interrupt.CheckPin(4)) { // rising
Serial.println(" Pin 4 Rising \t");
} else { // Falling
Serial.println(" Pin 4 Falling \t");
}
}
Interrupt.onPin(4, INPUT_PULLUP, MyFunction);
just like attachInterrupts() the only difference the function must have a way to receive 3 variables: uint32_t Time, uint32_t PinsChanged, uint32_t Pins
One last note all my functions return a pointer to the class they are from so you can do call another function with just a period between.
Interrupt.onPin(7,*** Code ***). onPin(10,*** Code ***). onPin(16,*** Code ***);
Here is my example code:
This code can handle Ping ultrasound sensors, encoders RC remote control input from the RC receivers, tachometers and I'm sure more.
Hope this helps
Z
#include "Interrupts.h"
InterruptsClass Interrupt;
volatile long EncoderCounter = -2;
float microsecondsToInches(long microseconds)
{
// According to Parallax's datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return (float) microseconds / 74 / 2;
}
float microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return (float)microseconds / 29 / 2;
}
void setup() {
Serial.begin(115200); //115200
Serial.println(" testing");
// put your setup code here, to run once:
pinMode(9, OUTPUT);
Interrupt.onInterrupt([ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
sei(); // re enable other interrupts at this point,
Interrupt.PinCallBack(Time, PinsChanged, Pins);
});
Interrupt.onPin(4, INPUT_PULLUP, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
if (Interrupt.CheckPin(4)) { // rising
Serial.println(" Pin 4 Rising \t");
} else { // Falling
Serial.println(" Pin 4 Falling \t");
}
}).onPin(5, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
uint16_t RCTime = Interrupt.RCRemote(5, Time, Pins, true);
if (RCTime) {
Serial.print(" RC Time:");
Serial.print(RCTime);
}
}).onPin(6, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
unsigned int PingTime = Interrupt.Ping(6, Time, Pins);
if (PingTime) {
Serial.print("Ping \t");
Serial.print(microsecondsToCentimeters(PingTime));
Serial.println("cm");
}
});
Interrupt.onPin(9, INPUT_PULLUP, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
Serial.print("Switch \t");
Serial.println(Interrupt.Switch(9, Time, 1000, false));
}).onPin(10, INPUT_PULLUP, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
Serial.print("Switch \t");
Serial.println(Interrupt.Switch(10, Time, 1000, false));
}).onPin(11, INPUT_PULLUP, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
Serial.print("Switch \t");
Serial.println(Interrupt.Switch(11, Time, 1000, false));
}).onPin(12, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
EncoderCounter += Interrupt.Encoder(12, 13, Pins, true);
Serial.print("Count ");
Serial.print(EncoderCounter);
Serial.print("\t Encoder \t");
Serial.println(Interrupt.Encoder(12, 13, Pins, true));
}).onPin(13, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
EncoderCounter -= Interrupt.Encoder(12, 13, Pins, true);
Serial.print("Count ");
Serial.print(EncoderCounter);
Serial.print("\t Encoder \t");
Serial.println(-1 * Interrupt.Encoder(12, 13, Pins, true));
});
}
void loop() {
// put your main code here, to run repeatedly:
int t = 100;
static unsigned long _ETimer;
if ( millis() - _ETimer >= (t)) {
_ETimer += (t);
Serial.print(".");
digitalWrite(9, LOW);
delayMicroseconds(1);
digitalWrite(9, HIGH); // Trigger another pulse
delayMicroseconds(10);
digitalWrite(9, LOW);
}
}
Interrupts.cpp (6.5 KB)
Interrupts.h (5.54 KB)