Wire.setWireTimeout()
Wire.setWireTimeout() задаёт предельное время ожидания I²C-операции в режиме контроллера — если шина зависла, библиотека прервёт передачу и вернёт ошибку вместо бесконечного ожидания.
Полная статья
Описание
setWireTimeout() устанавливает предельное время ожидания для I²C-передачи в режиме контроллера. Если за это время операция не завершается, библиотека прерывает её и возвращает код ошибки — скетч продолжает работу вместо того, чтобы зависнуть навсегда.
Если вызвать функцию без аргументов, будет применено значение тайм-аута по умолчанию, которого достаточно для большинства конфигураций с одним контроллером на шине.
Функция входит в состав библиотеки Wire.
Синтаксис
Wire.setWireTimeout(timeout, reset_on_timeout)Wire.setWireTimeout()
Параметры
timeout— максимальное время ожидания в микросекундах. Значение0полностью отключает проверку тайм-аута. Тип данных:uint32_t.reset_on_timeout— если передатьtrue, аппаратный модуль Wire будет автоматически сброшен при срабатывании тайм-аута. Тип данных:bool.
Возвращает
Ничего.
Пример кода
#include <Wire.h>
void setup() {
Wire.begin(); // Подключиться к шине I2C (адрес необязателен для контроллера)
#if defined(WIRE_HAS_TIMEOUT)
Wire.setWireTimeout(3000 /* us */, true /* reset_on_timeout */);
#endif
}
void loop() {
// Отправить команду периферийному устройству
Wire.beginTransmission(8);
Wire.write(123);
byte error = Wire.endTransmission();
if (error) {
Serial.println("Error occurred when writing");
if (error == 5)
Serial.println("It was a timeout");
}
delay(100);
// Прочитать результат
#if defined(WIRE_HAS_TIMEOUT)
Wire.clearWireTimeoutFlag();
#endif
byte len = Wire.requestFrom(8, 1);
if (len == 0) {
Serial.println("Error occurred when reading");
#if defined(WIRE_HAS_TIMEOUT)
if (Wire.getWireTimeoutFlag())
Serial.println("It was a timeout");
#endif
}
delay(100);
}
Где применяется
- Устройства с несколькими I²C-периферийными модулями, один из которых может «зависнуть» и удерживать шину.
- Промышленные или встраиваемые системы, где надёжность важнее скорости реакции на ошибку.
- Прототипы с длинными проводами или нестабильным питанием периферии.
- Конфигурации с несколькими контроллерами на одной шине, где арбитраж может затянуться.
Практические замечания
- Тайм-аут — это симптом, а не лечение. Если тайм-ауты срабатывают регулярно, ищите первопричину: отсутствие подтягивающих резисторов, слишком длинные провода, помехи, неправильный адрес устройства или его некорректное поведение. Тайм-аут лишь не даёт скетчу зависнуть, но не восстанавливает повреждённые данные.
- Рекомендуемое значение — 25 мс (25 000 мкс). Это максимальное время растяжения тактового сигнала, допустимое протоколом SMBus. Для более высоких тактовых частот или конфигураций с несколькими контроллерами значение можно уменьшить.
- Флаг тайм-аута нужно сбрасывать вручную. После срабатывания проверяйте состояние через
getWireTimeoutFlag(), а сбрасывайте черезclearWireTimeoutFlag(). Флаг также сбрасывается при вызовеsetWireTimeout(). - Аппаратный сброс (
reset_on_timeout = true) полезен, когда сам модуль Wire попадает в некорректное состояние. Если платформа поддерживает эту возможность, сброс помогает восстановить шину без перезагрузки всего устройства. - Переносимость: функция появилась позже исходной версии библиотеки Wire и может отсутствовать на некоторых платформах. Для переносимого кода используйте макрос
WIRE_HAS_TIMEOUT— он определён только тогда, когда доступныWire.setWireTimeout(),Wire.getWireTimeoutFlag()иWire.clearWireTimeoutFlag(). - Явное отключение тайм-аута лучше выполнять через
setWireTimeout(0), а не полагаться на то, что он отключён по умолчанию — поведение по умолчанию может измениться в будущих версиях библиотеки. - Значения по умолчанию хранятся в макросах
WIRE_DEFAULT_TIMEOUTиWIRE_DEFAULT_RESET_WITH_TIMEOUT— их можно использовать для восстановления исходных настроек после изменения.
Как читать результат
Функция ничего не возвращает, но её эффект виден косвенно:
endTransmission()вернёт ненулевой код ошибки, если операция была прервана по тайм-ауту.requestFrom()вернёт0(нулевое количество байт) при тайм-ауте.getWireTimeoutFlag()вернётtrue, если тайм-аут сработал хотя бы раз с момента последней очистки флага.
Если getWireTimeoutFlag() постоянно возвращает true — это сигнал, что на шине есть проблема, требующая диагностики.