Интерфейс i2c и arduino

I2C at the Hardware Level

Signals

Each I2C bus consists of two signals: SCL and SDA. SCL is the clock signal, and SDA is the data signal. The clock signal is always generated by the current bus controller; some peripheral devices may force the clock low at times to delay the controller sending more data (or to require more time to prepare data before the controller attempts to clock it out). This is called «clock stretching» and is described on the protocol page.

Unlike UART or SPI connections, the I2C bus drivers are «open drain», meaning that they can pull the corresponding signal line low, but cannot drive it high. Thus, there can be no bus contention where one device is trying to drive the line high while another tries to pull it low, eliminating the potential for damage to the drivers or excessive power dissipation in the system. Each signal line has a pull-up resistor on it, to restore the signal to high when no device is asserting it low.

Notice the two pull-up resistors on the two communication lines.

Resistor selection varies with devices on the bus, but a good rule of thumb is to start with 4.7kΩ resistor and adjust down if necessary. I2C is a fairly robust protocol, and can be used with short runs of wire (2-3m). For long runs, or systems with lots of devices, smaller resistors are better.

Most I2C devices offered in the SparkFun catalog usually include pull-up resistors for the SCL and SDA pins. If you have many I2C devices on the same bus, you may need to adjust the equivalent value for the pull-up resistors by disconnecting the pull-up resistors on a few of the devices. Depending on what is connected to the bus and the design, you can include about 7x I2C devices on the same bus. However, if you are having any issues, you can cut the two traces connecting to the center jumper pad using an hobby knife or to disconnect the resistors on certain boards. As you can see, the design of the GPS board on the left used traces to connect the jumper pads for the pull-up resistors. The design of the GPS board on the right used solder to connect the jumper pads for the pull-up resistors.

Trace Connecting Jumper Pads on the SAM-M8Q Solder Connecting Jumper Pads on the XA1110

If your design requires longer runs of wire, you can use a dedicated IC to extend the signal such as the PCA9615.

Qwiic Differential I2C Bus Extender (PCA9615) Hookup Guide

May 31, 2018

Learn how to extend the range of your I2C communication bus with the Qwiic differential I2C bus extender (PCA9615 ) breakout board.

9

Signal Logic Levels

Since the devices on the bus don’t actually drive the signals high, I2C allows for some flexibility in connecting devices with different I/O voltages. In general, in a system where one device is at a higher voltage than another, it may be possible to connect the two devices via I2C without any level shifting circuitry in between them. The trick is to connect the pull-up resistors to the lower of the two voltages. This only works in some cases, where the lower of the two system voltages exceeds the high-level input voltage of the the higher voltage system—for example, a 5V Arduino and a 3.3V accelerometer. Depending on the design of the Arduino or the I2C device, we recommend using a logic level converter to be consistent and avoid damaging any device on the bus.

If the voltage difference between the two systems is too great (say, 5V and 2.5V), SparkFun offers a simple I2C level shifter board — e.g. the PCA9306 Level Translator Breakout. This dedicated level shifter board the board also includes an enable line, it can be used to disable communications to selected devices. This is useful in cases where more than one device with the same address is to be connected to a single controller — Wii Nunchucks are a good example. There are also bi-directional logic level converters that can be used.

added to your cart!

BOB-12009

$2.95

111

136

added to your cart!

$4.25

19

Introduction to I2C Communication

I2C combines the best features of SPI and UARTs. With I2C, you can connect multiple slaves to a single master (like SPI) and you can have multiple masters controlling single, or multiple slaves. This is really useful when you want to have more than one microcontroller logging data to a single memory card or displaying text to a single LCD.

Like UART communication, I2C only uses two wires to transmit data between devices:

SDA (Serial Data) – The line for the master and slave to send and receive data.

SCL (Serial Clock) – The line that carries the clock signal.

I2C is a serial communication protocol, so data is transferred bit by bit along a single wire (the SDA line).

Like SPI, I2C is synchronous, so the output of bits is synchronized to the sampling of bits by a clock signal shared between the master and the slave. The clock signal is always controlled by the master.

Источники существенной емкости

Микросхемы, используемые в схеме

Спецификация NXP указывает «максимальную емкость для каждого вывода ввода/вывода» 10 пФ. Каждая добавленная вами микросхема увеличит общую емкость шины примерно на 10 пФ (смотрите техническое описание для конкретной микросхемы), затем вы также должны рассмотреть емкость, связанную с дорожками, которые соединяют эту микросхему с шиной.

Емкость медной дорожки

Когда мы здесь говорим о «емкости медной дорожки», то имеем в виду одиночную дорожку над диэлектриком над полигоном земли на печатной плате. Емкостная связь между сигнальными линиями I2C и плоскостью земли может быть существенной, если микросхемы находятся далеко друг от друга, или если на шине I2C находятся несколько микросхем. Для длинных расстояний отделяйте линии I2C друг от друга расстоянием, равным нескольким ширинам дорожек (или размещайте между сигнальными трассами трассы Vdd и земли), чтобы уменьшить емкостные эффекты связи между двумя сигнальными линиями.

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

\ \approx \frac{0.264\tfrac{}{}(\epsilon_r+1.41)}{\ln\left(\frac{0.598\tfrac{1}{}\cdot \text{высота_слоя}} {0.08\tfrac{1}{} \cdot \text{ширина_дорожки}+0.1\tfrac{1}{}\cdot \text{толщина_дорожки}}\right)}\]

Формула модифицирована из «High Speed Digital Design» Джонсона и Грэхема.

Параметры микрополосковой линии

Ниже приведен расчет для смежных слоев четырехслойного стека со следующими реалистичными параметрами: εFR4 = 4,5, ширина дорожки = 0,13 мм, высота слоя = 0,23 мм, толщина дорожки = 0,035 мм.

\ \approx \frac{0.264\tfrac{}{}(4.5+1.41)}{\ln\left(\frac{0.598\tfrac{1}{}\cdot 0.23\text{}} {0.08\tfrac{1}{} \cdot 0.13\text{}+0.1\tfrac{1}{}\cdot 0.035\text{}}\right)}=0.68\tfrac{пФ}{см}\]

Влияние апертур на емкость микрополосковой линии

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

Апертура в слое металлизации

Итак, какое влияние это оказывает на общую емкость? Если мы используем те же параметры, что и в предыдущем расчете, но добавим 0,965 мм между сигнальной дорожкой и плоскостью земли, мы достигнем уменьшения емкости на ~40%. Если слой на вашей печатной плате позволяет иметь достаточно большой проем непосредственно под сигнальной дорожкой, это может быть целесообразным улучшением в проектах с очень длинными трассами.

\ \approx \frac{0.264\tfrac{}{}(4.5+1.41)}{\ln\left(\frac{0.598\tfrac{1}{}\left (0.23\text{}+0.035 \text{}+0.93\text{}\right )} {0.08\tfrac{1}{} \cdot 0.13\text{}+0.1\tfrac{1}{}\cdot 0.035\text{}}\right)}=0.40\tfrac{пФ}{см}\]

Сканер I2C интерфейса (шины) Ардуино

Для этого занятия нам потребуется:

  • плата Arduino Uno / Arduino Nano / Arduino Mega;
  • макетная плата;
  • два текстовых дисплея 1602 I2C;
  • любое устройство с I2C интерфейсом;
  • провода «папа-папа», «папа-мама».

Подключение двух дисплеев 1602 I2C к Ардуино

Перед тем, как управлять несколькими объектами, подключенных к IIC шине, необходимо узнать их адреса. Для этого используется программа — сканер I2C Arduino, которая позволяет узнать адреса всех устройств, подключенных в данный момент к шине. Соберите схему из двух текстовых экранов с IIC модулем (можно подключить только одно устройство), подключенных к Ардуино Уно, и загрузите следующий скетч.

Скетч. Сканер шины i2c для Arduino

#include <Wire.h>
 
void setup(){
    Wire.begin();    
    Serial.begin(9600);
} 
 
void loop(){
    byte error, address;
    int nDevices;
 
    Serial.println("Scanning...");
 
    nDevices = 0;
    for(address = 8; address < 127; address++ ){
        Wire.beginTransmission(address);
        error = Wire.endTransmission();
 
        if (error == 0){
            Serial.print("I2C device found at address 0x");
            if (address < 16)
                Serial.print("0");
            Serial.print(address,HEX);
            Serial.println(" !");
 
            nDevices++;
        }
        else if (error == 4) {
            Serial.print("Unknow error at address 0x");
            if (address < 16)
                Serial.print("0");
            Serial.println(address,HEX);
        } 
    }
    if (nDevices == 0)
        Serial.println("No I2C devices found\n");
    else
        Serial.println("done\n");
 
    delay(5000);
}

Пояснения к коду:

  1. данный код позволяет узнать все адреса устройств, подключенных к шине IIC. Если устройство не было подключено или подключено неправильно — на мониторе порта будет выходить сообщение, что устройства не найдены;
  2. ниже, на скриншоте монитора порта Arduino IDE, выводится адрес LCD 1602.

Сканер шины i2c для Arduino с LCD дисплеем

3Библиотека «Wire» для работы с IIC

Для облегчения обмена данными с устройствами по шине I2C для Arduino написана стандартная библиотека Wire. Она имеет следующие функции:

Функция Назначение
begin(address) инициализация библиотеки и подключение к шине I2C; если не указан адрес, то присоединённое устройство считается ведущим; используется 7-битная адресация;
requestFrom() используется ведущим устройством для запроса определённого количества байтов от ведомого;
beginTransmission(address) начало передачи данных к ведомому устройству по определённому адресу;
endTransmission() прекращение передачи данных ведомому;
write() запись данных от ведомого в ответ на запрос;
available() возвращает количество байт информации, доступных для приёма от ведомого;
read() чтение байта, переданного от ведомого ведущему или от ведущего ведомому;
onReceive() указывает на функцию, которая должна быть вызвана, когда ведомое устройство получит передачу от ведущего;
onRequest() указывает на функцию, которая должна быть вызвана, когда ведущее устройство получит передачу от ведомого.

Где применяется протокол I2C

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

ЖК дисплей Arduino LCD 1602

LCD 1602

Краткое описание пинов LCD 1602

Давайте посмотрим на выводы LCD1602 повнимательней:

Каждый из выводов имеет свое назначение:

  1. Земля GND;
  2. Питание 5 В;
  3. Установка контрастности монитора;
  4. Команда, данные;
  5. Записывание и чтение данных;
  6. Enable;

7-14. Линии данных;

  1. Плюс подсветки;
  2. Минус подсветки.

Технические характеристики дисплея:

  • Символьный тип отображения, есть возможность загрузки символов;
  • Светодиодная подсветка;
  • Контроллер HD44780;
  • Напряжение питания 5В;
  • Формат 16х2 символов;
  • Диапазон рабочих температур от -20С до +70С, диапазон температур хранения от -30С до +80 С;
  • Угол обзора 180 градусов.

Схема подключения LCD к плате Ардуино без i2C

Стандартная схема присоединения монитора напрямую к микроконтроллеру Ардуино без I2C выглядит следующим образом.

Из-за большого количества подключаемых контактов может не хватить места для присоединения нужных элементов. Использование I2C уменьшает количество проводов до 4, а занятых пинов до 2.

Генерация пользовательских символов для LCD

Если вы находите символы на дисплее неподходящими и неинтересными, вы можете создать свои собственные символы (глиф) для своего ЖК-дисплея. Пользовательские символы чрезвычайно полезны в том случае, когда вы хотите отобразить символ, который не является частью стандартного набора символов ASCII.

Как мы уже обсуждали ранее в этом руководстве, символ на дисплее формируется в матрице 5×8 пикселей, поэтому вам нужно определить свой пользовательский символ в этой матрице. Для определения символа необходимо использовать функцию createChar() библиотеки LiquidCrystal.

Для использования  createChar()  сначала необходимо назначить массив из 8 байт. Каждый байт (учитывается только 5 бит) в массиве определяет одну строку символа в матрице 5×8. В то время как нули и единицы в байте указывают, какие пиксели в строке должны быть включены, а какие-выключены.

Генератор символов LCD

Создание собственного символа до сих пор было непросто! Поэтому было создано небольшое приложение под названием «Генератор пользовательских символов» для LCD.

Вы видите синюю сетку ниже? Вы можете нажать на любой из 5 × 8 пикселей, чтобы установить/очистить этот конкретный пиксель. И когда вы нажимаете на пиксели, код для символа генерируется рядом с сеткой. Этот код может быть непосредственно использован в вашем скетче Arduino.

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

Следующий скриншот демонстрирует, как вы можете использовать эти пользовательские символы на дисплее.

//  подключаем библиотеку LiquidCrystal:
#include <LiquidCrystal.h>

// Создаем LCD объект. Выводы: (rs, enable, d4, d5, d6, d7)
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// создадим несколько пользовательских символов
byte Heart = {
0b00000,
0b01010,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000,
0b00000
};

byte Bell = {
0b00100,
0b01110,
0b01110,
0b01110,
0b11111,
0b00000,
0b00100,
0b00000
};


byte Alien = {
0b11111,
0b10101,
0b11111,
0b11111,
0b01110,
0b01010,
0b11011,
0b00000
};

byte Check = {
0b00000,
0b00001,
0b00011,
0b10110,
0b11100,
0b01000,
0b00000,
0b00000
};

byte Speaker = {
0b00001,
0b00011,
0b01111,
0b01111,
0b01111,
0b00011,
0b00001,
0b00000
};


byte Sound = {
0b00001,
0b00011,
0b00101,
0b01001,
0b01001,
0b01011,
0b11011,
0b11000
};


byte Skull = {
0b00000,
0b01110,
0b10101,
0b11011,
0b01110,
0b01110,
0b00000,
0b00000
};

byte Lock = {
0b01110,
0b10001,
0b10001,
0b11111,
0b11011,
0b11011,
0b11111,
0b00000
};

void setup() 
{
  // инициализируем LCD и устанавливаем количество столбцов и строк: 
  lcd.begin(16, 2);

  // создание нового символа
  lcd.createChar(0, Heart);
  // создание нового символа
  lcd.createChar(1, Bell);
  // создание нового символа
  lcd.createChar(2, Alien);
  // создание нового символа
  lcd.createChar(3, Check);
  // создание нового символа
  lcd.createChar(4, Speaker);
  // создание нового символа
  lcd.createChar(5, Sound);
  // создание нового символа
  lcd.createChar(6, Skull);
  // создание нового символа
  lcd.createChar(7, Lock);

  // Очищаем LCD дисплей 
  lcd.clear();

  // Печатаем сообщение на LCD.
  lcd.print("Custom Character");
}

// Печатаем все пользовательские символы
void loop() 
{ 
  lcd.setCursor(0, 1);
  lcd.write(byte(0));

  lcd.setCursor(2, 1);
  lcd.write(byte(1));

  lcd.setCursor(4, 1);
  lcd.write(byte(2));

  lcd.setCursor(6, 1);
  lcd.write(byte(3));

  lcd.setCursor(8, 1);
  lcd.write(byte(4));

  lcd.setCursor(10, 1);
  lcd.write(byte(5));

  lcd.setCursor(12, 1);
  lcd.write(byte(6));

  lcd.setCursor(14, 1);
  lcd.write(byte(7));
}

После включения библиотеки нам нужно инициализировать пользовательский массив из восьми байтов.

byte Heart = {
0b00000,
0b01010,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000,
0b00000
};

В настройках мы должны создать пользовательский символ, используя функцию createChar(). Эта функция принимает два параметра. Первый — это число от 0 до 7, чтобы зарезервировать один из 8 поддерживаемых пользовательских символов. Второй параметр — это имя массива байтов.

// создание нового символа
lcd.createChar(0, Heart);

Далее в цикле для отображения пользовательского символа мы используем функцию write(), а в качестве параметра мы используем номер символа, который мы зарезервировали.

// byte(0) покажет символ Heart (сердце).
lcd.write(byte(0));

Steps of I2C Data Transmission

1. The master sends the start condition to every connected slave by switching the SDA line from a high voltage level to a low voltage level before switching the SCL line from high to low:

2. The master sends each slave the 7 or 10 bit address of the slave it wants to communicate with, along with the read/write bit:

3. Each slave compares the address sent from the master to its own address. If the address matches, the slave returns an ACK bit by pulling the SDA line low for one bit. If the address from the master does not match the slave’s own address, the slave leaves the SDA line high.

4. The master sends or receives the data frame:

5. After each data frame has been transferred, the receiving device returns another ACK bit to the sender to acknowledge successful receipt of the frame:

6. To stop the data transmission, the master sends a stop condition to the slave by switching SCL high before switching SDA high:

5 ответов

14

Для быстрого режима и подтягивания резистора емкость должна быть меньше 200 пФ, в соответствии с этим Документом NXP Спецификация I2C-шины и руководство пользователя .

С текущими источниками вы можете перейти на 400pF, но не с резисторами.

Если ваш провод составляет 20pF /30 см, и у вас есть еще 50pF от паразитной и входной емкости, вы ограничены длиной кабеля 2,25 м. Различные предположения приведут к разным числам.

13

Длины безумного звучания, такие как 10,25 и 100 м, вполне возможны, и я часто использую этот метод (с UART не I2C, но метод стоит), когда мне нужно быстро собрать вещи. Однако это не самый лучший способ.

Ключ должен знать порог входного напряжения. Убедитесь, что падение напряжения в проводке заземления значительно ниже этого, или передатчик с высоким потенциалом заземления не сможет достаточно сильно натянуть напряжение. Отсутствие толерантности к смещениям земли IMHO является самой большой причиной использования RS485 или может трансиверы (I2C over CAN упоминается в нескольких примечаниях к применению).

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

Но, давайте возьмем CAT5, например. CAT5 не может быть выше 52pf /m, или это не CAT5.

100 м кабеля 52pf имеют емкость 5200pf или 5.2nf.

5.2n раз 20kohms (pullup) дает постоянную времени около 104 микросекунд. Это ограничивает скорость примерно до 10 кГц или около того.

Используя подтягивания 2.2kohm, вы, вероятно, можете добраться до 100 кГц.

Я слышал, что устройства должны иметь резистор на SDL и SCK из-за большой емкостной нагрузки, которой они управляют, примерно 180 или 200 Ом.

Но, честно говоря, I2C — это вовсе не путь на большие расстояния. CAN-трансиверы или RS485, используемые с обычным UART, — это надежное решение с очень хорошей защитой от отказа, сопротивлением ESD, скоростью, расстоянием и т. Д., При стоимости доллара или чипе, смещения земли не имеют значения почти так же, как и вы свободно переносить электроэнергию вместе с данными.

Единственным недостатком является то, что трансивер может доставлять 70 мс и 1 или 2ma только прослушивание, поэтому I2C или прямой TTL UART могут быть полезны в экстремальных ситуациях с низким энергопотреблением, но подумайте, сколько времени вы фактически тратите на отправку.

6

Я работаю в компании, создающей USB-датчики. Большинство из них основаны на чипах датчиков I2C, эти устройства могут быть разделены на две части, поэтому вы можете установить процессорную часть в одном месте, а сенсорную часть — в другую. Мы провели довольно много тестов на подключении I2C между процессором устройства и датчиками I2C. На частоте 100 кГц, с хорошим протоколом восстановления ошибок, 25 м можно легко получить с помощью основных проводов. Мы даже смогли достичь 100 м один раз с помощью кабеля CAT5.

4

Что-то вроде P82B96 от NXP можно использовать для изменения уровней напряжения на шине, что позволяет значительно увеличить расстояния.

Существуют и другие чипы с аналогичной функциональностью.

3

IIC — это синхронный протокол и, как таковой, он может запускаться произвольно медленно, чтобы соответствовать системным требованиям относительно расстояния и шума.

Объяснение скетча для ведомого

Для ведомого устройства существует небольшая разница в кодировании I2C-связи. Первая разница заключается в адресе .

Для ведомых устройств адрес является обязательным. Для нашего проекта адрес для ведомого устройства будет 0x08. Это может быть любой адрес, но убедитесь, что он уникален в сети I2C.

Некоторые I2C ведомые устройства также имеют определенные I2C-адреса, поэтому сначала проверьте спецификацию.

Мы присоединим I2C сеть в качестве ведомого устройства, добавив код внутри .

Обработчики событий

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

Обработчики событий — это части кода, которые управляют событиями, с которыми наше устройство, скорее всего, столкнется во время работы.

Wire.onReceive()

В части скетча мы добавляем функцию для регистрации функции (обработчика), которая будет управлять полученными данными.

Мы вызываем нашу функцию-обработчик

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

В конце эскиза находится код функции-обработчика. Он инициализируется как . Параметр содержит количество байт полученных данных.

Wire.onRequest()

Следующий обработчик события, который мы будем использовать — . Эта функция используется на подчиненных устройствах и работает аналогично .

Единственное отличие заключается в том, что она обрабатывает события запроса данных. Запросы данных поступают от основных устройств.

В функцию мы добавляем код . А в конце нашего эскиза добавляем функцию

Обратите внимание, что обработчики не принимают никаких параметров. Функция содержит только

Нам не нужны и , потому что библиотека Wire уже обрабатывает ответы от ведомых устройств.

References[edit]

  1. Record Sheets: 3085 Unabridged — Project Phoenix, p. 272
  2. Recognition Guide: ilClan, vol. 4, p30 — BV2 same PPU.
  3. Objectives: The Clans, p. 6
  4. Recognition Guide: ilClan, vol. 4, p. 10 — Warhammer IIC Snow Raven production site
  5. Technical Readout: 3055, p. 108
  6. Record Sheets: 3085 Unabridged — Project Phoenix, p. 274
  7. Technical Readout: Project Phoenix, p. 70
  8. Technical Readout: 3085, p. 282
  9. Record Sheets: 3085 Unabridged — Project Phoenix, p. 276
  10. Record Sheets: 3085 Unabridged — Project Phoenix, p. 277
  11. Record Sheets: 3085 Unabridged — Project Phoenix, p. 278
  12. Technical Readout: 3085, p. 283
  13. Record Sheets: 3085 Unabridged — Project Phoenix, p. 281
  14. Record Sheets: 3145 New Tech, New Upgrades, p. 166
  15. Record Sheets: 3145 New Tech, New Upgrades, p. 167
  16. Record Sheets: 3145 New Tech, New Upgrades, p. 168
  17. Recognition Guide: ilClan Vol.4, p. 10
  18. MechWarrrior Online Warhammer IIC Sale Page
  19. MechWarrior Online 2018 Holiday Bonus
  20. BattleMech Manual, p. 95 — Design Quirk Table — Warhammer IIC Entry.
  21. Wolf Hunters p. 145

Открытый сток

Определяющей особенностью I2C является то, что каждое устройство на шине, должно подключаться к линиям тактового сигнала (сокращенно SCL) и сигнала данных (сокращенно SDA) через выходные драйверы с открытым стоком (или открытым коллектором). Давайте посмотрим, что это на самом деле означает. Сначала рассмотрим типовой CMOS (инвертирующий) выходной каскад:

Если на входе присутствует высокий логический уровень, NMOS транзистор открыт, а PMOS транзистор закрыт. Таким образом, выход имеет низкоомное соединение с землей. Если на входе присутствует низкий логический уровень, ситуация меняется на противоположную, а выход имеет низкоомное соединение с VDD. Это называется двухтактным выходным каскадом, хотя это название не особенно информативно, поскольку оно не подчеркивает низкое сопротивление соединений, которые управляют выходом. В общем случае вы не можете напрямую соединять два двухтактных выхода, поскольку ток будет свободно протекать от VDD до земли, если на одном выходе выдается логическая единица, а на другом – логический ноль.

Теперь рассмотрим схему с открытым стоком:

PMOS транзистор был заменен резистором, внешним по отношению к микросхеме. Если на входе присутствует высокий логический уровень, NMOS транзистор обеспечивает низкоомное соединение с землей. Но если на вход подается низкий логический уровень, NMOS транзистор выглядит как разомкнутая цепь, а это означает, что выход подтягивается к VDD через внешний резистор. Такой механизм приводит к двум важным отличиям. Во-первых, появляется неочевидное рассеивание мощности, когда на выходе низкий логический уровень, поскольку ток протекает через резистор, через канал NMOS транзистора на землю (в двухтактной схеме этот ток блокируется высоким сопротивлением закрытого PMOS транзистора). Во-вторых, выходной сигнал ведет себя по-другому, когда на выходе высокий логический уровень, так как выход подключен к VDD через гораздо более высокое сопротивление (обычно не менее 1 кОм). Эта особенность позволяет напрямую соединять два (и более) устройства с открытым стоком: даже если на одном из них низкий логический уровень, а на другом – высокий логический уровень, то подтягивающий резистор гарантирует, что ток не протекает свободно от VDD на землю.

Некоторые последствия использования на шине схемы с открытым стоком:

  • Сигналы всегда по умолчанию находятся в состоянии логической единицы. Напримем, если ведущее устройство I2C пытается связаться с ведомым устройством, которое вдруг перестало функционировать, сигнал данных никогда не войдет в неопределенное состояние. Если ведомое устройство не управляет сигналом, то он будет считан как логическая единица. Аналогично, если ведущее устройство выключается в середине передачи, линии SCL и SDA вернутся в состояние логической единицы. Другие устройства могут определить, что шина доступна для новых передач, наблюдая, что и SCL, и SDA находятся в состоянии логической единицы в течении определенного периода времени.
  • Любое устройство на шине может безопасно приводить сигналы в состояние логического нуля, даже если другое устройство пытается привести их в состояние логической единицы. Это является основой функции «тактовой синхронизации» или «растяжки тактового сигнала» на шине I2C: ведущее устройство генерирует последовательность тактовых импульсов, но при необходимости ведомое устройство может удерживать линию SCL на низком уровне и тем самым уменьшать тактовую частоту.
  • Устройства с различными напряжениями питания могут сосуществовать на одной и той же шине, пока устройства с более низким напряжением не будут повреждены более высоким напряжением. Например, устройство 3,3 В может связываться с устройством 5 В, если SCL и SDA подтянуты до 5 В – схема с открытым стоком приводит к тому, что высокий логический уровень достигает напряжения 5 В, хотя устройство 3,3 В с типовым двухтактным каскадом не может управлять линией 5 В.

Получение данных датчика на Arduino UNO

Доступ к ячейкам памяти для запроса и чтения данных датчика через интерфейс I2C осуществляется обычным способом. Читатели, которые программировали Arduino для работы с I2C, узнают этапы,а добавленный скетч будет хорошо прокомментирован для облегчения отслеживания работы программы.

Во-первых, для использования библиотеки I2C вам необходим оператор:

Затем вам необходим I2C адрес PIC микроконтроллера. Он программно установлен в коде MPASM для PIC микроконтроллера в строке:

Этот адрес должен быть сдвинут вправо на один бит, чтобы сформировать адрес, который будет использоваться Arduino. Те, кто знаком с 7-разрядной адресацией I2C, узнают этот часто неудобный шаг. Смещение 0x32 вправо даст нам 0x19, и это будет адрес I2C, который используется Arduinio. Конечно, вы можете установить этот адрес в коде MPASM в любое доступное значение для адреса I2C, которое у вас есть.

Чтобы начать обмен, используйте:

Ниже в качестве примера приведены шаги для выдачи команды считывания датчика #2 (значение переменной было установлено в ):

Задержка в последней строке ждет, пока завершится чтение датчика, и, возможно, она длиннее, чем необходимо, но лучше быть осторожным. Вы можете попробовать уменьшить задержку, если это необходимо для вашего приложения.

На этом этапе данные от датчика DHT22 #2 должны быть в -. Чтобы запросить данные, используем следующее:

Сначала прочитаем байт статуса в .

Проверим, равен ли байт статуса (теперь в ) , что указывает на успешность выполнения команды. Затем получим 5 байтов данных DHT (из -) с помощью следующего кода:

После того, как мы поместили эти данные в программный массив -, мы преобразуем данные во влажность (RH) и температуру и, наконец, проверим совпадает ли контрольная сумма:

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

Приведенный ниже код скетча примера для Arduino просто считывает все три датчика каждые 5 секунд и отображает данные в мониторе последовательного порта.

Вывод на экран в результате работы тестового скетча Arduino

Шина I2C Ардуино описание

Микроконтроллеры Arduino используют два пина для работы по интерфейсу I2C. В Arduino Uno и Nano линии SDA соответствует аналоговый порт A4, а SCL соответствует аналоговый порт A5. На Ardunio Mega SDA — 20 пин, SCL — 21 пин. Для облегчения работы с шиной I2C и обмена данными между устройствами для Arduino IDE написана стандартная библиотека Wire (скачивать и устанавливать ее не надо).

Для каждого устройства, при подключении к микроконтроллеру, присваивается уникальный адрес (максимум можно подключить 127 устройств). Поменять адрес устройства на шине нельзя, так как он вшит в микросхему. Часто производители предоставляют возможность поменять адрес устройства в небольшом диапазоне, что дает возможность подключить к шине IIC Ардуино несколько одинаковых устройств.