Допустим, у нас 8-ми битный МК типа AVR, какой-нибудь датчик угла/скорости/влажности/жадности, который отдаёт своё значение через два регистра — в одном low-byte, в другом high-byte, при этом у датчика есть регистр ready, который устанавливается в HIGH, когда данные готовы для чтения. Теперь мы хотим усреднить показания датчика за секунду и что-то сделать с этим значением. Как я понял, это довольно типичная задача. Для этого мы вешаем прерывание на ready, и из прерывания обновляем значение показания датчика, а в основном потоке только используем это значение. Как правильно выстроить логику? Если бы значения укладывались в 1 байт, то было бы всё просто. Но с двумя байтами может быть так, что функция чтения видит старое значение в low-байте, происходит прерывание, и в high-байте уже новое значение.
Здравствуйте, cppguard, Вы писали:
C>Допустим, у нас 8-ми битный МК типа AVR, какой-нибудь датчик угла/скорости/влажности/жадности, который отдаёт своё значение через два регистра — в одном low-byte, в другом high-byte, при этом у датчика есть регистр ready, который устанавливается в HIGH, когда данные готовы для чтения. Теперь мы хотим усреднить показания датчика за секунду и что-то сделать с этим значением. Как я понял, это довольно типичная задача. Для этого мы вешаем прерывание на ready, и из прерывания обновляем значение показания датчика, а в основном потоке только используем это значение. Как правильно выстроить логику? Если бы значения укладывались в 1 байт, то было бы всё просто. Но с двумя байтами может быть так, что функция чтения видит старое значение в low-байте, происходит прерывание, и в high-байте уже новое значение.
Документацию читайте. Там обычно shadow регистр есть. Он позволяет читать данные которые не влазят в регистр.
Re[2]: Запись из прерывания, чтение из основного потока
Здравствуйте, kov_serg, Вы писали:
_>Документацию читайте. Там обычно shadow регистр есть. Он позволяет читать данные которые не влазят в регистр.
Не очень понял. У нас два регистра на датчике, значение поделено на байты и хранится в обоих регистрах по частям. Зачем ещё что-то? В любом случае, в datasheet ни слова про shadow. Есть high-byte, low-byte и ready.
Re[3]: Запись из прерывания, чтение из основного потока
Здравствуйте, cppguard, Вы писали:
C>Не очень понял. У нас два регистра на датчике, значение поделено на байты и хранится в обоих регистрах по частям. Зачем ещё что-то? В любом случае, в datasheet ни слова про shadow. Есть high-byte, low-byte и ready.
Посмотрите 16бит-ые таймеры например на 8 битных контроллерах.
Какой датчик? Можно конкретики например: ADS1115DS1722
Re[4]: Запись из прерывания, чтение из основного потока
Здравствуйте, cppguard, Вы писали:
C>Компас QMC5883L. Раздел 9, data output.
Так там же написано, что данные измеряются с заданным темпом и складываются в регистры. Значения которых не меняется до следующего измерения.
The data stays the same, regardless of reading status through I2C, until new data replaces them.
Максимальная скорость измерений 200Гц (5мс), i2c шина 100кГц (можно 400кГц) так что вам ничего не мешает вычитать все данные 6раз на 100кГц при 200Гц темпе измерения.
Re[6]: Запись из прерывания, чтение из основного потока
Здравствуйте, kov_serg, Вы писали:
C>>Компас QMC5883L. Раздел 9, data output. _>Так там же написано, что данные измеряются с заданным темпом и складываются в регистры. Значения которых не меняется до следующего измерения. _>
The data stays the same, regardless of reading status through I2C, until new data replaces them.
_>Максимальная скорость измерений 200Гц (5мс), i2c шина 100кГц (можно 400кГц) так что вам ничего не мешает вычитать все данные 6раз на 100кГц при 200Гц темпе измерения.
Может я что-то не понимаю, но как быть если:
1. Прочитан low-byte.
2. Измерения обновились.
3. Прочитан high-byte.
Re: Запись из прерывания, чтение из основного потока
Ваш вопрос касается проблемы "атомарности" операций с данными, которые разбиты на несколько байт. Это действительно общая проблема, и решение её зависит от конкретной аппаратной архитектуры и языка программирования. В вашем случае (с 8-битным МК типа AVR), обычным подходом будет использование блокировки прерываний на время чтения или записи 16-битных данных.
Вот возможный псевдокод для такой ситуации:
volatile uint16_t sensor_value; // Общая переменная, используемая и обработчиком прерываний, и основной программой
// Обработчик прерыванияvoid ISR()
{
uint8_t low_byte = read_low_byte_from_sensor();
uint8_t high_byte = read_high_byte_from_sensor();
sensor_value = (high_byte << 8) | low_byte;
}
// Основной поток программыvoid main()
{
while (true)
{
// Блокируем прерывания
cli(); // clear interrupt - специфичная для AVR команда для блокировки прерываний
uint16_t local_copy = sensor_value;
// Разблокируем прерывания
sei(); // set interrupt - команда AVR для разблокировки прерываний
// Используем local_copy для вычисления среднего значения или других операций...
}
}
Этот подход обеспечивает "атомарность" операций чтения и записи 16-битного значения. Здесь мы временно блокируем прерывания на время копирования значения из общей переменной, чтобы избежать ситуации, когда прерывание происходит в середине этого процесса. Как только копирование завершено, прерывания снова разблокируются.
Примечание: убедитесь, что время блокировки прерываний минимально, чтобы не пропустить другие важные прерывания. Большую часть обработки данных лучше выполнять с разрешенными прерываниями, используя локальную копию данных.
Re[7]: Запись из прерывания, чтение из основного потока
Здравствуйте, cppguard, Вы писали:
C>>>Компас QMC5883L. Раздел 9, data output. _>>Так там же написано, что данные измеряются с заданным темпом и складываются в регистры. Значения которых не меняется до следующего измерения. _>>
The data stays the same, regardless of reading status through I2C, until new data replaces them.
_>>Максимальная скорость измерений 200Гц (5мс), i2c шина 100кГц (можно 400кГц) так что вам ничего не мешает вычитать все данные 6раз на 100кГц при 200Гц темпе измерения.
C>Может я что-то не понимаю, но как быть если: C>1. Прочитан low-byte. C>2. Измерения обновились. C>3. Прочитан high-byte.
Читай всё подряд. Если к окончанию чтения бит "DRDY" в статусном регистре равен "0" — значит ты всё верно прочитал. В противном случае — читай заново.
Data Ready Register (DRDY), it is set when all three axis data is ready, and loaded to the output data registers in
the continuous measurement mode. It is reset to “0” by reading any data register (00H~05H) through I²C
commends