This is running on an ATTINY84. I am stumped in that the statusMask variable is not ever being set by the main loop, though I know for a fact the interrupts are being called because a diagnostic LED tell's me so, I have ran the diagnostic LED in every conceivable spot, and the one place I never get a response is inside of if (statusMask), which makes no sense because the interrupt does indeed get triggered, any ideas?
#include <PinChangeInterrupt.h>
/*
MatCat Airplane Lighting Contoller
PWM and I2C connectivity to drive 3 channels of lighting.
This code is open source and free to be used by whomever
for non-commercial purposes. Please keep the proper
copyright when distributing this code, thank you!
*/
// PWM Outputs
unsigned int headlights = 2;
unsigned int navlights = 3;
unsigned int floodlights = 4;
// PWM Inputs
unsigned int headlightInput = 5;
unsigned int navlightInput = 6;
unsigned int floodlightInput = 7;
// Operational Parameters
int strobeFrequency = 1000; // 1 second between pulses
int strobeLength = 30; // 30ms strobe length
int strobeBreak = 50; // 50ms break between fast pulses
volatile byte headlightLevel = 0; // Output buffer level for headlights
volatile byte navlightLevel = 0; // Output buffer level for navlights
volatile byte floodlightLevel = 0; // Output buffer level for floodlights
volatile uint16_t oldHeadLevel = 0; // Old lighting level
volatile uint16_t oldNavLevel = 0;
volatile uint16_t oldFloodLevel = 0;
volatile uint8_t oldHeadOut = 0;
volatile uint8_t oldNavOut = 0;
volatile uint8_t oldFloodOut = 0;
// Bit mask for keeping track of whats going on
static uint8_t HEADLIGHT_FLAG = 1;
static uint8_t NAVLIGHT_FLAG = 2;
static uint8_t FLOODLIGHT_FLAG = 4;
static uint8_t I2C_FLAG = 8; // Indicates the usage of I2C over PWM
uint8_t hasBound = 0; // A variable to keep track of being bound
volatile uint8_t statusMask; // This is the actual mask variable
// Timers to keep track of pulse widths
volatile unsigned long headlightTimer = 0;
volatile unsigned long navlightTimer = 0;
volatile unsigned long floodlightTimer = 0;
// Timers for other operations
unsigned long lastStrobeTime; // Used for strobe timing
unsigned long lastFrameTime; // When was the last PWM frame?
unsigned int secondTime; // A special timer for measuring a second
uint8_t rxFrequency = 0; // Rated in HZ, normal is 50
uint16_t frameCount = 0; // Count of frames per second
void setup() {
// Setup inputs
pinMode(headlightInput, INPUT);
pinMode(navlightInput, INPUT);
pinMode(floodlightInput, INPUT);
// Setup outputs
pinMode(headlights,OUTPUT);
pinMode(navlights,OUTPUT);
pinMode(floodlights,OUTPUT);
// Setup a few variables
lastStrobeTime = millis();
secondTime = millis();
// Let's do a little init. routine
strobeLight(headlights,160,100);
delay(100);
strobeLight(navlights,160,100);
delay(100);
strobeLight(floodlights,160,100);
delay(500);
for (int a = 0; a < 5; a++) {
strobeAll(160,160,160,30);
delay(100);
}
// Ok now let's setup some interupts
attachPcInterrupt(headlightInput,headlightOn,RISING);
attachPcInterrupt(headlightInput,headlightOff,FALLING);
attachPcInterrupt(navlightInput,navlightOn,RISING);
attachPcInterrupt(navlightInput,navlightOff,FALLING);
attachPcInterrupt(floodlightInput,floodlightOn,RISING);
attachPcInterrupt(floodlightInput,floodlightOff,FALLING);
}
void loop() {
// Setup some local variables for reading
// the values set by interrupts.
static uint16_t headLevel = 0;
static uint16_t navLevel = 0;
static uint16_t floodLevel = 0;
static uint8_t flagmask = 0;
static uint8_t updateFlag = 0;
static long frameTime = 0;
static uint8_t secondFlag = 0;
static uint8_t strobeFlag = 0;
if (statusMask) {
// We need to update what's going on.
noInterrupts();
flagmask = statusMask;
if (flagmask & HEADLIGHT_FLAG) {
// Headlights have been updated
if (headlightLevel != oldHeadLevel) {
headLevel = headlightLevel;
oldHeadLevel = headLevel;
updateFlag |= HEADLIGHT_FLAG;
}
// Let's capture the frame time for calculation later
frameTime = (uint16_t)(micros() - lastFrameTime);
lastFrameTime = micros();
}
if (flagmask & NAVLIGHT_FLAG) {
// Navs have been updated
if (navlightLevel != oldNavLevel) {
navLevel = navlightLevel;
oldNavLevel = navLevel;
updateFlag |= NAVLIGHT_FLAG;
}
}
if (flagmask & FLOODLIGHT_FLAG) {
// Floods have been updated
if (floodlightLevel != oldFloodLevel) {
floodLevel = floodlightLevel;
oldFloodLevel = floodLevel;
updateFlag |= FLOODLIGHT_FLAG;
}
}
// We need to clear the status flags from interrupts
statusMask = 0;
interrupts();
}
// Let's handle the second timer.
if ((millis() - secondTime) >= 1000) {
// A second has passed, reset the timer
secondTime = millis();
secondFlag = 1;
}
// Let's handle the strobe timer.
if ((millis() - lastStrobeTime) >= strobeFrequency) {
// We need to do a strobe...
lastStrobeTime = millis();
strobeFlag = 1;
}
if (frameTime > 0) {
// It's a new frame from the RX, let's do some math
frameCount++; // Add to frame count
if (secondFlag) {
// The frameCount variable will tell us, should be close to 50
rxFrequency = frameCount;
frameCount = 0; // Reset it
}
}
if (rxFrequency > 30) {
// We probably have a valid PWM signal, so consider it bound
hasBound = 1;
} else {
// Either we are not bound or lost bound...
hasBound = 0;
}
if (!hasBound) {
// We need to continue looking for an input...
strobeLight(headlights,50,15); // Indicate looking for PWM
delay(50);
strobeLight(navlights,50,15); // Indicate looking for PWM
delay(50);
strobeLight(navlights,50,15); // Indicate looking for PWM
delay(50);
strobeLight(navlights,50,15); // Indicate looking for PWM
delay(50);
strobeLight(navlights,50,15); // Indicate looking for PWM
delay(500);
} else {
// We are bound, so let's do what needs to be done
// First we need to see if any of the levels need to be adjusted...
uint8_t headOut = oldHeadOut;
uint8_t navOut = oldNavOut;
uint8_t floodOut = oldFloodOut;
// Before we output the the power, we need to check if we have to strobe...
if (strobeFlag) {
// We need to do some strobing before actually setting the output
strobeAll(255,255,255,strobeLength);
}
if (updateFlag & HEADLIGHT_FLAG) {
// We need to change output of headlights
headOut = map(headLevel,1000,2000,0,255);
if (headOut < 40) {headOut = 0;}
if (headOut > 210) {headOut = 255;}
oldHeadOut = headOut;
analogWrite(headlights,headOut);
}
if (updateFlag & NAVLIGHT_FLAG) {
// We need to change output of headlights
navOut = map(navLevel,1000,2000,0,255);
if (navOut < 40) {navOut = 0;}
if (navOut > 210) {navOut = 255;}
oldNavOut = navOut;
analogWrite(navlights,navOut);
}
if (updateFlag & FLOODLIGHT_FLAG) {
// We need to change output of headlights
floodOut = map(floodLevel,1000,2000,0,255);
if (floodOut < 40) {floodOut = 0;}
if (floodOut > 210) {floodOut = 255;}
oldFloodOut = floodOut;
analogWrite(floodlights,floodOut);
}
}
}
void strobeXTimes(int x) {
for (int a = 0;a < x;a++) {
strobeLight(headlights,255,20);
delay(50);
}
}
void strobeAll(byte valuehead,byte valuenav, byte valueflood, int duration) {
analogWrite(headlights,valuehead);
analogWrite(navlights,valuenav);
analogWrite(floodlights,valueflood);
delay(duration);
analogWrite(headlights,oldHeadOut);
analogWrite(navlights,oldNavOut);
analogWrite(floodlights,oldFloodOut);
}
void strobeLight(int light,byte value,int duration) {
analogWrite(light,value);
delay(duration);
if (light == headlights) {
analogWrite(light,oldHeadOut);
}
if (light == navlights) {
analogWrite(light,oldNavOut);
}
if (light == floodlights) {
analogWrite(light,oldFloodOut);
}
}
void headlightOn() {
// Do something when we have headlight PWM coming in...
headlightTimer = micros();
}
void headlightOff() {
// Do something when we have headlight PWM Pulse finished...
headlightLevel = (uint16_t)(micros() - headlightTimer);
statusMask |= HEADLIGHT_FLAG;
}
void navlightOn() {
navlightTimer = micros();
}
void navlightOff() {
navlightLevel = (uint16_t)(micros() - navlightTimer);
statusMask |= NAVLIGHT_FLAG;
}
void floodlightOn() {
floodlightTimer = micros();
}
void floodlightOff() {
floodlightLevel = (uint16_t)(micros() - floodlightTimer);
statusMask |= FLOODLIGHT_FLAG;
}