Написал небольшой скетч для измерения скорости чтения аналоговых портов. Но удивили больше всего функции измерения времени millis() и micros(). Код (Text): void setup() { Serial.begin(115200); unsigned int value; // dummy variable to prevent optimization unsigned int time; /* 1. Testing millis() function */ value = 0; time = millis(); for(int i=0; i<999; i++) { value += analogRead(0); } time = millis() - time; Serial.println(time); // 111 /* 2. Testing micros() function */ value = 0; time = micros(); for(int i=0; i<999; i++) { value += analogRead(0); } time = micros() - time; Serial.println(time); // 46360 /* 3. Output both functions value */ Serial.println(millis()); // 224 Serial.println(micros()); // 224640 } void loop() { } Третий тест показал что МК считает значения этих функций ожидаемо. Почему один и тот же код измеренный функцией millis выполняется 0,111 сек, а если измерить micros, то 0,046360 сек. -- в два раза быстрее. Если поменять местами тесты - то на результат это сильно не повлияет.
Прошу прощения за то что поторопился. Вопрос снят. Я, по наивности своей, думал что int - 32 бита. Если заменить unsigned int time; на unsigned long time; Все станет работать ожидаемо. Спасибо за терпение.
Эх, а я только докопался до этого. Чуть-чуть не успел А вы мерите как быстро работает analogRead? Если хотите драматически ускорить, я могу подсказать как.
Любопытно. Расскажите конечно. И еще такой вопрос. Как быстрее всего отдать с устройства (Уно) данные, через стандартный Serial, через WiFi, через Ethernet или записать на SD карту? Или все не принципиально? Хочу понять насколько часто Уно может снимать со всех аналоговых входов сигнал и сохранять его куда-нибудь.
На самом деле чудес не бывает, бывают хаки. Чтобы получить значение аналогового сигнала, с помощью компаратора вход сравнивается с рядом известных напряжений, такт за тактом, то есть не моментально. В итоге, при настройках по умолчанию, один замер аналогового сигнала занимает от 13 до 260 мкс, как повезёт. В среднем это 121 мкс, что вы и наблюдали. Можно сказать, что сравнение можно делать грубее, тратя на него меньше времени. Этим управляет регистр ADCSRA. Если в setup'e вы настроите его биты так: ADCSRA |= (1 << ADPS2); ADCSRA &= ~(1 << ADPS1 | 1 << ADPS0); Скорость увеличится в 8 раз. Для полной картины по множителям, см. стр. 266 даташита на ATmega328. При уменьшении точности картину начинает портить сама функция analogRead, которая непременно склеивает результат из двух байт, прибегает к преобразованию типов и т.п., чтобы получить 10-битный диапазон, который уже не уместен. Поэтому можно её непоправимо улучшить, взяв в расчёт только старший байт результата компарации: Код (Text): int analogReadFast(uint8_t pin) { uint8_t low, high; #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (pin >= 54) pin -= 54; // allow for channel or pin numbers #elif defined(__AVR_ATmega32U4__) if (pin >= 18) pin -= 18; // allow for channel or pin numbers #elif defined(__AVR_ATmega1284__) if (pin >= 24) pin -= 24; // allow for channel or pin numbers #else if (pin >= 14) pin -= 14; // allow for channel or pin numbers #endif #if defined(__AVR_ATmega32U4__) pin = analogPinToChannel(pin); ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); #elif defined(ADCSRB) && defined(MUX5) // the MUX5 bit of ADCSRB selects whether we're reading from channels // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); #endif // set the analog reference (high two bits of ADMUX) and select the // channel (low 4 bits). this also sets ADLAR (left-adjust result) // to 0 (the default). #if defined(ADMUX) ADMUX = (analog_reference << 6) | (pin & 0x07) | _BV(ADLAR); #endif // start the conversion sbi(ADCSRA, ADSC); // ADSC is cleared when the conversion finishes while (bit_is_set(ADCSRA, ADSC)); return ADCH; }
А по поводу скоростей Serial, WiFi, SD и т.п. вопрос хороший. Затрудняюсь ответить. Serial может дать 115200 бод. SD и Ethernet работает через SPI, поэтому теоретически должно работать быстрее, если скармливать буферы подходящего размера. Для SD — это блоки по 512 байт, для Ethernet — это видимо, MTU ~ 1492 байта.
Спасибо за информацию! Пока проверил - штатным образом получается передать данные по serial-у со скоростью более 500 раз в сек со всех датчиков - пока хватит. Блин это же почти вся ОЗУ контроллера.