/* * HalloweenaugenServo_II.c * * Created: 05.01.2024 * Author : xxx */ #define F_CPU 9600000 // ---CKDIV8-Fuse muss deaktiviert sein !!!--- #include #include #include #include #include #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) // setzt das angegebene Bit auf 1 #endif #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) // setzt das angegebene Bit auf 0 #endif //Zufallszahlen für Zeitwerte uint8_t laufZeit = 0; //Zur Info: 0=> 1Sek., Max-Werte für Zeit: 255, Anzahl: 50 //Ablage erfolgt im Flash-Speicher, um RAM zu sparen const uint8_t ANZAHL = 50; //const uint8_t zeitWerteSekundaer[ANZAHL] PROGMEM = {52, 99, 167, 3, 55, 22, 119, 27, 153, 85, 22, 10, 103, 48, 24, 124, 11, 7, 57, 120, 47, 77, 138, 79, 20, 116, 52, 5, 191, 8, 153, 26, 72, 64, 18, 185, 30, 12, 3, 129, 112, 17, 197, 89, 15, 107, 2, 61, 164, 79}; //const uint8_t zeitWerteSekundaer[ANZAHL] PROGMEM = {68, 9, 133, 14, 99, 104, 96, 93, 7, 123, 141, 39, 32, 29, 131, 6, 30, 148, 41, 122, 77, 43, 103, 5, 42, 81, 146, 24, 38, 82, 52, 136, 89, 118, 48, 71, 87, 69, 8, 61, 106, 73, 153, 109, 40, 147, 50, 10, 63, 121}; //const uint8_t zeitWerteSekundaer[ANZAHL] PROGMEM = {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2}; const uint8_t zeitWerteSekundaer[ANZAHL] PROGMEM = {1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1}; uint8_t zufallsZeitWert(); struct Auge { uint8_t zeit; bool zustand; const uint8_t pin; void update (void) { //Auge n: zweite Zeitvariable prüfen (Anzahl an Sekunden) if (zeit > 0) { zeit--; //Sekundären Zeitzähler reduzieren } else { //Wenn beide Zeitvariablen abgelaufen sind: //wenn Auge an, dann ausschalten if (zustand) { //wenn PinB1 =1 //ausschalten cbi(PORTB, pin); // pin auf 0 setzen zustand = false; //Zeitvariable auf Zufallswert für Aus-Zeit setzen zeit = 0; //zufallsZeitWert(); //Wert aus Zufallsliste beziehen } else { //wenn Auge aus, dann anschalten sbi(PORTB, pin); // pin auf 1 setzen zustand = true; //Zeitvariable auf Zufallswert für An-Zeit setzen zeit = 0; //zufallsZeitWert(); //Wert aus Zufallsliste beziehen } } } }; Auge auge [] { {0, false, PB1}, {0, false, PB2}, {0, false, PB3}, {0, false, PB4}, }; //Servo-Code: volatile uint8_t ZeitZaehlerServo = 0; volatile uint8_t zeitAugenFst = 0; volatile uint8_t phase = 3; uint8_t servoZyklus = 0; // Timer ist übergelaufen (alle 6,8267ms (=256*0,02666ms)), neue Phase beginnt (Clock : Timer-Prescaler=> 9,6MHz : 256 = 0,02666ms je Timer-Takt) // Jede 3. Phase (20,5ms) wird PB0=1 gesetzt und dann bei Erreichen des Vergleichswertes (OCR0A in der Main-Schleife löst "ISR(TIM0_COMPA_vect)" aus),s.u., wieder auf 0 gesetzt ISR(TIM0_OVF_vect) { // Servo nur in Phase 0 ansteuern if (phase > 2) { sbi(PORTB, PB0); //Servo-Signal an //Zeitvariablen (49*20,5ms => 1,004Sek) ZeitZaehlerServo++; //alle 3 Phasen (20,5 ms) eins hochzählen zeitAugenFst++; phase = 0; } phase++; // Nächste Phase 1... 2...3 => 0 } // Timer hat Vergleichswert erreicht ISR(TIM0_COMPA_vect) { cbi(PORTB, PB0); //Servo-Signal aus nach 1-2ms (=>1ms(37) bis 2ms(70, korrigierter Wert)) } int main(void) { DDRB = _BV(PB4) | _BV(PB3) | _BV(PB2) | _BV(PB1) | _BV(PB0); //Setzen der Register fuer 20 ms Timerinterrupt // Starte Timer 0 im Fast PWM Modus mit Prescaler TCCR0A = _BV(WGM01) | _BV(WGM00); //=> 8Bit Fast-PWM TIMSK0 = _BV(OCIE0A) | _BV(TOIE0); TCCR0B = _BV(CS02); //=>Timer0 starten, Prescaler 256 sei(); //Setzen des globalen Interrupt-Enable-Bit while (1) { //Zeitabfrage Augen 1 bis 4 (Servo mit Auge-3-An-Schaltung synchronisiert) if (zeitAugenFst > 48) { //Sekundentaktgeber //Sekunden-Taktgeber zurücksetzen zeitAugenFst = 0; //49 entspricht ca. 1 Sek. (1,004s) for (auto &a : auge) { a.update(); } } //Servo-Code: if (servoZyklus < 1) //Anzahl links-rechts-Zyklen des Servos { //Servo-Code if (ZeitZaehlerServo < 49) //<1 Sek. (1,004s) { // Servo nach links fahren OCR0A = 37; } if (ZeitZaehlerServo > 48 && ZeitZaehlerServo < 98) { // Servo nach rechts fahren OCR0A = 70; //berechnet 75, nach Messung auf 70 korrigiert } if (ZeitZaehlerServo > 98) //Ein links-rechts-Zyklus durchlaufen { //Sekundenzähler zurücksetzen ZeitZaehlerServo = 0; servoZyklus++; } } } } uint8_t zufallsZeitWert() { //gibt Zufallswert für Zeit zurück laufZeit++; if (laufZeit > (ANZAHL-1)) { laufZeit = 0; } return pgm_read_byte (&zeitWerteSekundaer[laufZeit]); //Zugriff & Rückgabe von Wert aus dem im Flash abgelegten Array }