В документации micros () указано, что возвращаемое значение всегда будет кратно 4.
Есть ли способ получить микросекундный клик с более высоким разрешением, предпочтительно до уровня 1 микросекунда?
Сброс до уровня AVR является приемлемым.
В документации micros () указано, что возвращаемое значение всегда будет кратно 4.
Есть ли способ получить микросекундный клик с более высоким разрешением, предпочтительно до уровня 1 микросекунда?
Сброс до уровня AVR является приемлемым.
Ответы:
Да, в зависимости от базовой частоты вашего Arduino. Например, здесь приведены входные частоты и периоды счетчика таймера после предварительного масштабирования для счетчика-таймера 2 ATMega2560 и базовая тактовая частота 16 МГц. Таймер имеет встроенные опции значений «prescaler», которые определяют частоту / период, показанные в этой таблице:
TCCR2B bits 2-0 Prescaler Freq [KHz], Period [usec] after prescale
0x0 (TC stopped) -- --
0x1 1 16000. 0.0625
0x2 8 2000. 0.500
0x3 32 500. 2.000
0x4 64 250. 4.000
0x5 128 125. 8.000
0x6 256 62.5 16.000
0x7 1024 15.625 64.000
Для лучшего разрешения по времени вы используете значение TCNT2. Существует встроенный счетчик, который идет от 0 до 255, потому что таймер 8 бит. Когда счетчик достигает значения, назначенного TCNT2, он запускает прерывание. Это прерывание называется TIMER2_OVF_vect.
учитывая эту информацию, результирующая частота прерываний будет: 16 МГц / (предварительное масштабирование * (255 - TCNT2))
Вы можете заставить таймер работать на полных 16 МГц (62,5 нсек), хотя это намного быстрее, чем вам нужно; 2 МГц с начальным счетом (255-2) даст вам частоту прерываний 1 МГц. Разделите это на 2 в вашем ISR:
extern uint32_t MicroSecClock = 0;
ISR(TIMER2_OVF_vect) {// this is a built in function that gets called when the timer gets to the overflow counter number
static uint_8 count; // interrupt counter
if( (++count & 0x01) == 0 ) // bump the interrupt counter
++MicroSecClock; // & count uSec every other time.
digitalWrite(53,toggle);// pin 53 is arbitrary
TCNT2 = 253; // this tells the timer when to trigger the interrupt. when the counter gets to 253 out of 255(because the timer is 8 bit) the timmer will trigger an interrupt
TIFR2 = 0x00; // clear timer overflow flag
};
Таблица данных для вашего MCU является основным ресурсом; эта статья даст вам (и дал мне!) хороший старт.
Марк, я решил написать новый набор функций, основанный на таймере Arduino Atmega328 Timer2 и использующий прерывания переполнения, чтобы получить точность до 0.5us. Мой код доступен для скачивания и использования здесь:
Вот краткое описание: «Я написал« libary », чтобы получить точность 0.5us для функции замены« micros () », чтобы я мог получать воспроизводимые результаты, читая сигнал PWM или PPM, с точностью до 1us. Я искал все вокруг Интернет и не мог найти что-то сопоставимое (или это было легко использовать, и поддерживал способность Arduino писать сигналы ШИМ через Servo Libary), поэтому я думаю, что это мой первый крупный вклад в мир Arduino и радиоуправления ».
Если допустимо снижение до уровня AVR (как вы упомянули в своем вопросе), вы можете установить таймер и даже получить отметки от часов AVR.
Вам нужно обратиться к таблице данных вашего AVR, потому что она отличается в разных ATMegas и ATTinys. Но процедура всегда одна и та же. Что вам нужно сделать, это:
TCCR
Таким способом можно получить точные отметки из регистра таймера, однако вам нужно подсчитывать переполнения вручную. Это максимально точно с точки зрения технологии.
Вот пример кода для устаревшего AT90S2313, но он дает вам хорошие подсказки, что делать в основном:
/* uC: AT90S2313 */
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
// set up timer 0
TCCR0 = (1<<CS01); // Prescaler 8
// enable overflow interrupt
TIMSK |= (1<<TOIE0);
// activate interrupts
sei();
while(1)
{
/* Do whatever you like */
}
}
ISR (TIMER0_OVF_vect)
{
/*
This gets called everytime there in an overflow in the timer register
*/
}
TIMSK
и TOIE0
т. Д. (Скопируйте настройку таймера из таблицы данных atmega328p). Похоже, вы не можете использовать макрос ISR (), вместо этого используйте arduino.cc/en/Reference/AttachInterrupt .