1) Если какая-то переменная используется одновременно в основном коде и в прерывании, то она должна быть помечена как volatile
. Затем каждое чтение или запись будет скомпилировано как чтение / запись соответствующей ячейки памяти. В противном случае компилятор может оптимизировать, минимизируя доступ к памяти. Таким образом, запись в переменную внутри основной программы не будет видна в прерывании.
2) Почему вы используете double
? Не используйте числа с плавающей запятой, если в этом нет крайней необходимости. В AVR нет аппаратной поддержки арифметики с плавающей точкой, поэтому каждая операция с плавающей точкой будет представлена в виде нескольких операций. В вашем примере ничто не мешает использовать целочисленную переменную, которая изменяется от 0 до 255. Даже если вы хотите использовать переменную диапазона 0-100, вы можете пересчитать ее, используя целочисленную арифметику.
3) Помните, что нужно обновлять переменные длиной более 1 байта. AVR - это 8-битная архитектура. Это означает, что обновление переменных в памяти шириной более 8 бит требует ряда операций. double
длиной 8 байт требует слишком много таких операций. Прерывание может сработать в любой момент в середине этого ряда, это означает, что значение переменной, полученное внутри ISR, будет обновлено только частично, что приведет к непредсказуемым результатам. В основном коде укажите в cli()
- sei()
любое обновление переменных, которые используются внутри ISR и имеют ширину более 1 байта.
3) Избегайте сложных расчетов в ISR. Практическое правило: любой ISR должен быть завершен как можно скорее, все интенсивные вычисления должны быть размещены за пределами ISR.
4) В этом примере вам вообще не нужен ISR! Вы можете написать OCR0A прямо внутри основного кода.