Hallo liebe Community!
Ich habe ein Problem mit einem meiner Codes.
Konkret geht es dabei eigentlich nur um ein Upgrade eines Codes, den ich bereits vor einem Jahr geschrieben habe und nun ein wenig erweitern wollte.
Letztes Jahr hab ich für mein Kind ein Nachtlicht mit einem attiny85 gebaut. Das hat auf einen angeschlossenen PIR-Sensor reagiert und sobald es an war, hat der Watchdog immer nachgesehen, ob der PIR immer noch meldet, ansonsten das Licht wieder ausgeschalten. Hat bislang prima funktioniert.
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
const byte LED = 0;
const byte SWITCH = 2;
const byte LUM = A3;
const byte LUMPOWER = 4;
byte ledPWM = 0;
const byte minPWM = 30;
const byte maxPWM = 255;
const int lumLimit = 200;
const int lumThreshold = 50;
ISR (PCINT0_vect) {
// Do something interesting here
}
ISR (WDT_vect) {
wdt_disable();
digitalWrite(LUMPOWER, HIGH);
}
void setup () {
resetWatchdog ();
pinMode (LED, OUTPUT);
pinMode (SWITCH, INPUT);
pinMode (LUMPOWER, OUTPUT);
for ( int flashCount = 0; flashCount < 3; flashCount++ ) {
for (ledPWM; ledPWM<maxPWM; ledPWM++ ) {
analogWrite(LED,ledPWM);
delay(10);
}
for (ledPWM; ledPWM>0; ledPWM-- ) {
analogWrite(LED,ledPWM);
delay(10);
}
delay(250);
}
digitalWrite(LUMPOWER, HIGH);
PCMSK |= bit (PCINT2);
GIFR |= bit (PCIF);
GIMSK |= bit (PCIE);
}
void loop () {
bool switchValue = digitalRead(SWITCH);
int lumValue = analogRead(LUM);
if ( switchValue == HIGH && lumValue <= lumLimit && ledPWM < maxPWM ) {
ledPWM++;
analogWrite(LED, ledPWM);
delay(10);
}
else if ( ( switchValue == LOW || lumValue > ( lumLimit + lumThreshold ) ) && ledPWM > 0 ) {
ledPWM--;
analogWrite(LED, ledPWM);
delay(10);
}
else if ( switchValue == LOW && ledPWM == 0 ) {
digitalWrite(LUMPOWER, LOW);
goToSleep();
digitalWrite(LUMPOWER, HIGH);
}
else {
goToWDTSleep();
}
}
void goToSleep () {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
byte keepADCSRA = ADCSRA;
ADCSRA = 0;
power_all_disable ();
noInterrupts ();
sleep_enable ();
interrupts ();
sleep_cpu();
sleep_disable();
power_all_enable();
ADCSRA = keepADCSRA;
}
void goToWDTSleep() {
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
byte keepADCSRA = ADCSRA;
ADCSRA = 0;
power_all_disable();
noInterrupts ();
resetWatchdog();
sleep_enable();
interrupts ();
sleep_cpu ();
sleep_disable();
power_all_enable();
ADCSRA = keepADCSRA;
}
void resetWatchdog () {
MCUSR = 0;
WDTCR = bit (WDCE) | bit (WDE) | bit (WDIF);
WDTCR = bit (WDIE) | bit (WDP2) | bit (WDP1);
wdt_reset();
}
Jetzt wollte ich das ganze Licht ein wenig erweitern, damit es auch über einen Taster händisch eingeschalten werden kann und hab den Code entsprechend umgeschrieben. Also Taster als PCInterrupt mit hinein gehängt, entsprechende Modi eingerichtet und dann auch noch dem µC die Aufgabe übergeben, sich um die Länge der Einschaltdauer zu kümmern (da jetzt ein anderer PIR verwendet wird).
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
const byte LED = 0;
const byte PIR = 2;
unsigned int pirTrigger = 0;
unsigned int pirTimeout = 30;
const byte LUM = A2;
const byte LUMPOWER = 3;
const int lumLimit = 200;
const int lumThreshold = 50;
const byte BUTTON = 1;
byte ledPWM = 0;
byte currentMode = 0;
unsigned long lastButtonPress = 0;
ISR (PCINT0_vect) {
noInterrupts();
}
ISR (WDT_vect) {
wdt_disable();
}
void setup() {
resetWatchdog();
pinMode (LED, OUTPUT);
pinMode (PIR, INPUT);
pinMode (LUM, INPUT);
pinMode (LUMPOWER, OUTPUT);
pinMode (BUTTON, INPUT_PULLUP);
for ( int flashCount = 0; flashCount < 3; flashCount++ ) {
while (ledPWM<255)
rampUpDown(1,5);
while (ledPWM>0)
rampUpDown(0,5);
digitalWrite(LED, LOW);
delay(250);
}
// PCMSK |= bit (PCINT1);
// PCMSK |= bit (PCINT2);
PCMSK = 0b000000110;
GIFR |= bit (PCIF); // clear any outstanding interrupts
GIMSK |= bit (PCIE); // enable pin change interrupts
}
void loop() {
if ( digitalRead(BUTTON) == LOW ) {
if ( millis() - lastButtonPress > 500 ) {
if ( currentMode < 2 )
currentMode++;
else
currentMode = 0;
lastButtonPress = millis();
}
if ( currentMode == 2 ) {
digitalWrite(LUMPOWER, HIGH);
for ( byte counter = 0; counter < 3; counter++ ) {
while (ledPWM<255)
rampUpDown(1,1);
while (ledPWM>0)
rampUpDown(0,1);
}
}
}
if ( currentMode == 0 ) {
if ( ledPWM > 0 ) {
rampUpDown(0,10);
}
else {
goToSleep();
}
}
if ( currentMode == 1 ) {
if ( ledPWM < 255 ) {
rampUpDown(1,10);
}
else {
goToSleep();
}
}
if ( currentMode == 2 ) {
bool pirValue = LOW;
if ( digitalRead(PIR) == HIGH ) {
pirTrigger = 0;
}
if ( pirTrigger < pirTimeout ) {
pirValue = HIGH;
if ( ledPWM == 255 )
pirTrigger++;
}
int lumValue = analogRead(LUM);
if ( pirValue == HIGH && lumValue <= lumLimit && ledPWM < 255 )
rampUpDown(1,10);
else if ( ( pirValue == LOW || lumValue > ( lumLimit + lumThreshold ) ) && ledPWM > 0 )
rampUpDown(0,10);
else if ( pirValue == LOW && ledPWM == 0 ) {
digitalWrite(LUMPOWER, LOW);
goToSleep();
digitalWrite(LUMPOWER, HIGH);
}
else {
goToWDTSleep();
}
}
#endif
} // end of loop
void goToSleep() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
byte keepADCSRA = ADCSRA;
ADCSRA = 0;
power_all_disable();
noInterrupts();
if ( useWDT == 1 ) resetWatchdog();
sleep_enable();
interrupts();
sleep_cpu();
sleep_disable();
power_all_enable();
ADCSRA = keepADCSRA;
}
void goToWDTSleep() {
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
byte keepADCSRA = ADCSRA;
ADCSRA = 0;
power_all_disable();
noInterrupts();
resetWatchdog();
sleep_enable();
interrupts();
sleep_cpu();
sleep_disable();
power_all_enable();
ADCSRA = keepADCSRA;
}
void resetWatchdog() {
MCUSR = 0;
WDTCR = bit (WDCE) | bit (WDE) | bit (WDIF);
WDTCR = bit (WDIE) | bit (WDP2) | bit (WDP1);
wdt_reset();
}
void rampUpDown(bool upDown, byte speed) {
if ( upDown == 1 ) ledPWM++;
else ledPWM--;
analogWrite(LED,ledPWM);
delay(speed);
}
Beim Einschalten läuft alles sauber. Die Startsequenz läuft durch, auch das ein- und ausschalten vom Licht tut mit dem Taster. Sobald aber der PIR (und somit auch der Watchdog) ins Spiel kommt, klappt es ein paar Mal mit dem Triggern und irgendwann (mal früher, mal später) resettet sich plötzlich der µC und ich komme einfach nicht dahinter, woran es liegt. Spiele ich die alte FW wieder drauf, verrichtet er seinen Dienst wie bisher auch.
Nachdem ich mittlerweile schon etliche Abende und Nächste damit verbracht hab, den Fehlerteufel ausfindig zu machen und es mir nicht gelungen ist, liegt meine Hoffnung bei der tollen Community, die wir hier haben - ob mir jemand weiterhelfen kann.
Vielen Dank im Voraus!