Пн ноя 06, 2023 00:11:19
#include <tiny24a.h>
#define BUTTON1 PINA.0 // вход первой кнопки
#define OUT1 PORTB.0 // выход состояния первой кнопки
#define VOLUME_UP PORTA.6 // Выходной импульс "Volume +" (по часовой стрелке)
#define VOLUME_DOWN PORTA.7 // Выходной импульс "Volume -" (против часовой стрелки)
#define CHATTER_WAIT 10 // задержка после отжатия кнопки для антидребезга - 100 мсек
#define POWEROFF_WAIT 5000 // время удержания кнопки для отключения
#define IMPULSE_DELAY 200 // Длительность импульса нажатой кнопки на выходе:
// указанное кол-во * (1000 мсек / частоту срабатывания прерывания в секунду) = ~ 50 мсек
eeprom unsigned char button1Memory;
unsigned char triggerChatter1;
unsigned char pressed1;
unsigned int offCounter1;
unsigned int encoderState, encoderStatePrev,
volumeUpStateCounter, volumeDownStateCounter,
delayUpCounter, delayDownCounter;
void main(void)
{
DDRA = (1<<DDA7) | (1<<DDA6) | (0<<DDA5) | (0<<DDA4) | (0<<DDA3) | (0<<DDA2) | (0<<DDA1) | (0<<DDA0);
PORTA = (0<<PORTA7) | (0<<PORTA6) | (1<<PORTA5) | (1<<PORTA4) | (0<<PORTA3) | (1<<PORTA2) | (1<<PORTA1) | (1<<PORTA0);
DDRB = (0<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);
PORTB = (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);
// --- Настройка работы прерывания таймера по переполнению ---
/*
Предделитель 8, Частота МК 1,200,000 Гц, "тик" таймера 1200000/8 = 150000 раз в секунду.
В счетный регистр таймера вносится 0хDA = 216.
Cчетчик таймера однобайтовый (max значение = 255), значит до переполнения он инкрементируется 255-218 = 37 раз
Тогда счетчик таймера переполнится и прерывание будет срабатывать:
150000 / 37 = 4054 раз в секунду
*/
TCCR0B = (0<<WGM02) | (0<<CS02) | (1<<CS01) | (0<<CS00); // инициализация работы таймера предделитель 8 (150кГц)
TIMSK0 = (0<<OCIE0B) | (0<<OCIE0A) | (1<<TOIE0); // включение прерывания нулевого таймера по переполнению
ACSR = (1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIS1) | (0<<ACIS0); // Отключить аналаговый компаратор
TCNT0 = 0xDA; // счетчик таймера
if (button1Memory)
OUT1 = button1Memory; // последнее запомненное состояние кнопки 1 на выход
#asm("sei") // разрешить прерывания
while (1)
{
if (volumeUpStateCounter >= 4)
{
VOLUME_UP = 1;
volumeUpStateCounter = 0;
delayUpCounter = 0;
}
if (volumeDownStateCounter >= 4)
{
VOLUME_DOWN = 1;
volumeDownStateCounter = 0;
delayDownCounter = 0;
}
if (delayUpCounter == IMPULSE_DELAY & VOLUME_UP == 1)
{
VOLUME_UP = 0;
}
if (delayDownCounter == IMPULSE_DELAY & VOLUME_DOWN == 1)
{
VOLUME_DOWN = 0;
}
};
}
// Прерыванию по переполнению счетчика таймера. ~ 4000 раз в секунду
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0 = 0xDA; // выставить счетчик таймера
encoderState = PINA & 0b00110000; // на pin 4 и 5 - входы фаз A и B энкодера
delayUpCounter++;
delayDownCounter++;
// --- обработка сигнала энкодера ---
if (encoderState != encoderStatePrev)
{
switch(encoderStatePrev)
{
case 32:
{
if(encoderState == 48) volumeUpStateCounter++;
if(encoderState == 0) volumeDownStateCounter++;
break;
}
case 0:
{
if(encoderState == 32) volumeUpStateCounter++;
if(encoderState == 16) volumeDownStateCounter++;
break;
}
case 16:
{
if(encoderState == 0) volumeUpStateCounter++;
if(encoderState == 48) volumeDownStateCounter++;
break;
}
case 48:
{
if(encoderState == 16) volumeUpStateCounter++;
if(encoderState == 32) volumeDownStateCounter++;
break;
}
}
encoderStatePrev = encoderState;
}
// --- обработка нажатия кнопки 1 ---
if (BUTTON1 == 0)
{
if (triggerChatter1 == 0 && OUT1 == 0) // если кнопка нажата только что и до этого выход был отключен
{
OUT1 = 1; // включить выход
button1Memory = 1; // запоминить состояние кнопки в памяти
pressed1 = 1; // запоминить, что при нажатии кнопки выход включился
}
else if (pressed1 == 0) // если выход не включался
{
if (offCounter1 < POWEROFF_WAIT) // и не истекло время удержания кнопки для выключения выхода
offCounter1++; // увеличивать счетчик удержания отключения
else if (offCounter1 == POWEROFF_WAIT) // если подошло кнопку удерживали нужное для отключения время
{
OUT1 = 0; // выключить выход
button1Memory = 0; // запоминить состояние кнопки в памяти
offCounter1 = 0xFFFF; // счетчик удержания отключения установить в MAX значение, чтобы он был больше времени задержки
}
}
triggerChatter1 = 1; // включить триггер-защелку
}
else // кнопка1 отжата
{
offCounter1 = 0; // сбросить счетчик удержания отключения
pressed1 = 0; // сбросить состояние кнопки1
if (triggerChatter1) // если кнопка1 была нажата
{
triggerChatter1++; // увеличить счетчик антидребезга
if (triggerChatter1 > CHATTER_WAIT)
triggerChatter1 = 0; // если время антидребезга прошло, то сбросить триггер-защелку
}
}
}
Пн ноя 06, 2023 00:39:59
Пн ноя 06, 2023 11:17:39
Пн ноя 06, 2023 18:03:10