Балансаир на MPU6050 из урока про акселерометр и гироскоп держал равновесие ровно до того дня, как я добавил на шину часы и экран. Кадр управления дышал пятью миллисекундами, а опрос кадра из 14 байтов при заводских 100 кГц съедал около полутора — вместе с остальными устройствами шина стала самым медленным звеном, платформа задёргалась. Замер millis() всё сказал: полный круг опроса — 1,4 мс на 100 кГц и всего 0,35 мс после разгона до 400. При этом каждое значение в кадре успевало устареть ещё до того, как попадало в регулятор, — а после разгона регулятор начал жить в реальном времени. Ни один датчик я не менял и шину не пересобирал — сменилась только скорость, и всё это обошлось без паяльника.
В этом уроке разберём, откуда у Uno берутся заводские 100 кГц, как регистр TWBR связывает кварц и частоту шины, что меняется физически при 400 кГц, когда разгонять нельзя и почему после разгона обязателен тест, а не вера в даташит. Сразу про симулятор: частоту в нём не покрутить — движок не тактирует шину в реальном времени. Зато соберём ping-тест устройств, который на живой плате покажет, выжила ли шина на новой скорости, а в симуляторе продемонстрирует саму механику проверки.
Формула TWBR: 72 и 12
На AVR контроллером шины управляет регистр TWBR, и связь прямая: F_SCL = F_CPU / (16 + 2·TWBR) при делителе 1. Кварц Uno — 16 МГц, значит TWBR = 72 даёт 16000000 / 160 = 100 кГц (заводская скорость), а TWBR = 12 даёт 16000000 / 40 = 400 кГц. Первый ход всегда одинаковый: Wire.setClock(400000) — библиотека посчитает регистр сама и не привяжет скетч к конкретной плате. А TWBR — то же самое руками: знание, откуда берётся число, спасает, когда setClock недоступен или хочется нестандартной скорости. Граница: TWBR живёт только на AVR — Uno, Nano, Mega; на ESP32 такого регистра нет, там setClock переконфигурирует шину средствами своего ядра. Поясню и делитель из формулы: это биты TWPS в регистре TWSR, по умолчанию они нулевые и дают множитель один, поэтому в жизни меняют только TWBR. Но если в проекте заводится чужая библиотека, которая трогает TWSR, — проверьте делитель перед расчётами: с множителем четыре все ваши частоты уедут вчетверо вниз, и искать это по логам бесполезно.
Теперь цена байта. Каждый байт на шине стоит 9 тактов: восемь данных плюс подтверждение. На 100 кГц это около 90 мкс, на 400 — около 22,5 мкс, вчетверо дешевле. Прикинем на живых примерах: кадр MPU6050 — адрес плюс 14 байтов, 135 тактов, 1,35 мс против 0,34 мс; 32-байтовая посылка в EEPROM — примерно 3 мс против 0,75 мс; обход восьми устройств по кругу — 1,4 мс против 0,36 мс. Разгон имеет смысл там, где цикл измеряется единицами миллисекунд: балансиры, регуляторы, быстрые опросы. Экрану, который обновляется раз в 100 мс, четыре сотни микросекунд экономии не нужны — там я скорость не трогаю. Прикидка на глаз всегда одна: любое устройство опрашивается за время, равное девяти тактам на байт плюс адрес, — от этой константы пляшут все кадры, и умножив её на число байтов, вы получите длину кадра без секундомера.
| Устройство | Потолок частоты | Примечание |
|---|---|---|
| DS1307 (часы) | 100 кГц | на быстрой шине молчит целиком |
| PCF8574 (LCD-переходник) | 100 кГц | экран на 400 кГц рисует кракозябры |
| DS3231 | 400 кГц | разрешает с запасом |
| MPU6050 | 400 кГц | кадр из 14 байтов опрашивается вчетверо быстрее |
| BMP280 | 400 кГц | измерения не страдают |
Из таблицы следует главное правило разгона: частота шины — это потолок самого медленного её жильца. Перед разгоном пробегите адресную книгу проекта из урока про таблицу адресов и поищите старичков: DS1307 исторически ограничен сотней, переходник LCD на PCF8574 по даташиту тоже. Существует и режим на 1 МГц (fast plus), но на макетной проводке фронты его не вытянут — для Uno я его не трогаю вовсе. И частая путаница, которую проговариваю заранее: скорость не добавляет дальности. Быстрый режим требует более коротких проводов и более сильных подтяжек, а не позволяет тянуть шину дальше — ускорение покупается чистотой сигнала, а не наоборот.
Физика 400 кГц сурова к проводам. Фронт сигнала обязан успевать за 300 наносекунд, а фронт — это заряд ёмкости через подтяжку: 10 кОм на шине со 100 пФ дают около 850 нс, втрое больше лимита; 4,7 кОм на короткой шине проходит, на длинной — уже на грани, и тогда 2,2 кОм. Расчёт по формуле 0,85×R×C с таблицей номиналов был в уроке про номиналы подтяжек, а чем плох длинный шлейф — в уроке про длину проводов. Моё правило: 400 кГц дружит с короткой шиной и подтяжками 2,2-4,7 кОм; всё, что длиннее полуметра, остаётся на сотне.
#include <Wire.h> // Разгон TWI на Uno до 400 кГц и проверка, что шина выжила.// Формула AVR: F_SCL = F_CPU / (16 + 2*TWBR) при делителе 1.// Кварц 16 МГц: TWBR=72 -> 100 кГц (заводская), TWBR=12 -> 400 кГц. void razgon400() { TWSR &= ~((1 << TWPS0) | (1 << TWPS1)); // делитель = 1 (он и так нулевой) TWBR = 12; // 16000000 / (16 + 24) = 400 кГц // Альтернатива одной строкой: Wire.setClock(400000);} const byte MPU = 0x68;const byte REG_KTO = 0x75; // регистр WHO_AM_Iconst byte PODPIS = 0x68; // паспортное значение void setup() { Wire.begin(); razgon400(); Serial.begin(9600); Serial.println("TWBR=12: цель 400 кГц, тест стабильности");} unsigned long promah = 0; void loop() { unsigned long t0 = millis(); for (int i = 0; i < 500; i++) { // 500 чтений регистра-подписи Wire.beginTransmission(MPU); Wire.write(REG_KTO); Wire.endTransmission(); Wire.requestFrom(MPU, 1); if (Wire.available() > 0 && Wire.read() != PODPIS) promah++; } Serial.print("krug=500 promah="); Serial.print(promah); Serial.print(" ms="); Serial.println(millis() - t0); delay(2000);}Тест стабильности и честность симулятора
Скорость, которую допустил даташит, — это ещё не скорость, которую допустила ваша проводка. Поэтому после разгона я гоняю тест: 500 чтений регистра-подписи WHO_AM_I со сверкой паспортного значения 0x68 и счётчиком промахов. На короткой макетке с подтяжками 4,7 кОм четыреста килогерц дают ноль промахов; шлейф в полметра с подтяжками 10 кОм начинает сыпать промахи уже в первые сотни чтений. Мой стенд в цифрах: провода 15 сантиметров и подтяжки 4,7 кОм — ноль промахов за пять тысяч чтений на 400 кГц; тот же шлейф в полметра — промах каждые несколько сотен; шлейф плюс 10 кОм — промахи десятками, и это уже не статистика, а приговор. Порядок лечения жёсткий: сначала подтяжки сильнее, потом провода короче, и только потом — откат частоты. Промахи читайте по шкале: ноль — скорость ваша; единичные — затяните подтяжку; десятками — возвращайтесь на сотню без сожалений. Заодно тест показывает время круга в миллисекундах: 500 чтений при 400 кГц идут примерно вчетверо быстрее, и цифра на экране Serial — лучшее подтверждение, что разгон состоялся.
В симуляторе картина иная, и тут честность важнее красоты: движок шину не тактирует в реальном времени, частоты нет, шина идеальна. Поэтому сим-блок показывает не разгон, а сам ping-тест — круг стуков по трём адресам со счётчиком ok. В виртуальной схеме он вернёт ok=3 всегда: заглушка ACK-ает всё. Ценность в другом: скетч теста вы заберёте на живую плату как есть, поменяв только список адресов, — и он сразу скажет, пережила ли шина ваш TWBR. А если на новой скорости кто-то начал отвечать невпопад, вердикты по кодам вернут вас к уроку про endTransmission, где каждый код расписан.
Эксперименты для закрепления
Первое: посчитайте по формуле TWBR = 2 — это 800 кГц, за пределами любых даташитов; на живой плате прогоните тест и посмотрите на счётчик промахов: мой стенд нуля не дал, и это лучший аргумент не выезжать за паспортные скорости. Второе: соберите разнородную шину — MPU6050 и LCD-переходник — и переключайте частоту на лету: 400 кГц перед датчиком, 100 кГц перед экраном, строго перед каждой транзакцией; заодно сравните время опроса датчика в обоих режимах, чтобы увидеть разницу своими глазами. Третье: измерьте время круга из 500 чтений на обеих частотах и поделите — у меня вышло 3,8-кратное ускорение вместо теоретических четырёх: накладные расходы на start-стоп съедают остаток.
Четвёртое: возьмите шлейф длиной в метр с подтяжками 10 кОм, поднимите частоту до 400 и посчитайте фронт по формуле 0,85×R×C из урока про подтяжки — промахи теста совпадут с расчётом с точностью до десятков процентов, и это редкий случай, когда теория и макетка обнимаются. Замеры времени делайте на millis-логике из урока про millis вместо delay — delay() в тесте замер врёт. А если после всех экспериментов шина начала подвисать целиком, маршрут лечения лежит в уроке про зависания и таймауты.
- Заводская скорость Uno — 100 кГц; 400 кГц включается Wire.setClock(400000) или регистром TWBR = 12
- Формула AVR: F_SCL = F_CPU / (16 + 2·TWBR); 72 даёт 100 кГц, 12 — 400 кГц; TWBR живёт только на AVR
- Байт с подтверждением — 9 тактов: 90 мкс на 100 кГц против 22,5 мкс на 400; кадр MPU6050 — 1,35 мс против 0,34
- Частота шины равна потолку самого медленного устройства: DS1307 и PCF8574 — только 100 кГц
- После разгона — тест стабильности: 500 чтений WHO_AM_I, промахи лечатся подтяжками 2,2-4,7 кОм и короткими проводами
- 1. TWBR = 12 при кварце 16 МГц и делителе 1 даёт шине:
- 2. Какое устройство не переживёт 400 кГц?
- 3. Первый ход для разгона шины:
- 4. Один байт с подтверждением на шине — это:
- 5. На 400 кГц фронт сигнала должен укладываться в 300 нс. Что помогает?
Частые вопросы по теме урока
- TWBR = 12 при кварце 16 МГц и делителе 1 даёт шине:
- 16000000 / (16 + 24) = 400 кГц. Для сотни нужен TWBR = 72. 400 кГц
- Какое устройство не переживёт 400 кГц?
- DS1307 ограничен 100 кГц; на быстрой шине он молчит. Переходник LCD на PCF8574 тоже любит только сотню. DS1307
- Первый ход для разгона шины:
- setClock сам посчитает регистр и не привяжет скетч к плате; TWBR = 12 — то же самое руками. Wire.setClock(400000)
- Один байт с подтверждением на шине — это:
- Байт стоит 9 тактов: около 90 мкс на 100 кГц и около 22,5 мкс на 400 кГц. 9 тактов: 8 данных плюс подтверждение
- На 400 кГц фронт сигнала должен укладываться в 300 нс. Что помогает?
- Фронт — заряд ёмкости через подтяжку: 10 кОм на 100 пФ дают 850 нс, втрое больше лимита. подтяжки 2,2-4,7 кОм и короткая шина