Привет. Хочу считать микросекунды и миллисекунды с помощью таймера0 на 328p. Накидал немного кода: Код (C++): #define F_CPU 16000000 #include <util/delay.h> #include <avr/io.h> #include <stdint.h> #include <avr/interrupt.h> #include <avr/sfr_defs.h> volatile uint32_t MicrosecCounter; volatile uint16_t MillisecCounter; ISR(TIMER0_COMPA_vect) { MicrosecCounter += 10; MillisecCounter++; } int main() { TIMSK0 = (1<<OCIE0A); OCR0A = 160; TCCR0A = (1<<WGM01); TCCR0B = (1<<CS00); sei (); while(1) { ; } } Правильно ли я задал параметры, чтобы значение MicrosecCounter увеличивалось каждые 10us? Каким образом можно увеличивать MillisecCounter на 1 каждые 1000us?
OCR0A = 159. а не 160 добавить счетчик и каждое сотое прерывание увеличивать MillisecCounter на единицу
b707, спасибо. А OCR0A меньше на 1, это особенность именно 328p? Просто смотрел похожий код для Attiny10 и там для задержки в 50us был код без учета этой единицы: Код (C++): OCR0A = 400; //TOP=400, so OVF int at 8.000.000/400=20.000 Hz
это обычная логика. В примере для аттини тоже должно быть 399, а не 400 причина - счетчик таймера начинает счет с нуля. поэтому чтобы получить делитель на 2 - нужно ставить OCR = 1. чтобы делить на 4 - нужно ставить OCR = 3 и так далее Об этом часто забывают, да и для больших чисел это не так важно, разница между 399 и 400 несущественна
Это особенность программистов, которые не читают даташиты на МК. В даташитах все формулы есть - бери да считай.
посмотри в файлах ардуины wiring.c как millis и micros устроено. не факт что это оптимально, там еще ради универсальности много лишнего, но в целом суть та же
если выскочит ноль, значит прошла миллисекунда. Получать целое от деления гораздо тяжелее, чем остаток. На месте ТС я бы воспользовался одним из решений: 1.софтовый таймер 2.воспользоваться 16 или 32 битным таймером.
А сточки зрения производительности что будет выгоднее: 1. Завести еще и счетчик прерывания и увеличивать MillisecCounter каждые 100 прерываний. 2. MillisecCounter++, если остаток от деления 0. 3. Умножать MicrosecCounter в коде на float 0.001 для получения миллисекунд. Про 16 битный таймер не понял, чем в данном случае он будет лучше чем 8 битный.
16-ти битный таймер умеет считать до 999. А OCR каждый раз переписывать. Затея так себе, но зато имеем прерывания на каждый тик и чих.
между первыми двумя вариантами разница не очень велика, точно не скажу что выгоднее. Третий - заведомо проигрышный, причем в десятки раз
Операция деления (взятия остатка) очень затратная в AVR, т.к. нет аппаратной реализации. Поэтому в обработчиках прерываний лучше не использовать деление.