SimpleThings:
Do you have embedded C example,
since I write most of my code for Arduino in C, with some arduino functions.
I would like if someone could explain it to me how do I implement ISRs with C++, I am not a C++ expert and I rarely use it. Primarly C and java.
I simplified it more Added lots of notes and placed everything into a sketch for you it is set to be with a ping sensor hcsro04
trigger is on pin 7
echo is on pin 8
The code is a single sketch. I removed all Lambda other confusing parts.
It does use Callbacks just like attachInterrupt() does only difference is that I pass several variables to the functions
static void nothing(void) {};
typedef void (*voidFuncPtr)(uint32_t, uint32_t, uint32_t); // Create a type to point to a funciton.
typedef void (*voidFuncTimerPtr)();// Create a type to point to a funciton.
volatile voidFuncPtr Int_CB = nothing;
union Mask {
volatile uint32_t All;
volatile uint8_t Port[4];
};
Mask _Pins;
volatile uint32_t _PinMask; //volatile uint8_t rcPinMask[3]; //Pin Mask for active RC Pins
volatile uint32_t _PCintLast; //volatile uint8_t PCintLast[3]; // looking fo pin changes using bianary
/************ static functions common to all instances ***********************/
// port change Interrupt
void ISR_Exe(void);
ISR(PCINT2_vect) { //this ISR pins 0-7
ISR_Exe();
}
ISR(PCINT1_vect) { //this ISR s A0~A5
ISR_Exe();
}
ISR(PCINT0_vect) { //this ISR is common to every receiver channel, it is call everytime a change state occurs on a pins 8-13 only need 9-11
ISR_Exe();
}
void ISR_Exe() {
_Pins.Port[0] = PIND; // 0-7
_Pins.Port[1] = PINB; // 8-13
_Pins.Port[2] = PINC; // A0-A6
uint32_t _cTime = micros();
_Pins.Port[3] = 1; // Placeholder
uint32_t _Changed = _Pins.All ^ _PCintLast;// doing a ^ between the current interruption and the last one indicates wich pin changed
uint32_t _Masked = _Changed & _PinMask;// Has one of the pins we need changed
if (!_Masked)return; //No Data move on
if (Int_CB) {
Int_CB(_cTime, _Masked, _Pins.All); // Callback Function
}
_PCintLast = _Pins.All; // we memorize the current state of all PINs in group
}
class InterruptsClass {
public:
// Interrupts();
uint8_t BitNumber[20] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21}; // Key = Pin Val = Position List of pins that could be used as ping inputs:
static void nothing(void) {};
typedef void (*voidFuncPtr)(uint32_t, uint32_t, uint32_t); // Create a type to point to a funciton.
voidFuncPtr PinCB[20] = {nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing}; // Key = Pin Val = Position List of pins that could be used as ping inputs:
void AddPin(uint8_t pin, uint8_t InputType = INPUT);
void onInterrupt(void (*CB)(uint32_t, uint32_t, uint32_t));
void onPin(int Pin, int InputType, void (*CB)(uint32_t, uint32_t, uint32_t));
void PinCallBack(uint32_t Time, uint32_t PinsChanged, uint32_t Pins);
bool CheckPin(uint8_t Pin);
volatile uint32_t EdgeTime[20]; // Time Storage
// Ping
volatile int16_t Ping(uint8_t Pin, uint32_t cTime, uint32_t Pins);
};
/****************** end of static functions ******************************/
// Install Pin change interrupt for a pin, can be called multiple times
void InterruptsClass::AddPin(uint8_t Pin, uint8_t InputType) {
pinMode(Pin, InputType);// enable interrupt for pin...
if (bitRead(_PinMask, Pin))
bitWrite(_PinMask, BitNumber[Pin], 1);
*digitalPinToPCMSK(Pin) |= bit (digitalPinToPCMSKbit(Pin)); // enable pin
PCIFR |= bit (digitalPinToPCICRbit(Pin)); // clear any outstanding interrupt
PCICR |= bit (digitalPinToPCICRbit(Pin)); // enable interrupt for the group
}
void InterruptsClass::onInterrupt(void (*CB)(uint32_t, uint32_t, uint32_t)) {
Int_CB = CB;
}
void InterruptsClass::onPin(int Pin, int InputType, void (*CB)(uint32_t, uint32_t, uint32_t)) {
AddPin( Pin, InputType);
PinCB[Pin] = CB;
}
void InterruptsClass::PinCallBack(uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
for (byte Pin = 0; Pin < 20; Pin++) {
if (bitRead(PinsChanged, Pin)) {
if (PinCB[Pin]) {
PinCB[Pin](Time, PinsChanged, Pins);
}
}
}
}
bool InterruptsClass::CheckPin(uint8_t Pin) {
return (bitRead(_Pins.All, Pin));
}
volatile int16_t InterruptsClass::Ping(uint8_t Pin, uint32_t cTime, uint32_t Pins) {
if (CheckPin(Pin)) {
EdgeTime[Pin] = cTime; //Pulse went HIGH store the start time
return (0);
} else { // Pulse Went low calculate the duratoin
uint16_t dTime = cTime - EdgeTime[Pin]; // Calculate the change in time
return (dTime); // Lets send any duration up to 65535 micro seconds
}
}
InterruptsClass Interrupt;
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 AnyInterruptCallbackFunction(uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
sei(); // re enable other interrupts at this point, Makes it so we can print from interrupts if we don't go crazy and call them too much!!!!
Interrupt.PinCallBack(Time, PinsChanged, Pins); //Something triggered an interrupt lets see what it was
}
void UltrasonicPingCallback(uint32_t Time, uint32_t PinsChanged, uint32_t Pins) { //connect the echo pin to pin 8 and pin 7 will be the trigger
unsigned int PingTime = Interrupt.Ping(8, Time, Pins);
if (PingTime) {
Serial.print("Ping \t");
Serial.print(microsecondsToCentimeters(PingTime));
Serial.println("cm");
}
}
/*
void UltrasonicPingCallbackPin9(uint32_t Time, uint32_t PinsChanged, uint32_t Pins){ //connect the echo pin to pin 8 and pin 7 will be the trigger
unsigned int PingTime = Interrupt.Ping(9, Time, Pins);
if (PingTime) {
Serial.print("Ping \t");
Serial.print(microsecondsToCentimeters(PingTime));
Serial.println("cm");
}
}
*/
void setup() {
Serial.begin(115200); //115200
pinMode(7, OUTPUT); // for ping trigger
Interrupt.onInterrupt(AnyInterruptCallbackFunction); // basic trigger for all other functions it calls the function AnyInterruptCallBackFunction on all interrupts
Interrupt.onPin(8, INPUT, UltrasonicPingCallback); // Setup interrupt on pin 8, it is a standard INPUT rathere than one with pullup (INPUT_PULLUP) and wee are calling this function each time the interrupt is triggered: UltrasonicPingCallback
// Add as many pins as you would like just make a function to use the same pin
// Interrupt.onPin(9, INPUT, UltrasonicPingCallbackPin9); // Setup interrupt on pin 9, it is a standard INPUT rathere than one with pullup (INPUT_PULLUP) and wee are calling this function each time the interrupt is triggered: UltrasonicPingCallbackPin9
}
void loop() {
// put your main code here, to run repeatedly:
int t = 100;
static unsigned long _ETimer;
if ( millis() - _ETimer >= (t)) {
_ETimer += (t);
digitalWrite(7, LOW);
delayMicroseconds(1);
// digitalWrite(7, HIGH); // Trigger another pulse for ping sensor trigger on pin 7
delayMicroseconds(5);
digitalWrite(7, LOW);
}
}
Z