У вас есть несколько проблем с дизайном в вашем коде:
delay_ms
и подобное блокирует выполнение других частей вашего кода. В то время как такие задержки заманчивы для запуска простой программы в первый раз, сохранение таких проблем проектирования будет настоящей болью, поскольку ваше приложение будет расти и решать более сложные задачи. Примером является блокирующая реализация ключа debounce. Лучше запустить прерывание по таймеру, а затем на основе этой проверки PORTA каждые, скажем, 10 мс. 20 мс (при 50 Гц .. 100 Гц). Этого достаточно для разоблачения. В зависимости от прочитанного значения основная программа решает, будет ли это короткое или длинное нажатие клавиши или же двойной щелчок.
while(wait_for_event)
также блокирует ваше приложение. Например,
while ((UCSRA & (1 << RXC)) == 0);/* Wait till data is received */
блокирует ваше целое приложение, пока UART не получит что-либо. Это работает для простых программ, но для программ помимо тривиальных это часто является проблемой. В случае приема / передачи UART вы также используете некоторые прерывания UART. Если вы предпочитаете опрашивать прерываниям, то напишите опрос таким образом, чтобы он не блокировал другие вещи навсегда.
В общем случае структура вашего основного l oop будет
while (1)
{
if (condition_1)
{
reset_condition_1();
nonblocking_action_for_condition_1();
}
if (condition_2)
{
reset_condition_2();
nonblocking_action_for_condition_2();
}
}
Например, иногда я использую опрос для простого приема UART следующим образом (на вашем устройстве могут быть разные SFR):
int uart_getc_nowait (void)
{
return (UCSRA & (1 << RXC)) ? 0xff & UDR : -1;
}
Это не блокирует: другие части кода будут выполнять только действия если эта функция возвращает 0 ... 255.
Когда вы передаете данные, вы можете рассмотреть возможность использования FIFO : вы бы записали строку в FIFO, а ISR выбрал бы индивидуальный байты и отправьте их. Псевдокод:
ISR (uart-dataregister-is-empty)
{
if (fifo-is-empty)
{
disable-uart-dataregister-is-empty-interrupt;
}
else
{
byte = read-one-byte-from-fifo;
uart-dataregister = byte;
}
}
void uart_putc (byte)
{
if (fifo-is-full)
{
do-something-if-fifo-is-full;
}
else
{
write-byte-to-fifo;
// Following action is no problem if respective IRQ is already enabled.
enable-uart-dataregister-is-empty-interrupt;
}
}