Radio Life - Программа управления одной кнопкой

УНЧ с коммутатором

Программа управления одной кнопкой (вариант 3)


// ====================================================== // Слово состояния программы volatile unsigned int SYS_status; #define SYS_KEYPRESS 0x0001 // бит нажатой кнопки #define SYS_KEYRDY 0x0002 // бит готовности кнопки #define SYS_LEDON 0x0004 // бит включенной подсветки #define SYS_IN1 0x0008 // флаг включения входа 1 #define SYS_SEROUTRDY 0x0010 // флаг готовности вывода в порт Serial #define SYS_ADCRDY 0x0020 // флаг готовности АЦП #define SYS_HIVOL 0x0040 // флаг напряжения питания больше 11 В // ====================================================== // входы/выходы контроллера для работы с кнопками // и коммутатором // ------------------------------------------------------ // PD3 (D3) - вход прерывания кнопок // // PD4 (D4) - выход 0 // PD5 (D5) - выход 1 // PD6 (D6) - выход 2 // PD7 (D7) - выход 3 // ------------------------------------------------- // ячейки обработки кнопок с подавлением дребезга // ------------------------------------------------- volatile int KEY_value; // состояние кнопки int KEY_delay = 250; // задержка на дребезг #define KEY_1 0x08 // маска для кнопки #define OUT_LED 0x04 // маска подсветки #define OUT_1 0x10 // маска аналогового входа 1 #define OUT_2 0x20 // маска аналогового входа 2 #define OUT_3 0x40 // маска аналогового входа 3 #define OUT_4 0x80 // маска аналогового входа 4 #define TIM2_DIVIDER 0x07 // предделитель таймера 2 (1024) #define TIM2_MASK 0x02 // маска прерывания таймера 2 volatile int LED_count; // счетчик таймера подсветки #define LED_MAXON 20 // время включения подсветки #define SET_TIME 8 // таймаут на включение режима установки // ------------------------------------------------- // ячейки работы с последовательным портом // ------------------------------------------------- char SerBuf[16]; // буфер вывода порта // ------------------------------------------------- // ячейки работы с АЦП // ------------------------------------------------- char ADC_count; // счетчик периода работы АЦП int ADC_result; // данные с АЦП // ================================================= // ------------------------------------------------------------------------- void setup() { // запрещаем прерывания перед настройкой cli(); // сбрасываем слово состояния программы SYS_status = 0; // устанавливаем режим "выход" линий 4-7 порта D DDRD = (DDRD | 0xf0); // устанавливаем режим "выход" линии 2 порта B (подсветка) DDRB = (DDRB | 0x04); // сбрасываем счетчик таймера подсветки LED_count = 0; // +++++++++++++++++++++++++++++++++ // настройка режимов прерывания INT1 // +++++++++++++++++++++++++++++++++ // срабатывание по изменению уровня на входе INT1 (PD3) EICRA = (0 << ISC11) | (1 << ISC10); EIMSK |= (1 << INT1); // разрешаем прерывания INT1 // конец настройки прерывания INT1 // +++++++++++++++++++++++++++ // настройки режимов таймера 2 // +++++++++++++++++++++++++++ TCCR2A = 0; // установить регистры в 0 TCCR2B = 0; // таймер остановлен // устанавливаем режим CTC (сравнение с регистром OCR2A) TCCR2A |= (0 << WGM20) | (1 << WGM21); // установка регистра совпадения таймера OCR2A OCR2A = KEY_delay; // включение прерываний по сравнению (CTC) TIMSK2 = TIM2_MASK; // конец настройки прерывания таймера 2 // +++++++++++++++++++++++++++++++++++++ // Настройка сторожевого таймера 0.5 sec // +++++++++++++++++++++++++++++++++++++ // необходимо для изменения делителя таймера WDTCSR = (1 << WDCE) | (1 << WDE); // установка делителя 0,5 сек. WDTCSR = (0 << WDP3) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0); // разрешение прерываний таймера WDTCSR |= (1 << WDIE); // конец настройки прерывания сторожевого таймера // +++++++++++++++++++++++++++++++++++++ // Настройка последовательного порта // +++++++++++++++++++++++++++++++++++++ Serial.begin(38400); // скорость основного порта Serial.setTimeout(2); // таймаут ожидания приема строки символов в мс // конец настройки последовательного порта // +++++++++++++++++++++++++++++++++++++ // Настройка АЦП // +++++++++++++++++++++++++++++++++++++ ADC_count = 0; // Установка опорного напряжения 1.1 В. // и входа А3 // Устанавливаем только те биты, которые должны быть установлены в "1" ADMUX = (1 << REFS0) | (1 << REFS1) | (1 << MUX1) | (1 << MUX0); // Установка частоты преобразования // делитель на 128 ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) |(1 << ADPS0); // конец настройки АЦП // +++++++++++++++++++++++++++++++++++++ // включаем по умолчанию аналоговый вход 1 PORTD |= OUT_1; SYS_status |= SYS_IN1; strcpy(SerBuf, "test\r\n"); SYS_status |= SYS_SEROUTRDY; // разрешаем прерывания после настройки sei(); } // ------------------------------------------------------------------------- void loop() { // проверка на вывод в последовательный порт // ----------------------------------------- if ((SYS_status & SYS_SEROUTRDY) != 0) { Serial.print(SerBuf); Serial.print(" \r"); // сбрасываем флаг вывода SYS_status &= ~SYS_SEROUTRDY; } // проверка на готовность АЦП // ----------------------------------------- if ((SYS_status & SYS_ADCRDY) != 0) { // если напряжение питания выше 11 В, устанавливаем флаг // и включаем подсветку if(ADC_result > 450) { SYS_status |= SYS_HIVOL; PORTB |= OUT_LED; // устанавливаем бит включенной подсветки SYS_status |= SYS_LEDON; } // если ниже 11 В, то сбрасываем флаг else SYS_status &= ~SYS_HIVOL; ADC_result = ((ADC_result >> 3) * 193) >> 10; itoa(ADC_result, SerBuf, 10); SYS_status |= SYS_SEROUTRDY; SYS_status &= ~SYS_ADCRDY; } // проверка на срабатывание кнопки // ------------------------------- if ((SYS_status & SYS_KEYRDY) != 0) { // сбрасываем готовность кнопок SYS_status &= ~SYS_KEYRDY; // если кнопка нажата, включаем таймер подсветки if ((KEY_value & KEY_1) == 0) { // включаем подсветку PORTB |= OUT_LED; // устанавливаем бит включенной подсветки SYS_status |= SYS_LEDON; // устанавливаем бит нажатой клавиши SYS_status |= SYS_KEYPRESS; LED_count = 0; } else // сбрасываем бит нажатой клавиши SYS_status &= ~SYS_KEYPRESS; } // проверяем включена ли подсветка // ------------------------------- if ((SYS_status & SYS_LEDON) != 0 && (SYS_status & SYS_HIVOL) == 0) { if (LED_count >= LED_MAXON) { PORTB &= ~OUT_LED; SYS_status &= ~SYS_LEDON; } } // переключение входа при удержании кнопки SET_TIME/2 сек // ------------------------------------------------------ if (((SYS_status & SYS_KEYPRESS) != 0) && (LED_count == SET_TIME) && ((SYS_status & SYS_LEDON) != 0)) { // сначала гасим подсветку PORTB &= ~OUT_LED; SYS_status &= ~SYS_LEDON; // если включен Вход 1 if ((SYS_status & SYS_IN1) != 0) { // отключаем вход 1 PORTD &= ~OUT_1; // включаем вход 2 PORTD |= OUT_2; SYS_status &= ~SYS_IN1; } else { // отключаем вход 2 PORTD &= ~OUT_2; // включаем вход 1 PORTD |= OUT_1; SYS_status |= SYS_IN1; } } } // =================================== // Программа обработки прерывания INT1 // =================================== ISR(INT1_vect) { KEY_value = PIND; // сохраняем состояние кнопки TCNT2 = 0; // обнуляем счетчик таймера 2 TCCR2B = TIM2_DIVIDER; // запускаем таймер с делителем 1024 } // ============================================ // Программа прерывания таймера 2 по сравнению // ============================================ ISR(TIMER2_COMPA_vect) { TCCR2B = 0; // останавливаем таймер SYS_status |= SYS_KEYRDY; // фиксируем состояние кнопки } // ================================================== // Программа обработки прерывания сторожевого таймера // ================================================== ISR(WDT_vect) { LED_count++; // запускаем АЦП раз в секунду if(ADC_count++ == 2) { ADC_count = 0; ADCSRA |= (1 << ADSC); } } // ================================== // Программа обработки прерывания АЦП // ================================== ISR(ADC_vect) { SYS_status |= SYS_ADCRDY; // установка флага готовности данных АЦП ADC_result = ADCL; // сохраняем младший байт результата АЦП ADC_result += ADCH << 8; // сохраняем старший байт АЦП }

Рис. 1. Схема коммутатора
(увеличенное изображение)