Дисплей lcd1602. основы

Использование интерфейса RS-485 в Arduino

Для использования интерфейса RS-485 в плате Arduino мы будем использовать модуль 5V MAX485 TTL to RS485, в основе которого лежит микросхема Maxim MAX485. Модуль является двунаправленным и обеспечивает последовательную связь на расстояние до 1200 метров. В полудуплексном режиме он обеспечивает скорость передачи данных 2,5 Мбит/с.

Модуль 5V MAX485 TTL to RS485 использует питающее напряжение 5V и логический уровень напряжения также 5V, что позволяет без проблем подключать его к платам Arduino.

Данный модуль имеет следующие особенности:

  • работает с напряжениями 5V;
  • имеет в своем составе чип MAX485;
  • отличается низким энергопотреблением;
  • всеми его контактами можно управлять с помощью микроконтроллера;
  • размеры платы модуля: 44 x 14mm.

Внешний вид модуля RS-485 показан на следующем рисунке.

Назначение контактов (распиновка) модуля RS-485 приведена в следующей таблице.

Название контакта Назначение контакта
VCC 5V
A вход/выход линии RS-485
B вход/выход линии RS-485
GND GND (0V)
R0 выход приемника (RX pin)
RE разрешение работы приемника
DE разрешение работы передатчика
DI вход передатчика (TX pin)

Для подключения модуля к платам Arduino (UNO и NANO) мы будем использовать их последовательные порты на контактах 0 (RX) и 1 (TX). Для передачи данных модулю RS-485 мы будем использовать функцию Serial.print(), а для считывания данных из него – функцию Serial.Read() (или аналогичную).

Объяснение программы для ведомой (Slave) платы Arduino

1. Как и в ведущей плате, первым делом в программе мы должны подключить библиотеку Wire для задействования возможностей протокола I2C и библиотеку для работы с ЖК дисплеем. Также нам необходимо сообщить плате Arduino к каким ее контактам подключен ЖК дисплей.

Arduino

#include<Wire.h>
#include<LiquidCrystal.h>
LiquidCrystal lcd(2, 7, 8, 9, 10, 11);

1
2
3

#include<Wire.h>    
#include<LiquidCrystal.h>      

LiquidCrystallcd(2,7,8,9,10,11);

  1. В функции void setup():

—  мы инициализируем последовательную связь со скоростью 9600 бод/с;

Arduino

Serial.begin(9600);

1 Serial.begin(9600);

— далее мы инициализируем связь по протоколу I2C на контактах A4 и A5

В качестве адреса ведомого мы будем использовать значение 8 – очень важно здесь указать адрес ведомого;. Arduino

Wire.begin(8);

Arduino

Wire.begin(8);

1 Wire.begin(8);

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

Arduino

Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);

1
2

Wire.onReceive(receiveEvent);

Wire.onRequest(requestEvent);

— затем мы инициализируем ЖК дисплей для работы в режиме 16х2, отображаем на нем приветственное сообщение и очищаем его экран через 5 секунд.

Arduino

lcd.begin(16,2); //Initilize LCD display
lcd.setCursor(0,0); //Sets Cursor at first line of Display
lcd.print(«Circuit Digest»); //Prints CIRCUIT DIGEST in LCD
lcd
.setCursor(0,1); //Sets Cursor at second line of Display
lcd.print(«I2C 2 ARDUINO»); //Prints I2C ARDUINO in LCD
delay(5000); //Delay for 5 seconds
lcd.clear(); //Clears LCD display

1
2
3
4
5
6
7

lcd.begin(16,2);//Initilize LCD display

lcd.setCursor(,);//Sets Cursor at first line of Display

lcd.print(«Circuit Digest»);//Prints CIRCUIT DIGEST in LCD

lcd.setCursor(,1);//Sets Cursor at second line of Display

lcd.print(«I2C 2 ARDUINO»);//Prints I2C ARDUINO in LCD

delay(5000);//Delay for 5 seconds

lcd.clear();//Clears LCD display

3. Затем нам будут необходимы две функции: одна для события запроса (request event) и одна для события приема (receive event).

Для события запроса:

Эта функция будет выполняться когда ведущий будет запрашивать значение от ведомого. Эта функция будет считывать значение с потенциометра, подключенного к ведомой плате Arduino, преобразовывать его в диапазон 0-127 и затем передавать его ведущей плате.

Arduino

void requestEvent()
{
int potvalue = analogRead(A0);
byte SlaveSend = map(potvalue,0,1023,0,127);
Wire.write(SlaveSend);
}

1
2
3
4
5
6

voidrequestEvent()

{

intpotvalue=analogRead(A0);

byteSlaveSend=map(potvalue,,1023,,127);

Wire.write(SlaveSend);

}

Для события приема:

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

Arduino

void receiveEvent (int howMany)
{
SlaveReceived = Wire.read();
}

1
2
3
4

voidreceiveEvent(inthowMany)

{

SlaveReceived=Wire.read();

}

4. В функции Void loop():

Мы будем непрерывно отображать принятые от ведущей платы значения на экране ЖК дисплея.

Arduino

void loop(void)
{
lcd.setCursor(0,0); //Sets Currsor at line one of LCD
lcd.print(«>> Slave <<«); //Prints >> Slave << at LCD
lcd.setCursor(0,1); //Sets Cursor at line two of LCD
lcd.print(«MasterVal:»); //Prints MasterVal: in LCD
lcd.print(SlaveReceived); //Prints SlaveReceived value in LCD received from Master
Serial.println(«Slave Received From Master:»); //Prints in Serial Monitor
Serial.println(SlaveReceived);
delay(500);
lcd.clear();
}

1
2
3
4
5
6
7
8
9
10
11
12

voidloop(void)

{

lcd.setCursor(,);//Sets Currsor at line one of LCD

lcd.print(«>>  Slave  <<«);//Prints >> Slave << at LCD

lcd.setCursor(,1);//Sets Cursor at line two of LCD

lcd.print(«MasterVal:»);//Prints MasterVal: in LCD

lcd.print(SlaveReceived);//Prints SlaveReceived value in LCD received from Master

Serial.println(«Slave Received From Master:»);//Prints in Serial Monitor

Serial.println(SlaveReceived);

delay(500);

lcd.clear();

}

После того как вы соберете всю схему проекта и загрузите обе программы в платы Arduino вы можете приступать к тестированию работы проекта. Вращая потенциометр на одной стороне вы должны увидеть изменяющиеся значения на экране ЖК дисплея на другой стороне.

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

How to create and display custom characters?

With the function  it is possible to create and display custom characters on the LCD. This is especially useful if you want to display a character that is not part of the standard ASCII character set.

CGROM and CGRAM

LCDs that are based on the Hitachi HD44780 LCD controller have two types of memory: CGROM and CGRAM (Character Generator ROM and RAM). CGROM generates all the 5 x 8 dot character patterns from the standard 8-bit character codes. CGRAM can generate user-defined character patterns.

For 5 x 8 dot displays, CGRAM can write up to 8 custom characters and for 5 x 10 dot displays 4. For more info see the datasheet.

Custom character example code

The following example sketch creates and displays eight custom characters (numbered 0 – 7).

You can copy the code by clicking on the button in the top right corner of the code field.

/* Arduino example code to display custom characters on I2C character LCD. More info: www.www.makerguides.com */

// Include the library:
#include <LiquidCrystal_I2C.h>

// Create lcd object of class LiquidCrystal_I2C:
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2); // Change to (0x27,20,4) for 20x4 LCD.

// Make custom characters:
byte Heart[] = {
  B00000,
  B01010,
  B11111,
  B11111,
  B01110,
  B00100,
  B00000,
  B00000
};

byte Bell[] = {
  B00100,
  B01110,
  B01110,
  B01110,
  B11111,
  B00000,
  B00100,
  B00000
};

byte Alien[] = {
  B11111,
  B10101,
  B11111,
  B11111,
  B01110,
  B01010,
  B11011,
  B00000
};

byte Check[] = {
  B00000,
  B00001,
  B00011,
  B10110,
  B11100,
  B01000,
  B00000,
  B00000
};

byte Speaker[] = {
  B00001,
  B00011,
  B01111,
  B01111,
  B01111,
  B00011,
  B00001,
  B00000
};

byte Sound[] = {
  B00001,
  B00011,
  B00101,
  B01001,
  B01001,
  B01011,
  B11011,
  B11000
};

byte Skull[] = {
  B00000,
  B01110,
  B10101,
  B11011,
  B01110,
  B01110,
  B00000,
  B00000
};

byte Lock[] = {
  B01110,
  B10001,
  B10001,
  B11111,
  B11011,
  B11011,
  B11111,
  B00000
};

void setup() {
  // Initialize LCD and turn on the backlight:
  lcd.init();
  lcd.backlight();

  // Create new characters:
  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);

  // Clear the LCD screen:
  lcd.clear();

  // Print a message to the lcd:
  lcd.print("Custom Character");
}

// Print all the custom characters:
void loop() {
  lcd.setCursor(0, 1);
  lcd.write(0);

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

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

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

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

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

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

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

You should see the following output on the LCD:

How the code works

After including the library and creating the LCD object, the custom character arrays are defined. Each array consists of 8 bytes (only 5 bits are considered). There is 1 byte for each row of the 5 x 8 led matrix. In this example, 8 custom characters are created.

// Make custom characters:
byte Heart[] = {
  B00000,
  B01010,
  B11111,
  B11111,
  B01110,
  B00100,
  B00000,
  B00000
};

When looking closely at the array, you will see the following. Each row consists of 5 numbers corresponding to the 5 pixels in a 5 x 8 dot character. A 0 means pixel off and a 1 means pixel on. The prefix ‘B’ is the Arduino specific binary formatter.

It is possible to edit each row by hand, but I recommend using this visual tool on GitHub. This application automatically creates the character array and you can click on the pixels to turn them on or off.

In the setup, the custom characters are created with .

The first argument in this function is the number of the custom character (0-7) and the second argument is the character array that we created.

  // Create new characters:
  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);

In the loop, all the characters are displayed with lcd.write(). As the argument, we use the number of the custom character that we want to display.

  lcd.setCursor(0, 1);
  lcd.write(0);

Basic Arduino example code for I2C LCD

You can upload the following example code to the Arduino using the Arduino IDE.

For this tutorial, I used this 16×2 I2C character LCD display, but you can use other I2C LCDs of different sizes as well.

This example sketch will display the classic ‘Hello World!’ on the first line of the LCD and ‘LCD tutorial’ on the second line. Next, I will explain how the code works.

/* I2C LCD with Arduino example code. More info: https://www.makerguides.com */

// Include the libraries:
// LiquidCrystal_I2C.h: https://github.com/johnrickman/LiquidCrystal_I2C
#include <Wire.h> // Library for I2C communication
#include <LiquidCrystal_I2C.h> // Library for LCD

// Wiring: SDA pin is connected to A4 and SCL pin to A5.
// Connect to LCD via I2C, default address 0x27 (A0-A2 not jumpered)
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2); // Change to (0x27,20,4) for 20x4 LCD.

void setup() {
  // Initiate the LCD:
  lcd.init();
  lcd.backlight();
}

void loop() {
  // Print 'Hello World!' on the first line of the LCD:
  lcd.setCursor(2, 0); // Set the cursor on the third column and first row.
  lcd.print("Hello World!"); // Print the string "Hello World!"
  lcd.setCursor(2, 1); //Set the cursor on the third column and the second row (counting starts at 0!).
  lcd.print("LCD tutorial");
}

You should see the following output on the LCD:

How the code works

First, the required libraries are included. As mentioned earlier we need both the wire.h* and the LiquidCrystal_I2C library. In the rest of this tutorial, I will cover more of the built-in functions of this library.

*When using the latest version of the LiquidCrystal_I2C library it is no longer needed to include the wire.h library in your sketch. The other library imports wire.h automatically.

// Include the libraries:
// LiquidCrystal_I2C.h: https://github.com/johnrickman/LiquidCrystal_I2C
#include <Wire.h> // Library for I2C communication
#include <LiquidCrystal_I2C.h> // Library for LCD

The next step is to create an LCD object with the LiquidCrystal_I2C class and specify the address and dimensions. For this, we use the function . This is where you will need to change the default address to the address you found earlier if it happens to be different.

When using a 20×4 LCD, change this line to

Note that we have called the display ‘lcd’. You can give it a different name if you want like ‘menu_display’. You will need to change ‘lcd’ to the new name in the rest of the sketch.

// Connect to LCD via I2C, default address 0x27 (A0-A2 not jumpered)
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2); // Change to (0x27,20,4) for 20x4 LCD.

In the setup, the LCD is initiated with and the backlight is turned on with .

void setup() {
  // Initiate the LCD:
  lcd.init();
  lcd.backlight();
}

In the loop section of the code, the cursor is set to the third column and the first row of the LCD with . Note that counting starts at 0 and the first argument specifies the column. So sets the cursor on the third column and the second row.

Next the string ‘Hello World!’ is printed with . Note that you need to place quotation marks (” “) around the text since we are printing a text string. When you want to print numbers, no quotation marks are necessary. For example .

void loop() {
  lcd.setCursor(2, 0); // Set the cursor on the third column and first row.
  lcd.print("Hello World!"); // Print the string "Hello World!".
  lcd.setCursor(2, 1); //Set the cursor on the third column and the second row.
  lcd.print("LCD tutorial"); // Print the string "LCD tutorial".
}

If you want to see an example for displaying (changing) variables on the LCD, check out my tutorial for the HC-SR04 ultrasonic distance sensor:

How to use a HC-SR04 Ultrasonic Distance Sensor with Arduino

I2C Protocol

I2C (Inter Integrated Circuits) is a well known and widely used protocol. It allows us to connect multiple readers to a single writer, meaning that, you could have more than one sensor connected to the same pins of your Arduino board through I2C. The only requisite is that each of those sensors have a unique address.

The I2C protocol involves using two lines to send and receive data: a serial clock pin (SCL) where the Arduino writer board pulses at a regular interval, and a serial data pin (SDA) over which data is sent between the two devices.

As the clock line changes from low to high, a single bit of information that will form the address of a specific device, and a command or data is transferred from the board to the I2C device over the SDA line. When this information is sent, the called upon device executes the request and transmits it’s data back, if required, to the board over the same line using the clock signal still generated by the writer on SCL.

If you want to learn more about the I2C protocol and how it works, you can check the I2C standards.

Полезные советы при работе с Arduino

Работа с текстовыми файлами

При дальнейшей работе с Arduino вам часто придётся разбираться с файлами библиотек (смотреть список методов или писать свои библиотеки), поэтому нужно сделать две очень важные вещи: включить отображение расширений файлов и скачать блокнот++. Блокнот++ удобнее обычного блокнота и имеет кучу фишек, например распознаёт “язык кода” и подсвечивает синтаксис.

Далее необходимо включить отображение расширений у файлов, чтобы знать, что перед вами за зверь. Краткая инструкция для Windows 7 и 10.

После этого делаем нужные файлы открываемыми по умолчанию в Notepad++

Написание текста программы

Автоформатирование – Arduino IDE умеет автоматически приводить ваш код в порядок (имеются в виду отступы, переносы строк и пробелы). Для автоматического форматирования используйте комбинацию CTRL+T на клавиатуре, либо Инструменты/АвтоФорматирование в окне IDE. Используйте чаще, чтобы сделать код красивым (каноничным, классическим) и более читаемым для других!

Скрытие частей кода – сворачивайте длинные функции и прочие куски кода для экономии места и времени на скроллинг. Включается здесь: Файл/Настройки/Включить сворачивание кода

Не используйте мышку! Чем выше становится ваш навык в программировании, тем меньше вы будете использовать мышку (да-да, как в фильмах про хакеров). Используйте обе руки для написания кода и перемещения по нему, вот вам несколько полезных комбинаций и хаков, которыми я пользуюсь ПОСТОЯННО:

  • Ctrl+← , Ctrl+→ – переместить курсор влево/вправо НА ОДНО СЛОВО
  • Home , End – переместить курсор в начало/конец строки
  • Shift+← , Shift+→ – выделить символ слева/справа от курсора
  • Shift+Ctrl+← , Shift+Ctrl+→ – выделить слово слева/справа от курсора
  • Shift+Home , Shift+End – выделить все символы от текущего положения курсора до начала/конца строки
  • Ctrl+Z – отменить последнее действие
  • Ctrl+Y – повторить отменённое действие
  • Ctrl+C – копировать выделенный текст
  • Ctrl+X – вырезать выделенный текст
  • Ctrl+V – вставить текст из буфера обмена
  • Ctrl+U – загрузить прошивку в Arduino
  • Ctrl+R – скомпилировать (проверить)
  • Ctrl+Shift+M – открыть монитор порта

Также для отодвигания комментариев в правую часть кода используйте TAB, а не ПРОБЕЛ. Нажатие TAB перемещает курсор по некоторой таблице, из-за чего ваши комментарии будут установлены красиво на одном расстоянии за вдвое меньшее количество нажатий!

Хаки с питанием

Питание от пинов – во время разработки прототипов без брэдборда всегда не хватает пинов для питания датчиков и модулей. Так вот, слабые (с потреблением тока менее 40 мА ) 5 Вольтовые датчики можно питать от любых пинов! Достаточно сформировать пин как выход, и подать на него нужный сигнал (HIGH – 5 Вольт, LOW – GND).

Пример: подключаем трёхпиновый датчик звука, не используя пины 5V и GND

Питание от штекера для программатора. Вы наверняка задавались вопросом, а зачем на Arduino NANO на краю платы расположены 6 пинов? Это порт для подключения ISP программатора. Что он делает в списке лайфхаков? Вот вам фото распиновки, используйте!

Энергосбережение

Использовать библиотеку энергосбережения Low Power. Примеры и описание внутри (видео урок пока не готов)

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

ВНИМАНИЕ! Резать ногу регулятору можно только в том случае, если плата питается от источника 3-5 Вольт в пины 5V и GND

1Описание FC-113 преобразователя последовательного интерфейса в параллельный

  • Модуль FC-113 сделан на базе микросхемы PCF8574T, которая представляет собой 8-битный сдвиговый регистр – «расширитель» входов-выходов для последовательной шины I2C. На рисунке микросхема обозначена DD1.
  • R1 – подстроечный резистор для регулировки контрастности ЖК дисплея.
  • Джампер J1 используется для включения подсветки дисплея.
  • Выводы 1…16 служат для подключения модуля к выводам LCD дисплея.
  • Контактные площадки А1…А3 нужны для изменения адреса I2C устройства. Запаивая соответствующие перемычки, можно менять адрес устройства. В таблице приведено соответствие адресов и перемычек: «0» соответствует разрыву цепи, «1» – установленной перемычке. По умолчанию все 3 перемычки разомкнуты и адрес устройства 0x27.

I2C модуль FC-113 для подключения ЖК экрана

Подключение LCD1602 к Arduino

Модуль оборудован четырех-пиновым разъемом стандарта 2.54мм

  • SCL: последовательная линия тактирования (Serial CLock)
  • SDA: последовательная линия данных (Serial DAta)
  • VCC: «+» питания
  • GND: «-» питания

Выводы отвечающие за интерфейс I2C на платах Arduino на базе различных контроллеров разнятся

Arduino Mega Arduino Uno/Nano/Pro Mini LCD I2C модуль Цвет проводов на фото
GND GND GND Черный
5V 5V VCC Красный
20 (SDA) A4 SDA Зелёный
21 (SCL) A5 SCL Жёлтый

Пример скетча

/*
Добавляем необходимые библиотеки
*/
#include <LiquidCrystal_I2C.h>

/*
Устанавливаем ЖК-дисплей по адресу 0x27, 16 символов и 2 строки
*/
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup()
{
/*
Инициализируем ЖК-дисплей
*/
lcd.init();
/*
Включаем подсветку дисплея
*/
lcd.backlight();
/*
Устанавливаем курсор на первую строку и нулевой символ.
*/
lcd.setCursor(0, 0);
/*
Выводим на экран строку
*/
lcd.print(» micro-pi.ru «);
}

void loop()
{
/*
Устанавливаем курсор на вторую строку и 3 символ.
*/
lcd.setCursor(3, 1);
/*
Выводим на экран количество секунд с момента запуска ардуины
*/
lcd.print(millis() / 1000);
delay(1000);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

/*
  Добавляем необходимые библиотеки
*/
#include <LiquidCrystal_I2C.h>
 
/*
  Устанавливаем ЖК-дисплей по адресу 0x27, 16 символов и 2 строки
*/

LiquidCrystal_I2Clcd(0x27,16,2);

voidsetup()

{

/*

    Инициализируем ЖК-дисплей
  */

lcd.init();

/*

    Включаем подсветку дисплея
  */

lcd.backlight();

/*

    Устанавливаем курсор на первую строку и нулевой символ.
  */

lcd.setCursor(,);

/*

    Выводим на экран строку
  */

lcd.print(»   micro-pi.ru  «);

}
 
 

voidloop()

{

/*

    Устанавливаем курсор на вторую строку и 3 символ.
  */

lcd.setCursor(3,1);

/*

    Выводим на экран количество секунд с момента запуска ардуины
  */

lcd.print(millis()1000);

delay(1000);

}

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

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

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

Wire.onReceive()

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

Wire.onRequest()

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

5Управление устройством по шине IIC

Рассмотрим диаграммы информационного обмена с цифровым потенциометром AD5171, представленные в техническом описании:

Рассмотрим диаграммы чтения и записи цифрового потенциометра AD5171

Нас тут интересует диаграмма записи данных в регистр RDAC. Этот регистр используется для управления сопротивлением потенциометра.

Откроем из примеров библиотеки «Wire» скетч: Файл Образцы Wire digital_potentiometer. Загрузим его в память Arduino.

#include <Wire.h> // подключаем библиотеку "Wire"
byte val = 0; // значение для передачи потенциометру

void setup() {
  Wire.begin();   // подключаемся к шине I2C как мастер
}

void loop() {
  Wire.beginTransmission(44); // начинаем обмен с устройством с I2C адресом "44" (0x2C)
  Wire.write(byte(0x00)); // посылаем инструкцию записи в регистр RDAC
  Wire.write(val); // задаём положение 64-позиционного потенциометра
  Wire.endTransmission(); // завершаем I2C передачу

  val++; // инкрементируем val на 1
  if (val == 63) { // по достижении максимума потенциометра
    val = 0; // сбрасываем val 
  }
  delay(500);
}

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

По ссылкам внизу статьи, в разделе похожих материалов (по тегу), можно найти дополнительные примеры взаимодействия с различными устройствами по интерфейсу IIC, в том числе примеры чтения и записи.

Аппаратный модуль TWI

Смотрите следующую схему потока для записи на шину I2C:

Взаимодействие приложения с шиной TWI (I2C) во время типовой передачи

Ссылаясь на таблицу регистров, приведенную выше, операция записи I2C с использованием аппаратного модуля TWI вкратце будет выглядеть следующим образом:

  • Библиотека конфигурирует микросхему ATmega так, что внутренний аппаратный модуль TWI использует свои выводы, которые жестко привязаны к двум аналоговым выводам (4 и 5 на Duemilanove).
  • Библиотека устанавливает значение регистра TWCR для создания состояния .
    • Сначала она проверяет шину I2C, чтобы убедиться, что она свободна. Шина свободна, когда на обеих линиях и SDA, и SCL установлен высокий логический уровень (потому что устройство по умолчанию устанавливает выводы на шине в третье состояние «не подключено». Общий резистор подтягивает сигнал на шине к высокому уровню).
    • Что такое состояние ? Линия тактового сигнала SCL остается в состоянии логической 1, а мастер в это время меняет состояние на линии SDA на логический 0. Это уникальный момент, поскольку во время обычной передачи данных линии SDA изменяет состояние только тогда, когда на линии SCL установлен низкий логический уровень. Момент, когда сигнал на линии данных изменяется на логический 0, а на SCL логическая 1, является сигналом для всех устройств на шине I2C, с которыми мастер собирается начать взаимодействовать.
  • Аппаратный модуль TWI при завершении выполнения действия вызывает прерывание процессора.
  • Библиотека e проверяет состояние по регистру . Предположим, что всё хорошо.
  • Библиотека загружает в регистр адрес ведомого устройства плюс бит «запись». Вместе это значение известно как «SLA+W» («SLave Address plus Write»).
  • Библиотека устанавливает значение регистра для передачи .
  • В случае успеха, библиотека загружает данные в регистр , устанавливает , и данные передаются.
  • Библиотека проверяет состояние по регистру . Предположим, что всё хорошо.
  • Библиотека устанавливает значение регистра для передачи состояния . В состоянии линия SCL освобождается (переходит в высокий логический уровень), и затем линия SDA переходит в состояние логической 1. Обычно линия SDA должна оставаться неизменной, когда на линии SCL установлен высокий логический уровень.

Операция чтения выполняется похожим образом.