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();
}

, 👍0


1 ответ


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

3

Похоже, основная проблема заключается в том, что вы не придерживаетесь протокола связи MCP. Вы просто пытаетесь отправить на него только чисто аналоговые измерения.

Посмотрите на это изображение со страницы 18 таблицы данных MCP4725:

Описание протокола I2C для 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, сколько у вас есть цифровых выходных контактов, чтобы изменить их адреса.

,

да! ты легенда! работал отлично. большое спасибо за хорошо написанный ответ. я действительно оценил разбивку того, почему мой код не будет работать., @Hayden Bartsch