Ви не увійшли.
На самом деле millis() имеет джиттер. А на 8-ми мгц просто гигантский! Поэтому иногда (например для динамической индикации) приходится использовать нештатный миллис().
Ну а в пустом loope конечно можно добиться абсолютной (до такта) скважности = 2, только зачем?)
Вот любопытные вещи относительно хронометража в Arduino:
При использовании millis() нужно помнить об одной особенности - millis() "тикает" не равномерно.
Возвращаемое значение увеличивается на единицу каждые 1024 мсек. Затем, когда миллис отстанет на 1 мсек, она "подводится" на единицу, т.е. возвращаемое значение перескакивает через один.
При измерении длительных интервалов это не страшно, но при интервалах в несколько мсек это заметно.
Смотря, что вы считаете длительным интервалом ... по моему весьма заметно....
#include <S65Display.h>
S65Display lcd;
#define BLACK RGB( 0, 0, 0)
#define WHITE RGB(255,255,255)
#define RED RGB(255, 0, 0)
#define GREEN RGB( 0,255, 0)
#define GREEN2 RGB( 0,255, 51)
#define BLUE RGB( 0, 0,255)
#define YELLOW RGB(255,255, 0)
#define YELLOW2 RGB(153,153, 0)
#define PINK RGB(204,051,153)
#define BGCOLOR RGB( 51,204,255)
char str[10];
byte hour=0, minut=0, secund=0;
unsigned long TimeCHR;
byte Sec=0, Min=0, Hrs=0;
void setup() {
lcd.init(2); lcd.clear(0);
lcd.clear(BLACK); //закрашиваем дисплей
lcd.drawRect(1,1,175,131,RED); // рисуем рамку
lcd.drawRect(3,3,173,129,GREEN2); // рисуем рамку
lcd.drawRect(5,5,171,127,BLUE); // рисуем рамку
lcd.drawText(52, 55,"test time", 1, GREEN, BLACK);
// ************************************
// * Настраиваем таймер времени *
// ************************************
TIMSK1 = 0x01; // включенно глобальное прерывание переполнения таймера
TCCR1A = 0x00;
TCNT1 = 0x0BDC; // установить начальное значение для удаления ошибки времени (регистр бит-бит)
TCCR1B = 0x04; // запуск таймера / установка часов
}
// ********************************************************************
// функция учета времени
// ********************************************************************
ISR(TIMER1_OVF_vect) { TCNT1=0x0BDC; measure(); }
// функция вызывается с интервалом в одну секунду
void measure (void) { secund++;
if (secund==60) {secund=0; minut++;}
if (minut==60) {minut=0; hour++;}
if (hour==24) {hour=0;}
sprintf(str, "%02d.%02d.%02d", (int)hour, (int)minut, (int)secund);
lcd.drawText(55, 25, str, 1, YELLOW, BLACK); }
// ====================================================================
// ====================================================================
void loop() {
TimeCHR = millis();
Sec = (TimeCHR/1000L)%60;
Min = ((TimeCHR/1000L)/60L)%60;
Hrs = ((TimeCHR/1000L)/3600L)%24;
sprintf(str, "%02d.%02d.%02d", (int)Hrs, (int)Min, (int)Sec);
lcd.drawText(55, 85, str, 1, YELLOW2, BLACK);
/* for (int i = 0; i <= 15; i++) {
lcd.drawText(52, 55,"test time", 1, WHITE, BLACK); delay(100);
lcd.drawText(52, 55,"test time", 1, RED, BLACK); delay(100);
lcd.drawText(52, 55,"test time", 1, BLUE, BLACK); delay(100);
lcd.drawText(52, 55,"test time", 1, PINK, BLACK); delay(100);
lcd.drawText(52, 55,"test time", 1, GREEN, BLACK); delay(100);
} */
}
// ====================================================================
Проверили.
Правда не совсем точно...
Скважность, конечно не ровно 2, но близко к тому. Читать надо.
Как это "не ровно"?
Если время пустого цикла loop() порядка ~0.5мкс. то при delay( 1 ) скважность будет 1 + 1.0005 - это и есть "не ровно 2"?
рассыпается миф
Так там в теме именно так вопрос и ставился - проверить это. Проверили. Скважность, конечно не ровно 2, но близко к тому. Читать надо.
Olej пише:В-третьих, мне не хочется возиться с осциллографом.
Ну, как писал Высоцкий: "Стукнул раз - специалист - видно по нему!
Я не понимаю что вас так развеселило? Я написал же как и почему способ аппаратного определения, с помощью осциллографа, тоже порочный логически: он будет давать заниженные значения частоты, или затянутый период одного цикла loop().
Хотя сама цифра длины периода и не так важна (разве любопытства ради). Если она мала (800нс или 300нс - не важно) то:
- рассыпается миф, пересказываемый во многих обсуждениях об Arduino, что цикли с 2-мя delay( 1 ) (и любыми другими delay()) будет иметь скважность не 2 ... т.е. что loop() ещё что-то куда-то добавляет;
- можно спокойно не учитывать какие бы ни было задержки, вносимые частями исполняющей системой, прикомпилируемой IDE;
- хотя можно, понятности и точности ради, вообще исключить из исполнимого скетча функции setup() и loop(), прописав туда собственную функцию main():
int main() {
Serial.begin( 9600 );
Serial.println( "++" );
}
- IDE замечательно, без ругани компилирует такой код (загружает и выполняет) ... хотя какие-то операции инициализации в библиотеках при этом выпадают из выполнения, есть некоторые отличия в поведении.
В-третьих, мне не хочется возиться с осциллографом.
Ну, как писал Высоцкий: "Стукнул раз - специалист - видно по нему!
Olej пише:Так что стоило повозиться с тестированием,
Достаточно было почитать тему по той ссылке, что я давал. Там есть этот пример с осциллограммой.
Во-первых, я всё сразу читал. Во-вторых, там пример с осциллографом - тоже с логическим дефектом. В-третьих, мне не хочется возиться с осциллографом.
Так что стоило повозиться с тестированием,
Достаточно было почитать тему по той ссылке, что я давал. Там есть этот пример с осциллограммой.
3. дополнительная задержка, вносимая в цикл loop() исполняющей системой Arduino исчезающе мала, меньше 1мкс ... неважно сколько там точно.
Это хорошая новость (для меня ). Потому что она опровергает описываемые на разных форумах Arduino утверждения о том, что простейший пример генерации меандра не будет иметь скважности 2:
void loop()
{
digitalWrite( ledPin, HIGH );
delay( 1 );
digitalWrite( ledPin, LOW );
delay( 1 );
}
Так что стоило повозиться с тестированием, чтобы лишний раз самому убедиться, что разговоры по дополнительные задержки, вносимые к циклу loop() - это пустое: цикл - он и в Африке цикл.
Так что измерял ты не скорость вызовов 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)
Понятно. Диагноз ясен. Вопрос закрыт.
Вот и я подумал, что с самонадеянным ... радиомонтажником обсуждать дальше не стану.
Понятно. Диагноз ясен. Вопрос закрыт.
Olej пише:В AVR обычно и в Arduino в частности таймер настроен на системный тик как-раз по 1024-й микросекунде (если не лазить к таймеру руками).
Ты идиот? Частота в ардуино 16МГц, значит системный тик - 1/16 микросекунды.
Идиот - это ты, дружище.
А 1/16 микросекунды - это период частоты процессора, к системному тику никакого прямого отношения не имеет ... хотя системный тик и формируется из этой частоты.
Это только у недоумков-самоделкиных, безграмотных радиолюбителей - что частота процессора, что системный тик ... и всё по хер.
В AVR обычно и в Arduino в частности таймер настроен на системный тик как-раз по 1024-й микросекунде (если не лазить к таймеру руками).
Ты идиот? Частота в ардуино 16МГц, значит системный тик - 1/16 микросекунды. Не знаю, какие тебе нужны источники и пруфы, чтобы из частоты период получить, ну почитай учебник для 6-го класса.
а мне такие эксперименты проделывать в облом
Так ты определись - или делай, или не болтай. Не пахнет там никакими 17,6 мкс и близко. Это твои тормоза. Так что измерял ты не скорость вызовов loop, а скорость твоих тормозов.