// ATtiny13A #define EEPRDEBUGNO // отладка - запись в EEPROM #ifdef EEPRDEBUG #include #define EEPROM_LEN 32 // область используемой памяти в словах (вся доступная) #define STORE_LEN EEPROM_LEN uint16_t EEMEM store_debugged[STORE_LEN]; volatile uint16_t i_eeprom = 0x04; #endif #define F_CPU 9600000 #include #include #include #define ALARM_40M 88888888UL // будильник на 40 минут #define KEY_HASH_ONOFF_MIN 0x35 #define KEY_HASH_ONOFF_MAX 0x3A #define KEY_HASH_ALARM_40M_MIN 0x4C #define KEY_HASH_ALARM_40M_MAX 0x51 #define LIGHT_MIN_VALUE 850 // при какой минимальной освещенности включится лампа (с большим запасом) #define MAX_PULSE_WIDTH 1500 // максимальное расстояние между фронтами импульсов в тиках таймера #define MAX_PULS_AMO 10 // макс. число обрабатываемых импульсов volatile long dt[MAX_PULS_AMO] = {0}; // хранилище числа тиков таймера для каждого фронта volatile uint8_t front_number = 0; // номер последнего обработанного фронта volatile unsigned long timer_ticks = 0; // счетчик в прерывании таймера volatile unsigned long alarm_time = 0; // еще для случая нескольких будильников ISR(TIM0_OVF_vect){ timer_ticks++; } uint8_t get_front_number(void) { ATOMIC_BLOCK(ATOMIC_RESTORESTATE){ return front_number; } } unsigned long get_timer_ticks(void) { ATOMIC_BLOCK(ATOMIC_RESTORESTATE){ return timer_ticks; } } ISR(INT0_vect){ if(front_number >= MAX_PULS_AMO) return; dt[front_number] = get_timer_ticks(); front_number++; } int analogReadADC3() // данные с фоторезистора { uint8_t l, h; ADMUX |= (1 << MUX0) | (1 << MUX1); // вход ADC3 (2) (PB3) - фоторезистор ADCSRA |= (1 << ADSC); while(ADCSRA & (1<= ALARM_40M) // будильник сработал { alarm_time = 0; PORTB |= (1 << PB2); // сигнал будильника _delay_ms(3500); PORTB &= ~(1 << PB2); continue; } } uint8_t result_ph = (PINB & (1 << PB0)); // данные с фоторезистора if (!result_ph) // контроль освещенностью { int photo = analogReadADC3(); if (photo > LIGHT_MIN_VALUE) // однократное срабатывание { PORTB &= ~(1 << PB2); } continue; } uint8_t pulse_amo = get_front_number(); // число накопленных импульсов (количеств тиков таймера размерами 4 байта) if(pulse_amo > 1) // накоплено больше одного импульса (можно считать разницы) { if((get_timer_ticks() - dt[pulse_amo - 1]) >= MAX_PULSE_WIDTH) // после последнего фронта прошло достаточно времени { uint16_t hash = 0; for (uint8_t i = 0; i < pulse_amo - 1; i++) { if (dt[i+1] <= dt[i]) continue; // редкий случай - переполнение... uint16_t ticks_tween_fronts = (uint16_t)(dt[i+1] - dt[i]); // расстояния между фронтами hash += (1 << i) * ticks_tween_fronts / 50; } #ifdef EEPRDEBUG for (uint8_t i = 0; i < 1; i++) // отладочное мигание { PORTB ^= (1 << PB2); _delay_ms(500); } eeprom_write_word (&store_debugged[i_eeprom++], hash); // записать хэш для изучения #else if ((hash >= KEY_HASH_ONOFF_MIN) && (hash <= KEY_HASH_ONOFF_MAX)) // вкл./выкл. { // отключить возможный будильник при вкл./выкл. alarm_time = 0; PORTB ^= (1 << PB2); } else if ((hash >= KEY_HASH_ALARM_40M_MIN) && (hash <= KEY_HASH_ALARM_40M_MAX)) // будильник через 40 минут { alarm_time = get_timer_ticks(); PORTB &= ~(1 << PB2); // сигнал включения будильника _delay_ms(2000); PORTB |= (1 << PB2); _delay_ms(1000); PORTB &= ~(1 << PB2); } #endif ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { front_number = 0; } } continue; } } }