Ви не увійшли.
Вот любопытные вещи относительно хронометража в Arduino:
При использовании millis() нужно помнить об одной особенности - millis() "тикает" не равномерно.
Возвращаемое значение увеличивается на единицу каждые 1024 мсек. Затем, когда миллис отстанет на 1 мсек, она "подводится" на единицу, т.е. возвращаемое значение перескакивает через один.
При измерении длительных интервалов это не страшно, но при интервалах в несколько мсек это заметно.
Так же (время системного тика чуть меньше 1mc) имеет место во всех процессорных семействах и всех операционных системах (или средах выполнения). Но это в точности соответствует представлениям реального времени и требованиям стандарта POSIX 1003b для реального времени: "фактические значения временных интервалов может быть сколь угодно больше заказанных, но никогда не может оказаться меньше". Или то же самое: единица шкалы измерения времени (1мс.) может быть меньше, но не смеет быть больше.
В вашем изложении период 1mc фактически соответствует 0,9765625mks. Тогда процесс коррекции millis() строго детерминированный, и можно точно вычислить период, с которым ошибка millis() будет накапливать 1ms и будет подлежать коррекции.
Неактивний
В связи с чем сделал такое тестовое приложение:
#include <stdio.h>
int serial_fputchar( const char ch, FILE *stream ) { Serial.write( ch ); return ch; }
static FILE *serial_stream = fdevopen( serial_fputchar, NULL );
void setup() {
stdout = serial_stream;
Serial.begin( 115200 );
}
void loop() {
while( !Serial.available() );
unsigned len = 0;
while( Serial.available() ) {
int r = Serial.read();
if( r >= '0' && r <='9' )
len = len * 10 + ( r - '0' );
delay( 1 );
}
Serial.println( len, DEC );
printf( "вычисление... ожидайте...\n" );
unsigned long *prev = new unsigned long [ len ],
*next = new unsigned long [ len ];
int i = 0;
do {
prev[ i ] = millis();
while( prev[ i ] == ( next[ i ] = millis() ) );
if( next[ i ] - prev[ i ] > 1 ) i++;
} while( i < len );
for( i = 0; i < len; i++ ) {
printf( "%lu:%lu:%2u", prev[ i ], next[ i ], i ? prev[ i ] - prev[ i - 1 ] : 0 );
printf( "%s", ( 9 == ( i % 10 ) ) ? "\n" : " | " );
}
printf( "\n" );
delete [] prev;
delete [] next;
}
Неактивний
Интересный вопрос: продолжительность пустого цикла опроса loop()?
Часто пишут: что мы, мол, точно не знаем задержек повторения loop() ... поэтому сложно судить ... о скважности, например delay() ...
Проверяем!
void setup() {
Serial.begin( 115200 );
}
unsigned long rep, i, s1, s2, prev, next;
bool cont = true;
void loop() {
if( cont ) { // ввод числа повторений
while( !Serial.available() );
rep = 0;
while( Serial.available() ) {
int r = Serial.read();
if( r >= '0' && r <='9' )
rep = rep * 10 + ( r - '0' );
delay( 3 );
}
cont = false;
s1 = s2 = prev = next = i = 0;
}
next = micros();
if( i <= rep ) { // посчёт задержек
if( i > 0 ) {
uint32_t inter = next - prev;
s1 += inter;
s2 += inter * inter;
}
i++;
}
prev = next;
if( i == rep + 1 ) { // вычисление результатов
Serial.print( i - 1, DEC );
Serial.print( " : " );
double m = (double)s1 / rep,
d = (double)s2 / rep - m * m;
Serial.print( m, 2 );
Serial.print( " +/-" );
Serial.println( sqrt( d ) );
cont = true;
}
}
В итоге имеем:
Итог:
- период повторения "пустых" loop() в среднем 17.61 мкс.
- со среднеквадратичным разбросом (СКО) 2.09 мкс. (11.87% от среднего)
Остання редакція Olej (2018-03-22 00:27:33)
Неактивний
- период повторения "пустых" loop() в среднем 17.61 мкс.
А если бы ты туда ко всему ещё и delay впихнул, то время было бы ещё больше.
Частота вызова пустого loop - 1.136МГц, стало быть период - 880 наносекунд.
Источник - http://arduino.ru/forum/programmirovanie/chastota-vyzovov-loop
Остання редакція Kaka (2018-03-22 11:55:31)
Неактивний
Olej пише:время системного тика чуть меньше 1mc
Поделись телефоном дилера. Тоже хочу эту траву попробовать.
Попробуй ... если годишься хоть что-то в этом понимать
Посмотрим что ты за Сухов...
Вот тебе телефон дилера - http://arduino.ru/forum/programmirovani … ent-354224:
Возвращаемое значение увеличивается на единицу каждые 1024 мсек. Затем, когда миллис отстанет на 1 мсек, она "подводится" на единицу, т.е. возвращаемое значение перескакивает через один.
Разницу между 1024 и 1000 уловишь?
+ фактический результат теста выше - где хорошо видно неравномерный инкремент последовательных millis(): на 1, но иногда, каждый 42-43-й раз, на 2.
Остання редакція Olej (2018-03-22 12:11:16)
Неактивний
Olej пише:- период повторения "пустых" loop() в среднем 17.61 мкс.
А если бы ты туда ко всему ещё и delay впихнул, то время было бы ещё больше.
При чём здесь delay(), если интерес состоял именно в максимальной частоте loop(), которая в слабеньком Arduino совсем не так высока, и часто недостаточная в реальной обработке уже в звуковом диапазоне. Т.е. частота "быстрого" цикла без пассивных ожиданий и активно нагружающих операций в цикле.
Частота вызова пустого loop - 1.136МГц, стало быть период - 880 наносекунд.
Источник - http://arduino.ru/forum/programmirovanie/chastota-vyzovov-loop
Если бы ты читал до конца то, на что ссылаешься ... да ещё давал себе труд понимать то, что читаешь - то заметил бы такую простую вещь, что "стало быть" - это при запрещённых прерываниях процессора, когда служба времени не работает и недоступна для использования - это граничный режим, который на практике никому и никогда не понадобится.
P.S. Хотя ссылка сама по себе интересная ... дальше там, а не с начала - я её как-то пропустил.
Остання редакція Olej (2018-03-22 12:26:43)
Неактивний
P.S. Хотя ссылка сама по себе интересная ... дальше там, а не с начала - я её как-то пропустил.
Там же показывают как loop() встраивает в функцию main() Arduino IDE:
for (;;) { loop(); if (serialEventRun) serialEventRun(); }
Вот то обслуживание ("системное"), которое за: if (serialEventRun) serialEventRun(); и тем, что может оттуда вызываться по цепочке, и добавляет к периоду тупого вызова loop() в цикле.
Там же, кстати, утверждается:
Предлагаю автору провести эксперимент с таким циклом:
while (1) { loop(); if (serialEventRun) serialEventRun(); }
и убедиться, что цикл выполняется в 4 раза быстрее.
Если это действительно так (мне в облом это проверять), то это полный идиотизм ... кого? компилятора AVR? разработчиков IDE? и т.д.
Неактивний
Olej пише:это при запрещённых прерываниях процессора,
А теперь возьми примпер оттуда, убери запрет прерываний и получи свои 17,6 мкс, бла-блабол.
А вот это значение, в реальной работе, с разрешёнными прерываниями и хотелось получить.
Только это ещё вопрос: получится или нет "свои 17,6 мкс" или нет? Потому как в их примере это можно только осциллографом видеть ... а мне такие эксперименты проделывать в облом. А я себе определял выше "свои 17,6 мкс" чисто программным путём, без шнурков и обвязки.
Так что про "возьми примпер оттуда" - это как-раз и есть бла-бла-бла: языком оно совсем просто ворочать, не камни, чай
Так-то вот как-то ... , примпер.
Остання редакція Olej (2018-03-22 15:19:08)
Неактивний
Olej пише:Разницу между 1024 и 1000 уловишь?
А ты разницу между системным тиком и тиком миллис уловишь? Или тебе это всё едино?
В AVR обычно и в Arduino в частности таймер настроен на системный тик как-раз по 1024-й микросекунде (если не лазить к таймеру руками).
Что такое за термин "тик миллис" - это только ты один такие страшные слова знаешь. Но millis() как-раз и считает 1.024мс интервалы, и именно из-за этого отстаёт от течения физического времени, и его приходится корректировать, каждые 42/43 отсчёта millis() инкрементируется не на 1, а на 2. Это по дефаулту, хотя детальные параметры коррекции можно перенастроить (но вряд ли стоит это делать). А соотношение вот тех 42 и 43 в последовательности корректировок они выбрали, чтобы моделировать некоторое дробное приближение 42.xxx.
А если тебе как-то по-другому это известно, так изложи ... с ссылками на источники и аргументами, а не бла-бла-бла:
Дабы глупость каждого была видна.
Остання редакція Olej (2018-03-24 11:08:59)
Неактивний
а мне такие эксперименты проделывать в облом
Так ты определись - или делай, или не болтай. Не пахнет там никакими 17,6 мкс и близко. Это твои тормоза. Так что измерял ты не скорость вызовов loop, а скорость твоих тормозов.
Неактивний
В AVR обычно и в Arduino в частности таймер настроен на системный тик как-раз по 1024-й микросекунде (если не лазить к таймеру руками).
Ты идиот? Частота в ардуино 16МГц, значит системный тик - 1/16 микросекунды. Не знаю, какие тебе нужны источники и пруфы, чтобы из частоты период получить, ну почитай учебник для 6-го класса.
Остання редакція Kaka (2018-03-22 16:55:49)
Неактивний
Olej пише:В AVR обычно и в Arduino в частности таймер настроен на системный тик как-раз по 1024-й микросекунде (если не лазить к таймеру руками).
Ты идиот? Частота в ардуино 16МГц, значит системный тик - 1/16 микросекунды.
Идиот - это ты, дружище.
А 1/16 микросекунды - это период частоты процессора, к системному тику никакого прямого отношения не имеет ... хотя системный тик и формируется из этой частоты.
Это только у недоумков-самоделкиных, безграмотных радиолюбителей - что частота процессора, что системный тик ... и всё по хер.
Неактивний
Так что измерял ты не скорость вызовов loop, а скорость твоих тормозов.
В принципе, да.
За счёт очень длинных (в сравнении с тактовой частотой) операций процессора +=, * + очень короткой задержки сверх цикла loop(), даже влияние 2-3 операций уже длиннее 1-го цикла loop(). Но это можно компенсировать, сделав калибровку на выполнение точно тех же операций (не заисанных в коде по-другому), но во внутреннем пустом цикле не выходя за пределы 1-го прохода цикла loop().
Как-то вот так, например:
void setup() {
Serial.begin( 115200 );
}
unsigned long rep, i, s1, prev, next;
bool cont = true;
#define step() \
next = micros(); \
if( i++ > 0 ) \
s1 += (next - prev); \
prev = next;
void loop() {
if( cont ) { // ввод числа повторений
while( !Serial.available() );
rep = 0;
while( Serial.available() ) {
int r = Serial.read();
if( r >= '0' && r <='9' )
rep = rep * 10 + ( r - '0' );
delay( 3 );
}
cont = false;
s1 = i = 0;
}
step(); // интервал в loop
if( i > rep ) { // вычисление результатов
double m = (double)s1 / rep;
s1 = i = 0;
loop: step(); // интервал во внутреннем цикле
if( i <= rep ) goto loop;
double c = (double)s1 / rep;
Serial.print( rep, DEC );
Serial.print( " : " );
Serial.print( m, 3 );
Serial.print( " - " );
Serial.print( c, 3 );
Serial.print( " = " );
Serial.println( m - c, 3 );
cont = true;
}
}
В результате будет как-то так:
100 : 9.960 - 9.640 = 0.320
1000 : 9.992 - 9.684 = 0.308
10000 : 9.998 - 9.684 = 0.314
100000 : 9.998 - 9.684 = 0.314
1000000 : 9.998 - 9.684 = 0.315
1. видно хорошую сходимость в зависимости от числа усреднения
2. может, чуть заниженный итог из-за одной "лишней" операции goto (для цикла использовать for() и while() не хотелось, там зависимоть от того как компилятор распорядится, и вносимые искажения там ещё больше ... проверено)
3. дополнительная задержка, вносимая в цикл loop() исполняющей системой Arduino исчезающе мала, меньше 1мкс ... неважно сколько там точно.
P.S. (Это что не лазить и не смотреть период осциллографом... Хотя с осциллографом тоже есть вопрос: в цикле loop() должна быть хотя бы одна операция вывода ... даже если её записать операцией AVR как PIND |= (1 << 3); - без промежуточного вызова функций Arduino)
Неактивний
3. дополнительная задержка, вносимая в цикл loop() исполняющей системой Arduino исчезающе мала, меньше 1мкс ... неважно сколько там точно.
Это хорошая новость (для меня ). Потому что она опровергает описываемые на разных форумах Arduino утверждения о том, что простейший пример генерации меандра не будет иметь скважности 2:
void loop()
{
digitalWrite( ledPin, HIGH );
delay( 1 );
digitalWrite( ledPin, LOW );
delay( 1 );
}
Так что стоило повозиться с тестированием, чтобы лишний раз самому убедиться, что разговоры по дополнительные задержки, вносимые к циклу loop() - это пустое: цикл - он и в Африке цикл.
Неактивний
Olej пише:Так что стоило повозиться с тестированием,
Достаточно было почитать тему по той ссылке, что я давал. Там есть этот пример с осциллограммой.
Во-первых, я всё сразу читал. Во-вторых, там пример с осциллографом - тоже с логическим дефектом. В-третьих, мне не хочется возиться с осциллографом.
Неактивний
Olej пише:В-третьих, мне не хочется возиться с осциллографом.
Ну, как писал Высоцкий: "Стукнул раз - специалист - видно по нему!
Я не понимаю что вас так развеселило? Я написал же как и почему способ аппаратного определения, с помощью осциллографа, тоже порочный логически: он будет давать заниженные значения частоты, или затянутый период одного цикла loop().
Хотя сама цифра длины периода и не так важна (разве любопытства ради). Если она мала (800нс или 300нс - не важно) то:
- рассыпается миф, пересказываемый во многих обсуждениях об Arduino, что цикли с 2-мя delay( 1 ) (и любыми другими delay()) будет иметь скважность не 2 ... т.е. что loop() ещё что-то куда-то добавляет;
- можно спокойно не учитывать какие бы ни было задержки, вносимые частями исполняющей системой, прикомпилируемой IDE;
- хотя можно, понятности и точности ради, вообще исключить из исполнимого скетча функции setup() и loop(), прописав туда собственную функцию main():
int main() {
Serial.begin( 9600 );
Serial.println( "++" );
}
- IDE замечательно, без ругани компилирует такой код (загружает и выполняет) ... хотя какие-то операции инициализации в библиотеках при этом выпадают из выполнения, есть некоторые отличия в поведении.
Остання редакція Olej (2018-03-27 09:51:22)
Неактивний