Связь между arduino nano и MCP3424 по I2c
Я завершаю свой проект, в котором используется 18-битный АЦП MCP3424 i2c и Arduino Nano для измерения температуры с помощью термистора NTC, но у меня проблемы с библиотекой проводов Arduino. Это мой первый проект с использованием i2c, поэтому я не очень хорошо разбираюсь в этом вопросе, но я внимательно прочитал техническое описание MCP3424, которое можно найти по адресу (http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf) и пробовал много разных способов заставить его работать. Также я новичок в размещении сообщений на этом стеке, поэтому извините меня, если мой синтаксис неверен (я делаю все возможное). Вот код, который у меня есть на моем Arduino.
#include<Wire.h>
#define ReadMode 0xDD //Устройство будет выводить данные преобразования (7 бит, адрес устройства. 1 бит, режим чтения/записи)
#define WriteMode 0xDC //Устройство ожидает конфигурационный байт (7 бит, адрес устройства. 1 бит, режим чтения/записи)
#define ConfigByte18 0x8c //PGA = 1, SPS = 3,75, однократный режим, канал 1, инициировать новое преобразование.
#define ConfigByte16 0x88 //PGA = 1, SPS = 15, однократный режим, канал 1, инициировать новое преобразование.
void setup() {
Serial.begin(9600);//Инициировать подключение к компьютеру
Wire.begin();//Запуск библиотеки Wire
Wire.setClock(100000);//убедитесь, что тактовая частота находится в стандартном режиме
delay(500);//Разрешить загрузку и установку ADC
Wire.beginTransmission(WriteMode);//начать передачу с АЦП в режиме записи
Wire.write(ConfigByte18);//настроить ADC с настройками, найденными в «ConfigByte18»
Wire.endTransmission();
Serial.print("Everything worked\n");
}
void loop() {
unsigned char x, y, z, a, b, c;
//Serial.println("Байт готов к чтению:");
Wire.begin();
Wire.setClock(100000);//убедитесь, что тактовая частота находится в стандартном режиме
Wire.beginTransmission(ReadMode);//начать передачу с АЦП в режиме записи
Wire.requestFrom(0x6E, 6);//запросить 6 байт информации от MCP3424
x = Wire.read();//читаем байты
delay(10);
y = Wire.read();
delay(10);
z = Wire.read();
delay(10);
a = Wire.read();
delay(10);
b = Wire.read();
delay(10);
c = Wire.read();
Serial.print(x);//печатать байты
Serial.print(", ");
Serial.print(y);
Serial.print(", ");
Serial.print(z);
Serial.print(", ");
Serial.print(a, HEX);
Serial.print(", ");
Serial.print(b, HEX);
Serial.print(", ");
Serial.println(c, HEX);
Wire.endTransmission();
delay(1000);
}
Итак, объяснение моего понимания: в разделе «void setup» я начинаю передачу в режиме записи (см. стр. 21 таблицы данных, чтобы следовать вместе с моим пояснительным рисунком и таблицей 5-3). в функции начала передачи я обращаюсь к slave с 0xDC, потому что адрес устройства начинается с 1101 (предварительно запрограммировано), а затем 110, так как у меня есть два контакта Adr, привязанных к +5v, и, наконец, 0, так как я хочу изменить настройки конфигурации. Это переводится как 0xDC в шестнадцатеричном формате. Затем я отправляю подчиненному байт информации для регистра конфигурации (см. стр. 18, раздел 5.2). Я отправляю 0x8C, так как хочу, чтобы мои настройки были PGA = 1, SPS = 3,75, режим One-Shot, канал 1, инициировать новое преобразование. Это должно означать, что мне нужно отправить подчиненному 10001100 или 0x8c. Затем это общение заканчивается как «Любой байт, отправленный после этого второго байта, будет проигнорирован» в соответствии со страницей 21. Затем в цикле я начинаю передачу таким же образом, за исключением того, что теперь я открываю передачу в режиме чтения, который равен 0xDD в качестве последнего бита (R /W бит) теперь равен 1. Затем я запрашиваю шесть байтов информации и читаю шесть байтов. Если вы сейчас перейдете на страницу 23 таблицы данных, вы можете снова следовать ей. Здесь я должен получить три байта данных от подчиненного устройства, и каждый последующий байт должен повторять настройки регистра конфигурации. На данный момент меня не интересуют первые три байта данных, поскольку я прежде всего просто хочу знать, как изменить настройки конфигурации. Вместо этого Arduino печатает три байта данных от подчиненного устройства, как и ожидалось, а затем три байта с одинаковым значением, также как и ожидалось, поскольку все они должны быть настройками конфигурации. То, что печатается во вторых трех байтах, это «90». Не то, что я ожидал. Сейчас попробовал разобраться в чем дело (тяжело без осциллографа). 90, преобразованное из шестнадцатеричного в двоичное, равно 10010000, и я полагаю, что настройки по умолчанию (которые можно найти на странице 18) 00001001. Может ли это быть настройками по умолчанию, если да, кто-нибудь может сказать мне, что происходит и как это исправить? Заранее благодарю вас за помощь и спасибо, что нашли время прочитать мою проблему.
@Asyu7, 👍1
Обсуждение1 ответ
Лучший ответ:
Проблема в том, что вы неправильно поняли, как библиотека Wire
обрабатывает адреса.
I2C использует байт адреса, где первые 7 битов являются фактическим адресом, а последний бит (бит чтения/записи) определяет направление связи. Библиотека Wire
предоставляет различные функции для обоих направлений (в вашем случае: Wire.beginTransmission()
для основной записи и Wire.requestFrom()
для основного чтения) и скрывает сложность бита чтения/записи. То, что вы должны указать в качестве адреса, — это чистый адрес устройства без бита чтения/записи. Для записи конфигурации вы использовали адрес 0xDC
, но фактический адрес устройства — 0x6E
, поскольку вы использовали его в Wire.requestFrom()
позвонить.
Кроме того, в вашем loop()
вы пытаетесь запустить мастер-запись с помощью Wire.beginTransmission()
, хотя вы запускаете мастер-чтение сразу после него. Wire.beginTransmission()
и Wire.endTransmission()
предназначены исключительно для основных транзакций записи. Так что вы должны удалить эти строки здесь. Для мастера чтения вызов Wire.requestFrom()
и достаточно соответствующего чтения.
Что происходит в вашем коде: В setup()
вы записываете новые данные конфигурации по неверному адресу (0xDC
вместо 0x6E
). Передача не удалась, так как скорее всего на шине нет устройства с таким адресом, но вы этого не замечаете, так как не проверяете возвращаемое значение Wire.endTransmission()
, которое показало бы код ошибки. Затем в функции loop()
вы снова инициализируете и переконфигурируете всю библиотеку Wire
, что не имеет смысла, как упоминал Юрай в своих комментариях. Хотя это будет стоить всего несколько циклов вычислительного времени. Затем библиотека устанавливается в основной режим записи (здесь нет фактического действия I2C, просто внутреннее для библиотеки), а затем в основной режим чтения (фактическое действие I2C. Предоставленное количество байтов считывается здесь с подчиненного устройства). В конце вы говорите библиотеке, что она должна завершить передачу мастер-записи из предыдущего, которого больше нет (поскольку вы сделали мастер-чтение). Так что это ничего не даст. Также вы делаете много задержек между чтениями, что не обязательно. Когда функция Wire.requestFrom()
возвращается, все коммуникации I2C завершаются. Байты, которые могли быть получены, принимаются и записываются в буфер библиотек. Wire.read()
только прочитает следующее значение из буфера, удалит его оттуда и вернет значение. Никаких действий I2C в этот момент, поэтому delay(10)
бесполезен
TL;DR:
- Всегда используйте правильный адрес без бита чтения/записи:
0x6E
- Инициализируйте и настройте библиотеку
Wire
только один раз вsetup()
- Удалите
Wire.beginTransmission()
иWire.endTransmission()
из функцииloop()
, поскольку вы выполняете только основное чтение там. - Удалите строки
delay(10);
между вызовамиWire.read()
.
Спасибо за ответ, Крисл, это многое проясняет! Еще один вопрос, если позволите, чтобы инициировать чтение с MCP3424, мне нужно немного обновить регистр конфигурации. Означает ли это, что каждый раз, когда я хочу получить показания, мне нужно выполнять три проводные функции: beginTransmission(0x6E), Wire.write() и endTransmission?, @Asyu7
Да, в режиме One Shot вам всегда нужно выполнять beginTransmission()
, write()
, endTransmission()
, requestFrom()
и read()
для каждого измерения. Но поскольку в настоящее время вы непрерывно считываете данные с АЦП, вам следует рассмотреть возможность использования режима непрерывного измерения, чтобы измерение автоматически запускалось с фиксированным интервалом, и вам нужно было только запрашивать данные у АЦП., @chrisl
Хорошо, я понимаю, как я могу это сделать, да, но в будущем я планирую читать со всех 4 каналов, поэтому мне придется каждый раз менять байт конфигурации и использовать все 5 команд при каждом изменении, верно?, @Asyu7
Да, когда вы меняете каналы по каждому запросу, вы должны использовать все вышеперечисленные команды, чтобы сначала установить правильный байт конфигурации, запустить преобразование, а затем собственно запросить данные., @chrisl
- Варианты протокола для обмена данными между Arduino и ESP8266
- Проблемные данные I2C к датчику GY955/BNO055 (Китай)
- Сервопривод продолжает сбрасывать положение, когда нет разницы в полученном значении?
- Плата управления реле I2C от двух Arduino Uno
- Доступ к мультиплексным контактам I2C и UART STM32F103 в arduino IDE
- Как назвать датчики температуры вместо адреса печати с помощью датчиков ds2482-100 и ds18b20 - Справка
- Два датчика с использованием I2C
- Не могу заставить MMC3416xPJ работать
не инициализируйте библиотеку в каждом цикле. удалить начало и установить часы. и requestFrom не должен быть заключен в транзакцию, @Juraj
извините за транзакцию = beginTransmmition endTransmmition, @Juraj
использовать библиотеку. например https://github.com/bersch/MCP3424, @Juraj