I2C - программная отправка данных
Я пытаюсь считать напряжение с источника питания на Arduino Micro, а затем отправить его на осциллограф через I2C (MCP4725). Я бы использовал контакты по умолчанию на Micro, но я хочу подключить три I2C, а шина по умолчанию допускает только два. Поэтому я пытаюсь использовать библиотеку SoftI2CMaster
.Я просмотрел примеры и документацию, но не могу заставить ее отправлять какие-либо данные. Я успешно просканировал (из примеров) и нашел адреса I2C, поэтому я предполагаю, что проблема в конце моего кода.
Будем признательны за любые советы!
#define SDA_PORT PORTD
#define SDA_PIN 4 // = A4
#define SCL_PORT PORTC
#define SCL_PIN 6 // = A5
#include <SoftWire.h>
#define I2C_7BITADDR 0x62 //MCP4725
SoftWire Wire = SoftWire();
int aPin;
void setup(void) {
Serial.begin(9600);
Wire.begin();
}
void loop(void){
aPin = analogRead(A0); //читаем из блока питания
Wire.beginTransmission(I2C_7BITADDR);
Wire.write(aPin); //отправляем напряжение на osc.
Wire.endTransmission();
}
@Hayden Bartsch, 👍0
1 ответ
Лучший ответ:
Похоже, основная проблема заключается в том, что вы не придерживаетесь протокола связи MCP. Вы просто пытаетесь отправить на него только чисто аналоговые измерения.
Посмотрите на это изображение со страницы 18 таблицы данных MCP4725:
Он описывает работу в быстром режиме, который, кажется, является правильным режимом для этого. (Аналогичные описания для других режимов можно найти под этим изображением). Первый байт создается библиотекой SoftWire, а вот за следующее отвечаете вы. следующие 2 байта состоят (в этом порядке) из 2 битов, устанавливающих быстрый режим, 2 битов для выбора отключения питания устройств (оба нулевые для нормальной работы ЦАП), а затем 12 бит фактического значения напряжения для ЦАП.
Сейчас я покажу еще одну проблему с вашим кодом. Вы считываете аналоговое напряжение с помощью АЦП ардуино, которое представляет собой 10-битное число (типа int
) и используете его в
Wire.write(aPin);
Но параметр для Wire.write()
определяется как uint8_t
(см. line92 в SoftWire.h библиотеки Softwire), что означает, что ваше значение int
преобразуется, и вы теряете все биты выше 255 (младший байт), потому что uint8_t
просто не может хранить больше.
Что вам нужно сделать: вы должны объединить байты данных I2C в своем коде, а затем отправить их. Это может выглядеть так:
byte byte1 = (aPin & 0x0F00) >> 8;
byte byte2 = (aPin & 0xFF);
В этом коде используются побитовые операторы. &
выполняет операцию И, >>
сдвигает биты вправо на величину после оператора. 0x
обозначает значение в шестнадцатеричном представлении (двоичное представление будет 0b
). Итак, для первого байта мы выполняем И со значением 0x0F00
, что даст нам значение только с первыми 4 битами второго байта aPin
. Затем мы сдвигаем результат на 8 бит вправо, чтобы оставшиеся данные были хорошо выровнены справа от вашего байта. Нам не нужно включать сюда биты режима и биты выбора отключения питания, так как они в любом случае равны нулю. Если вы хотите установить их ненулевыми, вы можете использовать побитовое ИЛИ (конечно, с правильным сдвигом, чтобы биты имели правильное положение в результирующем байте):
byte mode_bits = 0b10;
byte power_down_bits = 0b11;
byte byte1 = (mode_bits << 6) | (power_down_bits << 4) | (aPin & 0x0F00) >> 8;
Затем вы можете отправить эти байты через I2C:
Wire.beginTransmission(I2C_7BITADDR);
Wire.write(byte1);
Wire.write(byte2);
Wire.endTransmission();
Это должно работать, хотя обратите внимание, что я не проверял это. Я только что прочитал техническое описание, которое всегда необходимо прочитать.
Что произошло с вашим исходным кодом: В техническом описании для команды "Записать регистр DAC" (которая использует 4 байта, включая байт адреса) указано следующее:
Устройство игнорирует любые частично полученные байты данных, если I2C связь с Мастером заканчивается до заполнения 4-го байта.
Поэтому он просто отбрасывает все незавершенные сообщения I2C. Хотя это не указано четко, мы можем быть уверены, что то же самое происходит и для других режимов работы. Вы отправляли только 1 байт, поэтому MCP счел сообщение неполным и проигнорировал его.
Тем не менее, существует принцип обхода ограничения только в 2 устройства на одной шине, о котором я тоже узнал совсем недавно. Возможно, вы не захотите идти этим путем, но это отличная идея и действительное решение проблемы с лимитом.
Каждый MCP имеет 1 адресный контакт A0, который устанавливает 1 бит адреса, что дает 2 возможных адреса. На шине I2C не должно быть более 1 устройства с одинаковым адресом. Но если этот удвоенный адрес никогда не вызывается, с шиной проблем нет.
Вы должны подключить контакты A0 каждого MCP к одному цифровому выходному контакту Arduino. Установив состояние этих выходных контактов, вы можете изменить адрес MCP (требование состоит в том, чтобы MCP фактически проверял контакт A0 во время работы, но в техническом описании это предполагается). Теперь вы держите каждый вывод A0 на одном уровне, чтобы все MCP имели одинаковый адрес. Чтобы связаться с ним, вы должны изменить состояние его контакта A0, чтобы изменить его адрес. Теперь этот МКП является единственным МКП с таким адресом (все остальные МКП имеют другой адрес). Теперь вы можете общаться с ним. Если вы хотите связаться с другим MCP, вы сбрасываете контакт A0 первого MCP, а затем меняете контакт A0 следующего MCP.
Так вы убедитесь, что на одном из двух адресов всегда будет максимум 1 MCP, а другой адрес вы никогда не используете. Вы можете использовать столько MCP, сколько у вас есть цифровых выходных контактов, чтобы изменить их адреса.
- Подключение нескольких MPU 6050 к Micro/Lenardo
- Не удается вызвать функцию при обратном вызове для onRequest()
- Сброс Arduino Uno в коде
- Отправка и получение различных типов данных через I2C в Arduino
- Как работают функции вне цикла void?
- Как отображать переменные на 0,96-дюймовом OLED-дисплее с библиотекой u8glib?
- Как отправить строку на мастер с помощью i2c
- Как выбрать альтернативные контакты I2C на ESP32?
да! ты легенда! работал отлично. большое спасибо за хорошо написанный ответ. я действительно оценил разбивку того, почему мой код не будет работать., @Hayden Bartsch