Вопросы о библиотеке HMC5883L

Сейчас я изучаю структуру библиотек. Я хочу узнать, как хорошие программисты пишут код, каким стратегиям они следуют, какому искусству программист следовал при разработке библиотеки. И насколько важно, чтобы библиотека была написана в хорошо оформленном виде.

Но поскольку я снова и снова исследую библиотеку, мне действительно нужно понять, как следовал программист, и причины, лежащие в основе примененной стратегии.

Пример, который я сейчас изучаю, — это HMC5883L и то, как программист использовал библиотеку Wire для управления разработкой библиотеки. Опытным программистам это должно быть довольно легко, но я действительно изучаю концепции, стратегии и т. д.

Поскольку я говорю снова и снова, у меня возникают разные вопросы, поэтому, чтобы начать это обсуждение, я хочу начать с вопроса о программисте, пишущем две очень похожие функции, которые делают практически одно и то же.

// Читаем байт для регистрации
uint8_t HMC5883L::fastRegister8(uint8_t reg)
{
    uint8_t value;
    Wire.beginTransmission(HMC5883L_ADDRESS);
    #if ARDUINO >= 100
        Wire.write(reg);
    #else
        Wire.send(reg);
    #endif
    Wire.endTransmission();

    Wire.requestFrom(HMC5883L_ADDRESS, 1);
    #if ARDUINO >= 100
        value = Wire.read();
    #else
        value = Wire.receive();
    #endif
    Wire.endTransmission();

    return value;
}

// Читаем байт из регистра
uint8_t HMC5883L::readRegister8(uint8_t reg)
{
    uint8_t value;
    Wire.beginTransmission(HMC5883L_ADDRESS);
    #if ARDUINO >= 100
        Wire.write(reg);
    #else
        Wire.send(reg);
    #endif
    Wire.endTransmission();

    Wire.beginTransmission(HMC5883L_ADDRESS);
    Wire.requestFrom(HMC5883L_ADDRESS, 1);
    while(!Wire.available()) {};
    #if ARDUINO >= 100
        value = Wire.read();
    #else
        value = Wire.receive();
    #endif
    Wire.endTransmission();

    return value;
}

Обновление: Собственно, первую версию программист использовал только в функции HMC5883L.begin();, но почему?

if ((fastRegister8(HMC5883L_REG_IDENT_A) != 0x48)
|| (fastRegister8(HMC5883L_REG_IDENT_B) != 0x34)
|| (fastRegister8(HMC5883L_REG_IDENT_C) != 0x33))
{
return false;
}

Все остальное в библиотеке использовало вторую версию.

Итак, по сути, эти две функции предназначены для чтения указанного регистра в HMC5883L, мои вопросы:

  1. в чем разница? Я знаю, что второй функции было уделено особое внимание, но почему?
  2. Это так важно?
  3. Есть ли ситуации, требующие какой-либо версии функций?

, 👍0

Обсуждение

Никогда не было «быстрого» способа сделать i2c, это миф. Есть много неправильных способов сделать i2c., @Jot

Да, я все еще изучаю, как на самом деле работает i2c, и разбираюсь с чипами i2c., @R1S8K


2 ответа


Лучший ответ:

2

Честно говоря, вторая версия функции - мусор. Первая версия (почти) правильный способ сделать это. Во второй версии есть вещи, которых там быть не должно. Нет абсолютно никакой причины, по которой создатель библиотеки создал эту вторую функцию.

  • Он «ждет» доступности данных, когда эти данные будут доступны в момент завершения requestFrom() — поэтому это совершенно избыточно
  • Он выполняет ложный вызов beginTransmission() прямо перед вызовом requestFrom(). beginTransmission() предназначен только для записи, а не для чтения. Там это бессмысленно.

Однако:

  • Обе функции выполняют endTransmission() после receiveFrom(), что не имеет смысла — endTransmission() предназначен для балансировки только beginTransmission(), а не receiveFrom(). receiveFrom() — это полностью автономная функция, не требующая никакой другой обработки.

Эта библиотека, вероятно, не подходит для изучения, чтобы научиться использовать библиотеку Wire. Он содержит код, который указывает на то, что автор сам не имел должного представления о работе библиотеки.

,

Огромное тебе спасибо, чувак! Я имею в виду, что вы серьезный человек :) Я очень рад, что мои вопросы значительны и важны. Я бы тоже попробовал развивать свою библиотеку, для меня это значит получать все больше и больше навыков, информации и учиться искусству программирования. Мне нужно забыть о своих старых кодах и библиотеках :), @R1S8K

Но если у меня возникнут еще вопросы, стоит ли мне вернуться сюда? Или убрать выбор ответа, пока я не закончу обсуждение темы?, @R1S8K

Если у вас есть новые вопросы, задавайте новые вопросы. Держите его «атомарным» :), @Majenko

все библиотеки HMC5883L для Arduino имеют такое :-) (включая Adafruit), @Juraj

Тогда они все скопировали друг друга :) У меня есть DTWI для чипKIT, который не делает этого - но тогда DTWI работает не так, как Wire..., @Majenko

@Юрай Не **все** из них. У этого 19 звезд, и он очень хорош: https://github.com/sleemanj/HMC5883L_Simple., @Jot

@Jot Спасибо за ссылку :), @R1S8K

Я действительно только сейчас обнаружил, как читать из определенного регистра из HMC5883L, я думал, что смогу прочитать 1-й регистр, и автоматический указатель чипа перенесет меня к следующему, не заканчивая проводную передачу и не начиная чтение нового. что регистрируют, но получается на самом деле так, мне приходится делать две совершенно отдельные проводные передачи. Один для указания регистра для чтения, а второй для чтения этого регистра., @R1S8K

Правильный. Во время инициализации не возникает проблем с чтением или записью одного байта. Если во время работы требуются данные x,y,z, было бы полезно прочитать эти 6 байтов вместе., @Jot


1

Не существует «быстрого» способа сделать i2c. Если вы уже используете «быстрые» функции в своем коде, вы можете сделать это встроенным вызовом readRegister8.

Приведенная ниже функция считывает байт из HMC5883L.
Если HMC5883L не подключен, Wire.read() возвращает -1. Оно будет преобразовано в возвращаемое значение 0xFF.

// Читаем байт из регистра
uint8_t HMC5883L::readRegister8(uint8_t reg)
{
    uint8_t value;
    Wire.beginTransmission(HMC5883L_ADDRESS);
    Wire.write(reg);
    Wire.endTransmission();    // добавляем параметр false для повторного запуска

    Wire.requestFrom(HMC5883L_ADDRESS, 1);
    value = Wire.read();

    return value;
}
,

Но разве не требуется Wire.endTransmission(); после value = Wire.read();?, @R1S8K

Нет, никогда, только при записи данных. См.: https://www.arduino.cc/en/Reference/WireEndTransmission. Это одна из ошибок в коде, о которой Маженко упомянул в своем ответе., @Jot

Хорошо, я перемещаюсь по i2c, немного поработал с библиотекой Wire и протестировал несколько строк по чтению каждого регистра. Далее мне нужно создать аналогичный надежный код i2c, который работает с аналогичным управлением данными в ISR и блокирует каждый режим до тех пор, пока он не будет готов., @R1S8K

Да, вы правы, мне следует поставить «false» между операциями записи/чтения. Нашел эту ссылку: ** Если это правда, endTransmission() отправляет сообщение об остановке после передачи, освобождая шину I2C. Если false, endTransmission() отправляет сообщение о перезапуске после передачи**, @R1S8K