В данном уроке мы немного изменим программу которая была описана в уроке №2, проблема была в том, что пока у нас выполняется задержка _delay_ms(), наша программа не реагирует на нажатие кнопки или другие действия.
В нашей программе мы так же будем менять скорость изменения ШИМ, при нажатии кнопки, но при этом мы не будем использовать задержки.
Схема подключения:
************************
Задержки у нас выполняются за счет прерываний TIMER2.
Реестры с которыми будем работать:
Значения битов:
Программный код:
int k=0;// переменная для увеличения, уменьшения паузы
int t=0;// переменная для фиксации факта нажатия кнопки
int n2=0;//переменная для определения направления скорости работы ШИМ
int w=0;// переменная для изменения уровня ШИМ
void setup() {
//Serial.begin(9600);
//настройка ШИМ
DDRB |= 1 << 1; // PB1 как выход, канал 1
DDRB |= 1 << 2; // PB2 как выход, канал 2
TCCR1A = 0; // Сброс данных регистра
TCCR1B = 0; // Сброс данных регистра
TCNT1 = 0; // Установка нижнего предела
TCCR1B |= (1 << CS10); // Работа без делителя
TCCR1A |= (1 << COM1A1) | (1 << COM1B1); // Не инверсный режим работы
ICR1 = 639; // 16 МГц / 1 * ( 1 + 639 ) = 25 кГц
// Установка верхнего предела
// значением в бите ICR1
// Режим 14 из документации
TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM12) | (1 << WGM13);
OCR1A = 0xff; // Начальное значение уровня 100%
OCR1B = 0x0f; // Начальное значение уровня 50%
cli(); // отключить глобальные прерывания
//настройка Timer2
TCCR2A = 0;
TCCR2B = 0;
OCR2A = 155; // установка регистра совпадения 500 мс
TCCR2A = (1 << WGM21); // CTC режим
TIMSK2 |= (1 << OCIE2A); // включение прерываний по совпадению
TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20); // запуск с таймера с делителем на 1024
//настройка прерывания по входной кнопке
EICRA |= (1<<ISC01);//включим прерывания INT0 по нисходящему фронту
EIMSK |= (1<<INT0);//разрешим внешние прерывания INT0
sei(); // включить глобальные прерывания
DDRD &= ~(0b00000100);//Включаем ножку INT0 (PD2) на вход
PORTD |= 0b00000100;//Включаем резистор на ножке INT0 (PD2) к питанию
}
ISR(INT0_vect){// фиксируем факт нажатия кнопки
t=1;
}
ISR(TIMER2_COMPA_vect){ // прерывание по второму таймеру для работы задержки
if (t==1){// если нажата кнопка
if (n2==0){//увеличиваем скорость изменения скважности ШИМ
OCR2A=OCR2A+0x02;
if (OCR2A >= 253){//если дошли до максимума
n2=1;
}
}
if (n2==1){//уменьшаем скорость изменения скважности ШИМ
OCR2A=OCR2A-0x02;
if (OCR2A <= 2){// если дошли до минимума
n2=0;
}
}
t=0;
}
k=1;
}
void loop() {
if (k==1){// если было прерывание по таймеру 2
if ((OCR1A>=0xff)and(w==0)){w=1;}// меняем направления ШИМ
if ((OCR1A <= 0x01)and(w==1)){w=0;}//меняем направления ШИМ
if(w==0){ // увеличиваем скважность
OCR1A=OCR1A+0x01;
}
if(w==1){// уменьшаем скважность
OCR1A=OCR1A-0x01;
}
// Serial.print(OCR2A);Serial.print(» «); Serial.print(w);Serial.print(» «); Serial.println(OCR1A);
k=0;
}
}