Бібліотека AVR для роботи з шиною I2C та з годинником реального часу PCF8583. Бібліотека AVR для роботи з шиною I2C та з годинником реального часу PCF8583 Альтернативна бібліотека для роботи з i2c дисплеєм

LCD дисплей- Частий гість у проектах Ардуїно. Але в складних схемах у нас може виникнути проблема нестачі портів Arduino через необхідність підключити екран, який має дуже багато контактів. Виходом у цій ситуації може стати I2C /IICперехідник, який підключає практично стандартний для Arduino екран 1602 до плат Uno, Nano або Mega лише за допомогою 4 пінів. У цій статті ми подивимося, як можна підключити LCD екран з інтерфейсом I2C, які можна використовувати бібліотеки, напишемо короткий приклад і розберемо типові помилки.

Рідкокристалічний дисплей (Liquid Crystal Display) LCD 1602є гарним вибором для виведення рядків символів у різних проектах. Він коштує недорого, є різні модифікації з різними кольорами підсвічування, ви можете легко завантажити готові бібліотеки для скетч Ардуїно. Але найголовнішим недоліком цього екрану є той факт, що дисплей має 16 цифрових висновків, з яких обов'язковими є мінімум 6. Тому використання цього екрану LCD без i2c додає серйозні обмеження для плат Arduino Uno або Nano. Якщо контактів не вистачає, вам доведеться купувати плату Arduino Mega або ж заощадити контакти, в тому числі за рахунок підключення дисплея через i2c.

Короткий опис пінів 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 екрани та шилди для ардуїно

LCD екран 1602 (і варіант 2004) досить популярний, тому ви без проблем зможете знайти його як у вітчизняних інтернет магазинах, так і на закордонних майданчиках. Наведемо кілька посилань на найдоступніші варіанти:

Модуль LCD1602+I2C із синім екраном, сумісний з Arduino Простий дисплей LCD1602 (зелене підсвічування) дешевше 80 рублів Великий екран LCD2004 з I2C HD44780 для ардуїно (синє та зелене підсвічування)
Дисплей 1602 з IIC адаптером та синім підсвічуванням Ще один варіант LCD1602 із впаяним I2C модулем Модуль адаптера Port IIC/I2C/TWI/SPI для екрана 1602, сумісний з Ардуїно
Дисплей з RGB-підсвічуванням! LCD 16×2 + keypad +Buzzer Shield for Arduino Шилд для Ардуїно з кнопками та екраном LCD1602 LCD 1602 LCD дисплей для 3D принтера (Smart Controller for RAMPS 1.4, Text LCD 20×4), модулем кардрідера SD та MicroSD-

Опис протоколу I2C

Перш ніж обговорювати підключення дисплея до ардуїно через i2c-перехідник, коротко поговоримо про сам протокол i2C.

I2C/IIC(Inter-Integrated Circuit) – це протокол, що спочатку створювався для зв'язку інтегральних мікросхем усередині електронного пристрою. Розробка належить фірмі Philips. В основі i2c протоколу є використання 8-бітної шини, яка потрібна для зв'язку блоків в електроніці, що управляє, і системі адресації, завдяки якій можна спілкуватися по одним і тим же проводам з декількома пристроями. Ми просто надаємо дані то одному, то іншому пристрою, додаючи до пакетів даних ідентифікатор потрібного елемента.

Найпростіша схема I2C може містити один провідний пристрій (найчастіше це мікроконтролер Ардуїно) та кілька ведених (наприклад, дисплей LCD). Кожен пристрій має адресу в діапазоні від 7 до 127. Двох пристроїв з однаковою адресою в одній схемі не повинно бути.

Плата Arduino підтримує i2c на апаратному рівні. Ви можете використовувати піни A4 та A5 для підключення пристроїв за цим протоколом.

У роботі I2C можна виділити кілька переваг:

  • Для роботи потрібно лише 2 лінії – SDA (лінія даних) та SCL (лінія синхронізації).
  • Підключення великої кількості провідних приладів.
  • Зменшення часу розробки.
  • Для керування всім набором пристроїв потрібен лише один мікроконтролер.
  • Можливе число мікросхем, що підключаються, до однієї шини обмежується тільки граничною ємністю.
  • Висока ступінь збереження даних через спеціальний фільтр пригнічує сплески, вбудованого в схеми.
  • Проста процедура діагностики збоїв, що виникають, швидке налагодження несправностей.
  • Шина вже інтегрована в саму Arduino, тому не потрібно додатково розробляти шинний інтерфейс.

Недоліки:

  • Існує ємнісне обмеження на лінії – 400 пФ.
  • Важке програмування контролера I2C, якщо на шині є кілька різних пристроїв.
  • При велику кількість пристроїв виникає труднощі локалізації збою, якщо один з них помилково встановлює стан низького рівня.

Модуль i2c для LCD 1602 Arduino

Найшвидший та найзручніший спосіб використання i2c дисплея в ардуїно – це покупка готового екрану з вбудованою підтримкою протоколу. Але таких екранів не дуже вистають вони не дешево. А ось різноманітних стандартних екранів випущено вже величезну кількість. Тому найдоступнішим і найпопулярнішим сьогодні варіантом є купівля та використання окремого I2C модуля – перехідника, який виглядає ось так:

З одного боку модуля ми бачимо висновки i2c – земля, живлення та 2 для передачі даних. З іншого перехідника бачимо роз'єми зовнішнього живлення. І, природно, на платі є безліч ніжок, за допомогою яких модуль припаює до стандартних висновків екрану.


Для підключення до плати Ардуїно використовуються i2c виходи. Якщо потрібно, підключаємо зовнішнє живлення для підсвічування. За допомогою вбудованого підстроювального резистора ми можемо налаштувати настроювання контрастності J

На ринку можна зустріти LCD 1602 модулі з припаяними перехідниками, їх використання максимально упощено. Якщо ви купили окремий перехідник, потрібно буде заздалегідь припаяти його до модуля.

Підключення РК екрану до Ардуїно за I2C

Для підключення необхідні сама плата Ардуїно, дисплей, макетна плата, з'єднувальні дроти та потенціометр.

Якщо ви використовуєте спеціальний окремий i2c перехідник, потрібно спочатку припаяти його до модуля екрана. Помилитись там важко, можете керуватися такою схемою.


Рідкокристалічний монітор з підтримкою i2c підключається до плати за допомогою чотирьох дротів – два дроти для даних, два дроти для живлення.

  • Висновок GND підключається до GND на платі.
  • Висновок VCC – на 5V.
  • SCL підключається до піну A5.
  • SDA підключається до піну A.

І це все! Жодних павутин проводів, в яких дуже легко заплутатися. При цьому всю складність реалізації протоколу i2C ми можемо просто довірити бібліотекам.

Бібліотеки для роботи з i2c LCD дисплеєм

Для взаємодії Arduino c LCD 1602 по шині I2C вам знадобиться як мінімум дві бібліотеки:

  • Бібліотека Wire.h для роботи з I2C вже є у стандартній програмі Arduino IDE.
  • Бібліотека LiquidCrystal_I2C.h, яка включає велику різноманітність команд для управління монітором по шині I2C і дозволяє зробити скетч простіше і коротше. Потрібно додатково встановити бібліотеку Після підключення екрана потрібно додатково встановити бібліотеку LiquidCrystal_I2C.h

Після підключення до скетчу всіх необхідних бібліотек ми створюємо об'єкт і можемо використовувати його функції. Для тестування завантажимо наступний стандартний скетч з прикладу.

#include #include // Підключення бібліотеки //#include // Підключення альтернативної бібліотеки LiquidCrystal_I2C lcd(0x27,16,2); // Вказуємо I2C адресу (найпоширеніше значення), і навіть параметри екрана (у разі LCD 1602 - 2 рядки по 16 символів у кожному //LiquidCrystal_PCF8574 lcd(0x27); // Варіант для бібліотеки PCF8574 void setup() ( lcd.init (); // Ініціалізація дисплея lcd.backlight(); // Підключення підсвічування lcd.setCursor(0,0); // Встановлення курсору на початок першого рядка lcd.print("Hello"); // Набір тексту на першому рядку lcd.setCursor(0,1); // Встановлення курсору на початок другого рядка lcd.print("ArduinoMaster"); // Набір тексту на другому рядку ) void loop() ( )

Опис функцій та методів бібліотеки LiquidCrystal_I2C:

  • home() і clear() – перша функція дозволяє повернути курсор на початок екрана, друга теж, але при цьому видаляє все, що було на моніторі до цього.
  • write(ch) – дозволяє вивести одиночний символ ch на екран.
  • cursor() та noCursor() – показує/приховує курсор на екрані.
  • blink() і noBlink() – курсор блимає/не блимає (якщо раніше було включено його відображення).
  • display() та noDisplay() – дозволяє підключити/вимкнути дисплей.
  • scrollDisplayLeft() та scrollDisplayRight() – прокручує екран на один знак ліворуч/праворуч.
  • autoscroll() та noAutoscroll() – дозволяє увімкнути/вимкнути режим автопрокручування. У цьому режимі кожен новий символ записується в тому самому місці, витісняючи раніше написане на екрані.
  • leftToRight() і rightToLeft() – Встановлення напряму виведеного тексту – зліва направо або праворуч наліво.
  • createChar(ch, bitmap) – створює символ із кодом ch (0 – 7), використовуючи масив бітових масок bitmap для створення чорних та білих точок.

Альтернативна бібліотека для роботи з дисплеєм i2c

У деяких випадках при використанні зазначеної бібліотеки з пристроями, оснащеними контролерами PCF8574, можуть виникати помилки. У цьому випадку альтернативою можна запропонувати бібліотеку LiquidCrystal_PCF8574.h. Вона розширює LiquidCrystal_I2C, тому проблем із її використанням не повинно бути.

Проблеми підключення i2c lcd дисплея

Якщо після завантаження скетча у вас не з'явиться жодного напису на дисплеї, спробуйте виконати такі дії.

По-перше, можна збільшити чи зменшити контрастність монітора. Часто символи просто не видно через режим контрастності та підсвічування.

Якщо це не допомогло, перевірте правильність підключення контактів, чи підключено живлення підсвічування. Якщо ви використовували окремий i2c перехідник, перевірте ще раз якість паяння контактів.

Іншою частою причиною відсутності тексту на екрані може стати неправильна i2c адреса. Спробуйте спочатку поміняти в скетчі адресу пристрою з 0x27 0x20 або 0x3F. У різних виробників можуть бути різні адреси за замовчуванням. Якщо це не допомогло, можете запустити скетч i2c сканера, який переглядає всі підключені пристрої та визначає їх адресу методом перебору. Приклад скетчу i2c сканера.

Якщо екран все ще залишиться неробочим, спробуйте відпаяти перехідник та підключити LCD звичайним чином.

Висновок

У цій статті ми розглянули основні питання використання LCD екрану у складних проектах Ардуїно, коли нам потрібно економити вільні піни на платі. Простий і недорогий перехідник i2c дозволить підключити LCD екран 1602, займаючи всього 2 аналогові піни. У багатьох ситуаціях це може бути дуже важливим. Плата за зручність – необхідність використання додаткового модуля – конвертера та бібліотеки. На наш погляд, зовсім не висока ціна за зручність і ми рекомендуємо використовувати цю можливість у проектах.

Прийшла мені посилка з Китаю, в якій лежить мікросхема EEPROM фірми Atmel. Яку хочеться підключити до Arduino. Але зовсім не хочеться використати готову бібліотеку, а розібратися самому. За цим стаття вийти трохи об'ємною і нудною і розділимо її на три частини:

  • Теорія інтерфейсу I2C.
  • EEPROM, описи моєї мікросхеми (AT24C256) та підключення.
  • Написання бібліотеки до роботи з пам'яттю.

Частина перша, I2C та бібліотека «Wire».

Послідовний протокол обміну даними IIC(також званий I2C- Inter-Integrated Circuits, міжмікросхемне з'єднання). Розроблена фірмою Philips Semiconductors на початку 1980-х як проста 8-бітна шина внутрішнього зв'язку для створення електроніки, що управляє. Так як право на використання його коштує грошей фарма Atmel назвала його TWI, Але сенс від цього змінюється.

Як це працює?

Для передачі використовуються дві двонаправлені лінії передачі. SDA(Serial Data) шина послідовних даних та SCL(Serial Clock) Шина тактування. Обидві шини підтягнуті резисторами до плюсової шини живлення. Передача/Прийом сигналів здійснюється притисканням лінії 0, одиничку встановлюється сама, за рахунок підтягуючих резисторів.

У мережі є хоча б один провідний пристрій ( Master), яке ініціалізує передачу даних та генерує сигнали синхронізації та ведені пристрої ( Slave), які передають дані на запит ведучого. Кожен ведений пристрій має унікальну адресу, за якою ведучий і звертається до нього. Звичайно зрозуміло, що Ведучий це наш мікроконтролер, а ведений наша пам'ять. Провідний пристрій починає притискати шину SCLдо нуля з певною чистотою, а шину SDAпритискати або відпускати на певну кількість тактів передаючи Одиночку або Нулик. Передача даних починається з сигналу START потім передається 8 біт даних і 9-м бітом Ведомий пристрій підтверджує прийом байт притискаючи шину SDAдо мінуса . Закінчується передача сигналом STOP .

Бібліотека "Wire".

Для полегшення обміну даними з пристроями по шині I2C для Arduino написано стандартну бібліотеку Wireяка є вже у комплекті IDE. Вона має такі основні функції:

Wire.begin(Address)викликається один раз для ініціалізації та підключення до шини як Ведучий або Ведений пристрій. Якщо Address не заданий підключаємося як Майстер-пристрій.

Wire.beginTransmission(address) починає передачу на ведений I2C пристрій із заданою адресою.

Wire.endTransmission() припиняє передачу даних веденому. Функція повертає значення типу byte:

  • 0 - успіх.
  • 1 дані занадто довгі для заповнення буфера передачі.
  • 2 — прийнято NACK під час передачі адреси.
  • 3 - прийнятий NACK під час передачі даних.
  • 4 - інші помилки.

Wire.write()запис даних від веденого пристрою у відповідь на запит від провідного пристрою, або ставить в чергу байти для передачі від майстра до веденого пристрою. Фактично записує дані в буфер. Розмір буфера 32 байта (мінус 2 байти адресу, фактично 30 байт), а передає буфер функція Wire.endTransmission().

  • Wire.write(value)- value: значення передачі, один байт.
  • Wire.write(string)- string: рядок передачі, послідовність байтів.
  • Wire.write(data, length)- Data: масив даних для передачі, байти. length: кількість байтів для передачі.

Wire.read()Зчитує байт, який був переданий від веденого пристрою до ведучого або який був переданий від провідного пристрою до провідного. Значення, що повертається byte : черговий прийнятий байт.

Це основні функції бібліотеці, інші ми розглянемо по ходу п'єси))

Частина друга, EEPROM.

EEPROM (англ. Electrically Erasable Programmable Read-Only Memory) - електрично стирається ПЗП (ЕСППЗУ), що перепрограмується, один з видів енергонезалежної пам'яті (таких, як PROM і EPROM). Пам'ять такого типу може стиратися та заповнюватися даними до мільйона разів.

Мені надіслали вже готовий модуль EEPROM із мікросхемою AT24C256 фірми Atmel об'ємом 32 кбайт. Щоб розібратися з цим дивом нам доведеться проштудувати datasheetякий дуже нудний і англійською. Тож я вам видам уже готовий результат моїх мук.

Характеристики:

  • Низьковольтні та стандартні живлення. VCC = 1.7V до 5.5V.
  • 400kHz (1.7V) and 1MHz (2.5V, 2.7V, 5.0V) сумісний із частотою синхронізації.
  • Витривалість: 1,000,000 Циклів Записи.
  • Внутрішньо організований як 32768 сторінок x 8 біт.

висновки:

  • WP- Захист від запису. Якщо висновок підключений до GND можна записувати дані на згадку.
  • A0…A2- Виводи задають адресу пристрою.
  • Vcc- Харчування плюс.
  • GND- Харчування мінус.
Адреса пам'яті:

Задається трьома ногами A0..A2. Якщо нога притиснута до Gnd, то значення біта 0, якщо до Vcc то 1. Мікросхема використовує восьми бітна адреса, останній біт відповідає за вибір операції. Якщо значення біта високий, то ініціалізується операція читання, якщо низький (нуль) то операція запису.

Тобто якщо всі три висновки притиснуті до GND і ми хочемо записати в пам'ять, адреса пристрою буде виглядати як 10100000 (у бібліотеці «Wire» використовується 7-бітна адреса, зрушуємо все в право на один біт 01010000 0x50).

Запис даних на згадку:

Для запису ми спочатку звертаємося до пам'яті з бітом Записи на адресу. Потім надсилаємо дві 8-ми бітних адреси (тобто у нас 0x8000 адрес), потім байт даних і сигнал STOP. Після цього EEPROM входить до внутрішньо синхронізованого циклу запису tWR(Write Cycle Time 5 ms) в енергонезалежну пам'ять. Усі вхідні сигнали
відключено під час цього циклу запису, та EEPROM не відповість, поки запис не буде завершено.

Копаємося далі і знаходимо в dataheet що пам'ять мікросхеми організована як 512 сторінок по 64 байта. Тобто ми можемо записати відразу до 64 байт інформації за одну команду. Для цього ми передаємо всі 64 байти інформації і тільки після цього надсилаємо сигнал STOP.

Читання даних:

З читанням даних дедалі цікавіше. Пам'ять підтримує три варіанти читання:

  • Читати поточну адресу;
  • Читати випадкову адресу;
  • Послідовне читання;

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

Щоб прочитати випадкову адресу нам потрібно з початку відправити команду на записі передати адресу, яку хочемо прочитати( не забувайте, що адреса складається з двох 8-ми бітних частин). Потім надіслати команду на читання і отримати шуканий байт, завершивши все командою STOP.

Послідовне читання може виконуватися як з поточної адреси так і з випадкової і буде продовжуватися доки мікроконтролер не надішле сигнал СТОП. При переповненні адреси пам'ять скинути її і адресація почнеться з початку.

Ну що ж настав час спробувати щось записати:
#include // Підключаємо бібліотеку #define EEPROM_ADDRESS 0x53 // Задаємо адресу пам'яті word address = 0; // Адреса куди записуватимемо byte data_send = 170; // Дані void setup() ( Wire.begin(); // Ініціалізуємо I2C Serial.begin(9600); Serial.print("Write byte to EEPROM memory..."); Serial.println (data_send); Wire. beginTransmission(EEPROM_ADDRESS);// Починаємо передачу Wire.write(address >> 8);Wire.write(address & 0xFF);// Відправляємо два байти адреси Wire.write(data_send); endTransmission(); // Закінчуємо передачу і перевіряємо статус передачі.if (status == 0)Serial.println ("Ок"); // delay(10); ), Wire.beginTransmission(EEPROM_ADDRESS);// Щоб прочитати дані отруюємо спочатку адресу де вони лежать. (status == 0)Serial.println ("Ок"); // stop transmitting Wire.requestFrom(EEPROM_ADDRESS, (byte)1); // відправляємо команду на читання одного байта даних byte data = 0; if (Wire.available ()) // перевіряємо, що є дані для читання (data = Wire.read(); //читаємо дані) Serial.println (data, DEC); ) void loop() ( )

Wire.requestFrom(address, quantity) — Використовується майстром для запиту байтів від керованого пристрою. Ці байти може бути отримано з допомогою методів available() і read() . Розмір буфера такий самий 32 байти.

  • address : 7-бітна адреса пристрою, у якого запитуються байти;
  • quantity : кількість байтів, що запитуються;

Wire.available()— Повертає кількість байтів, доступних для отримання за допомогою read().

Ну і приклад із записом у пам'ять рядка «Hello Word»:

#include #define EEPROM_ADDRESS 0x53 word address = 0; char data_send = "Hello Word"; void setup() ( Wire.begin(); // Serial.begin(9600); Serial.print("Write byte to EEPROM memory..."); Serial.println (data_send); Wire.beginTransmission(EEPROM_ADDRESS); Wire.write(address >> 8); Wire.write(address & 0xFF); Wire.write(data_send); delay(10); Serial.println("Read byte from EEPROM memory..."); Wire.endTransmission(); if (status == 0)Serial.println ("Ок"); // stop transmitting Wire.requestFrom(EEPROM_ADDRESS, (byte)10); byte data = 0; i<10 ;i++) { if (Wire.available()) { data = Wire.read(); } Serial.write (data); } } void loop() { }

Організація пам'яті:

Так як в данихдописах про це написано неясно. Я на практиці намагався розібратися із цим. У datasheet написано що пам'ять мікросхеми організована як 512 сторінок по 64 байта. Що це означає? Якщо ми захочемо записати більше 64 байт відразу, скажімо за адресою 0x40 (адреса початок другої сторінки), при виході адреси за межі сторінки внутрішній лічильник мікросхеми скине адресу на початок сторінки. А зайві байти будуть записані на початок сторінки і зітруть дані, які були там записані.

Для читання таких обмежень немає, в даташіпі написано тільки те, що коли ви досягнете кінця адрес вас автоматично перекине на початок (адреса 0х00).

На цьому я думаю все. Ви, звичайно, можете завантажити вже готову бібліотеку для EEPROM, думаєте зможете і написати свою. Головне ми розібралися в основному принципі роботи.

Опис бібліотеки Wire

Дана бібліотека дозволяє вам взаємодіяти з I2C/TWI пристроями. На платах Arduino з компонуванням R3 (розпинання 1.0) SDA (лінія даних) та SCL (лінія тактового сигналу) знаходяться на висновках біля виводу AREF. Arduino Due має два I2C/TWI інтерфейси: SDA1 і SCL1 знаходяться біля виводу AREF, а додаткові лінії знаходяться на висновках 20 та 21.

У таблиці нижче показано, де розташовані TWI висновки різних платах Arduino.

Починаючи з Arduino 1.0, ця бібліотека успадковує функції Stream, що робить її сумісною з іншими бібліотеками читання/запису. Через це send() та receive() були замінені на read() та write() .

Примітка

Існують 7- та 8-бітні версії адрес I2C. 7 бітів ідентифікують пристрій, а восьмий біт визначає, чи йде запис або читання. Бібліотека Wire використовує 7 бітові адреси. Якщо у вас є технічний опис або приклад коду, де використовується 8-бітна адреса, вам потрібно відкинути молодший біт (тобто зрушити значення на один біт праворуч), отримавши адресу від 0 до 127. Однак адреси від 0 до 7 не використовуються , оскільки зарезервовані, тому першою адресою, яка може бути використана, є 8. Зверніть увагу, що при підключенні висновків SDA/SCL необхідні резистори, що підтягують. Докладніше дивіться приклади. На платі MEGA 2560 є резистори, що підтягують, на висновках 20 і 21.

Опис методів

Wire.begin()

Опис

Ініціалізує бібліотеку Wire та підключається до шини I2C як ведучий (майстер) або ведений. Як правило, має викликатися лише один раз.

Синтаксис

Wire.begin(address)

Параметри

address: 7-бітна адреса веденого пристрою (необов'язково); якщо не заданий, плата підключається до шини як майстер.

Значення, що повертається

приклад

Приклади для керованого пристрою дивіться в прикладах до методів onReceive() та onRequest() . Приклади для провідного пристрою дивіться у прикладах до інших методів. .

Wire.requestFrom()

Опис

Використовується майстром для запиту байтів від керованого пристрою. Ці байти може бути отримано з допомогою методів available() і read() .

Якщо цей аргумент дорівнює true, то requestFrom() після запиту посилає повідомлення STOP, звільняючи шину I2C.

Якщо цей аргумент дорівнює false, то requestFrom() після запиту надсилає повідомлення RESTART. Шина не звільняється, що заважає іншому пристрої-майстру влізти між повідомленнями. Це дозволяє одному провідному пристрою посилати кілька запитів, доки він контролює шину.

Синтаксис

Wire.requestFrom(address, quantity)

Wire.requestFrom(address, quantity, stop)

Параметри

  • address: 7-бітна адреса пристрою, у якого запитуються байти;
  • quantity: кількість байтів, що запитуються;
  • stop: boolean. true посилає повідомлення STOP після запиту. false посилає повідомлення RESTART після запиту, зберігаючи активне з'єднання.
Значення, що повертається

byte: кількість байтів, повернутих від веденого пристрою.

приклад

Wire.beginTransmission()

Опис

Починає передачу на ведений I2C пристрій із заданою адресою. Після нього послідовність байтів передачі ставиться у чергу з допомогою функції write() , та його передача з допомогою виклику endTransmission() .

Синтаксис

Wire.beginTransmission(address)

Параметри

address: 7-бітна адреса пристрою, на яку необхідно передати дані.

Значення, що повертається

приклад

Wire.endTransmission()

Опис

Завершує передачу на ведений пристрій, яка була розпочата методом beginTransmission() і передає байти, які були поставлені в чергу методом write().

Для сумісності з певними пристроями I2C, починаючи з Arduino 1.0.1, requestFrom() приймає аргумент логічного типу даних, що змінює його поведінку.

Якщо цей аргумент дорівнює true, то requestFrom() після передачі посилає повідомлення STOP, звільняючи шину I2C.

Якщо цей аргумент дорівнює false, то requestFrom() після передачі посилає повідомлення RESTART. Шина не звільняється, що заважає іншому пристрої-майстру влізти між повідомленнями. Це дозволяє одному провідному пристрою посилати кілька передач, доки він контролює шину.

За умовчанням цей аргумент дорівнює true.

Синтаксис

Wire.endTransmission()

Wire.endTransmission(stop)

Параметри

stop: boolean. true посилає повідомлення STOP після передачі. false посилає повідомлення RESTART після передачі, зберігаючи активне з'єднання.

Значення, що повертається

byte , який вказує на стан передачі:

  • 0: успіх;
  • 1: дані надто довгі для заповнення буфера передачі;
  • 2: прийнятий NACK під час передачі адреси;
  • 3: прийнятий NACK під час передачі даних;
  • 4: решта помилок.
приклад

Дивіться приклад до методу write().

Wire.write()

Опис

Записує дані від веденого пристрою у відповідь на запит від провідного пристрою, або ставить у чергу байти для передачі від майстра до веденого пристрою (між викликами beginTransmission() та endTransmission()).

Синтаксис

Wire.write(value)

Wire.write(string)

Wire.write(data, length)

Параметри

  • value: значення передачі, один байт.
  • string: рядок передачі, послідовність байтів.
  • data: масив даних передачі, байти.
  • length: кількість байтів передачі.
Значення, що повертається

byte: write() повертає кількість записаних байтів, хоча читання цієї кількості не обов'язково.

Приклад #include byte val = 0; void setup() ( Wire.begin(); // підключитися до шини i2c ) void loop() ( Wire.beginTransmission(44); // передача на пристрій #44 (0x2c) // адресу пристрою заданий у технічному описі Wire. write(val); // відправити байт значення Wire.endTransmission(); // зупинити передачу val++; // збільшити значення if(val == 64) // якщо сягнули 64-го значення (max) ( val = 0; // почати з початку) delay (500);

Wire.available()

Опис

Повертає кількість байтів, доступних отримання за допомогою read() . Цей метод повинен викликатись на провідному пристрої після виклику requestFrom() або на веденому пристрої всередині обробника onReceive() .

Синтаксис

Wire.available()

Параметри

Значення, що повертається

Кількість байт, доступних для читання.

приклад

Дивіться приклад до методу read().

Wire.read()

Опис

Зчитує байт, який був переданий від веденого пристрою до ведучого після виклику requestFrom() , або який був переданий від провідного пристрою до веденого.

Синтаксис

Параметри

Значення, що повертається

byte: черговий байт прийнятий.

Приклад #include byte val = 0; void setup() ( Wire.begin(); // підключитися до шини i2c (адреса для майстра не обов'язковий) Serial.begin(9600); // налаштувати послідовний порт для виведення ) void loop() ( Wire.requestFrom(2, 6);// запитати 6 байтів від веденого пристрою #2 while(Wire.available()) // ведений пристрій може надіслати менше, ніж запрошено (char c = Wire.read(); // прийняти байт як символ Serial.print (c); // надрукувати символ ) delay(500);

Wire.setClock()

Опис

Змінює тактову частоту зв'язку по шині I2C. У ведених I2C пристроїв немає мінімальної робочої тактової частоти, проте зазвичай використовується 100 кГц.

Синтаксис

Wire.setClock(clockFrequency)

Параметри

clockFrequency: значення частоти (в герцах) тактового сигналу. Приймаються значення 100000 (стандартний режим) та 400000 (швидкий режим). Деякі процесори також підтримують 10000 (низькошвидкісний режим), 1000000 (швидкий режим плюс) та 3400000 (високошвидкісний режим). Щоб переконатися, що необхідний режим підтримується, зверніться до документації на конкретний процесор.

Значення, що повертається

Wire.onReceive()

Опис

Реєструє функцію, яка буде викликатися, коли керований пристрій приймає передачу від майстра.

Синтаксис

Wire.onReceive(handler)

Параметри

handler: функція, яка повинна буде викликатись, коли ведений пристрій приймає дані; вона повинна приймати один параметр int (кількість байтів, прочитаних від майстра) і нічого не повертати, тобто:

void myHandler(int numBytes)

Значення, що повертається

приклад

#include void setup() ( Wire.begin(8); // підключитися до i2c шини з адресою #8 Wire.onReceive(receiveEvent); // зареєструвати обробник події Serial.begin(9600); // налаштувати послідовний порт для виведення ) void loop() ( delay(100); ) // функція, яка буде виконуватися щоразу, коли від майстра приймаються дані // дана функція реєструється як обробник події, дивіться setup() void receiveEvent(int howMany) ( while (1< Wire.available()) // пройтись по всем до последнего { char c = Wire.read(); // принять байт как символ Serial.print(c); // напечатать символ } int x = Wire.read(); // принять байт как целое число Serial.println(x); // напечатать число }

Wire.onRequest()

Опис

Реєструє функцію, яка буде викликатись, коли майстер запитує дані від веденого пристрою.

Синтаксис

Wire.onRequest(handler)

Параметри

handler: функція, яка повинна буде викликатись, вона не приймає параметрів і нічого не повертає, тобто:

void myHandler()

Значення, що повертається

приклад

Код для плати Arduino, що працює як ведений пристрій:

#include void setup() ( Wire.begin(8); // підключитися до i2c шини з адресою #8 Wire.onRequest(requestEvent); // зареєструвати обробник події ) void loop() ( delay(100); ) // функція, яка буде виконуватися щоразу, коли майстром будуть // запитані дані // дана функція реєструється як обробник події, дивіться setup() void requestEvent() ( Wire.write("hello "); // відповісти повідомленням )

Мені потрібно було зробити годинник на основі мікросхеми, що має I 2 C інтерфейс. Мікросхема RTC, т.зв. "годинник реального часу" PCF8583.

Усередині мікросхеми розташовані: годинник, будильник, таймер, календар (кривий) і 240 байт оперативної пам'яті, куди можна записувати будь-яку інформацію, яку тільки заманеться. Оперативна пам'ять це дуже корисна штука, на відміну від флеш-пам'яті, оперативна пам'ять не має обмежень за кількістю циклів перезапису, і в неї можна зберігати якісь дані, налаштування, скільки завгодно часто.

Але була одна проблемка - писати код страшно не хотілося, і я вирішив знайти готовий код в інтернеті. Як пізніше з'ясувалося, знайти "на свою голову". Завантажив приклад роботи з I 2 C, підправив, прошив мікроконтролер. Чи не запрацювало. Став колупати код, шукати причину непрацездатності… і жахнувся!! Запис у деяких випадках велася на весь порт відразу, а не в конкретні біти. Таким чином, якщо на порт ще щось повісити, наприклад, дисплей, то швидше за все, воно працювати не буде. Також неправильно було реалізовано читання даних по шині (без генерацій умови закінчення прийому або просто без NACK). Але це пів-біди. Основна проблема в іншому. Найчастіше автор коду виставляв у порт логічну "1", а як ми знаємо, шина I 2 C управляється "притягуванням" висновків SDA та SCL до загального дроту. А логічна «1» на шині, у свою чергу, формується рахунок підтяжки до плюсу живлення резисторами на 4,7 кілоом. Таким чином, якщо на виході мікроконтролера виставити логічну «1», а ведений пристрій «притягне» цей вихід до спільного дроту, то «ба-бах» вийде коротке замикання. Мені це дуже не сподобалося, і я вирішив винайти свій велосипед написати свою бібліотеку, а вірніше навіть дві бібліотеки: одна для роботи з шиною I 2 C, а інша безпосередньо для роботи з годинником реального часу PCF8583. Так, до речі, код написаний у .

Для того щоб підключити бібліотеку I 2 C до проекту, потрібно прописати її через include, як на картинці, а також скопіювати бібліотеку в папку з проектом.

Після цього необхідно відкрити файл "i2c.h", і вказати ніжки мікроконтролера, які будуть виступати в ролі шини I 2 C. За замовчуванням шина налаштована на ніжки PC0 (SCL) і PC1 (SDA). А налаштування робиться ось тут:

Все, бібліотеку I2C ми підключили, ніжки налаштували, бібліотека готова до роботи. Приклад використання:

I2c_init(); // Ініціалізація шини I2C i2c_start_cond(); // старт шини i2c_send_byte (0xA0); // адресу пристрою, що висить на шині i2c_send_byte (0x10); // байт даних, який записуємо до пристрою i2c_send_byte (0x10); // ще один байт даних, який записуємо у пристрій i2c_stop_cond(); // стоп шини

Після стоп-умови ми можемо перевірити, чи все у нас в порядку з шиною I 2 C. Для цього потрібно прочитати змінну «i2c_frame_error». Якщо все нормально, то в ній буде 0. Якщо один із висновків шини не «підтягнувся» до живлення, і логічна «1» не встановилася на шині, то бібліотека генерує помилку і записує в змінну «i2c_frame_error» циферку 1. Читати змінну « i2c_frame_error» потрібно після стоп-умови. На малюнку нижче продемонструю, як працює контроль помилки:

Тепер займемося підключенням бібліотеки годинника реального часу PCF8583. Для цього потрібно зробити ті ж дії. Скопіюємо в папку з проектом файл "PCF8583.h" і пропишемо його в include, як на фото:

Готово. Бібліотека годинника реального часу PCF8583 підключена. Вона не потребує будь-яких налаштувань, тому можна відразу приступати до читання часу та дати з мікросхеми. Звертаю увагу, що бібліотека PCF8583 працює за допомогою бібліотеки I2C, тому якщо хочемо працювати з PCF8583, потрібно підключити обидві бібліотеки!

Приклад використання бібліотеки (запис та читання часу та дати):

// Ініціалізація шини I2C i2c_init(); // Підготовляємо час та дату для запису в мікросхему PCF8583 PCF_hour=23; // 23 години PCF_min = 59; // 59 хвилин PCF_day=31; // 31 число PCF_month=12; // 12 місяць – грудень PCF_year=0; // Рік (0 - не високосний) PCF_weekday = 6; // 6 день тижня (неділя) // Записуємо час та дату в мікросхему PCF8583 PCF_write_hh_mm_ss(); // Зчитуємо час та дату з мікросхеми PCF8583 PCF_read_hh_mm_ss(); Приклад роботи з оперативною пам'яттю (запис та читання) // Підготовляємо 5 байт для запису в мікросхему PCF8583 PCF_data_ram_1=255; // байт 1 PCF_data_ram_2=255; // байт 2 PCF_data_ram_3=255; // байт 3 PCF_data_ram_4=255; // байт 4 PCF_data_ram_5=255; // байт 5 // Записуємо 5 байт у мікросхему PCF8583 PCF_write_ram(); // Зчитуємо 5 байт із мікросхеми PCF8583 PCF_read_ram();

Читання з мікросхеми ще простіше – достатньо викликати функціюPCF_ read_ hh_ mm_ ss() після чого час і дата з'являться в змінних, звідки їх тільки забирай. Для читання оперативної пам'яті відповідно використовуємо функціюPCF_ read_ ram() після чого дані забираємо до зміннихPCF_ data_ ram_ N

Ось список змінних, де і що зберігається:

// час та дата PCF_hour = 0; // час, годинник (від 0 до 23, захист від переповнення під час запису та читання) PCF_min=0; // час, хвилини (від 0 до 59, захист від переповнення під час запису та читання) PCF_sec=0; // час, секунди (тільки читання, під час запису скидаються в 00) PCF_day=0; // день (від 1 до 31, захист від переповнення під час запису та читання) PCF_weekday=0 // день тижня (0-понеділок; 6-неділя, захист від переповнення під час запису та читання) PCF_month=0; // Місяць (від 1 до 12, захист від переповнення при записі та читанні) PCF_year=0; // рік (0-високосний; 1,2,3-невисокосний, захист від переповнення при записі та читанні) // оперативна пам'ять PCF_data_ram_1; //Дані (ОЗУ PCF8583), байт 1 PCF_data_ram_2; //Дані (ОЗУ PCF8583), байт 2 PCF_data_ram_3; //Дані (ОЗУ PCF8583), байт 3 PCF_data_ram_4; //Дані (ОЗУ PCF8583), байт 4 PCF_data_ram_5; // Дані (ОЗП PCF8583), байт 5

Тепер розповім про захист від переповнення. Допустимо, ми забули підключити мікросхему. Прочитаємо дані з мікросхеми, і ... прочитається байт 11111111, або число 255. Вся справа в тому, що в основі шини I 2 C лежать 2 резистора, що підтягують, ось вони те і видають нам логічні «одинички» якщо мікросхема не підключена. Для захисту від подібних випадків, у бібліотеці PCF8583 я зробив захист від переповнень, який стежить за тим, щоб годинник не показував вам 62 години 81 хвилину… Наявність переповнення можна простежити, прочитавши змінну PCF_overflow. Якщо в ній 0, значить помилок переповнення не було. Якщо в ній 1 або більше, то помилки переповнення є. Читати змінну «PCF_overflow» потрібно після функції читання дати та часуPCF_ read_ hh_ mm_ ss()

Для наочності проект AVR Studio 6 під ATmega32 додається. Перекомпілювати можна під будь-який AVR. У проекті також підключив дисплей для візуального контролю. При подачі живлення мікроконтролер встановлює 23 години 59 хвилин, 31 грудня, Неділя. І за хвилину стає 00 годин 00 хвилин, 1 січня, Понеділок.

Тепер розповім, чому я говорив про "кривий" календар цієї мікросхеми. Справа в тому, що мікросхема не вміє зберігати поточний календарний рік, а зберігає лише прапор високосного року. Коротше кажучи:
0 – високосний рік
1 – не високосний рік
2 – не високосний рік
3 – не високосний рік

І так за циклом 0-1-2-3-0-1-2-3-0…

Загалом, щоб зробити нормальний календар, потрібно реалізовувати програмний розрахунок та збереження року, наприклад, у ту ж оперативну пам'ять PCF8583, але це не зручно. А головне, що за знеструмленої схеми пам'ять, на жаль, ніхто не перезапише...

Також додаю наприкінці статті невеликий відеозвіт. У програмуванні я можна сказати новачок, хоч і програмую вже 3 роки (помалу), за код суворо не судіть, якщо є якісь доповнення та зауваження, пишіть, виправлятимемо. Всім вдалих саморобок!

Список радіоелементів

Позначення Тип Номінал Кількість ПриміткаМагазинМій блокнот
МК AVR 8-біт

ATmega32

1 До блокноту
Годинник реального часу (RTC)

PCF8583

1 До блокноту
LCD-дисплейWH16021

Why another I2C library?

The standard I2C library для Arduino is the Wire library . While this library is sufficient most of the time, there are situations when it cannot be used:

  • I2C pins A4/A5 (або SDA/SCL) є в тому випадку, якщо інші purposes,
  • code shall run on both ATmega processor with 16 MHz and ATtiny processor with 1 MHz ,
  • ви є short on memory (flash and RAM).

Features

  • compatible with all 8-bit AVR MCUs
  • can make use of almost any pin
  • clock stretching (by slaves) supported
  • timeout on clock stretching
  • timeout on ACK polling for busy devices (new!)
  • internal MCU pullup resistors can be used (new!)
  • дуже lightweight (250 bytes of flash і 0 byte of RAM, except for call stack)
  • very fast (standard and fast mode on UNO, 33 kHz with 1 MHz CPU clock)
  • Optional Wire library compatible interface
  • no bus arbitration (i.e., лише один master allowed on bus)
  • supports only master mode
  • GPL license

Using the library

Alternative Interface

Meanwhile, я маю писемний брокер навколо SoftI2CMaster що emulates the Wire library (master mode only). Це інший C++-header файл, який називається SoftWire. Directly after this include statement you need to create a Wire instance.

Цей розділ sacrifices є деякими зразками оригіналу, в особливих його малого друку, але їсти потрібні, якщо ви потребуєте відшкодування оригіналу. Наступні table lists the memory requirements.

WireSoftI2CMaster SoftWire Flash memory RAM
1956 252 712 208 0 64
Сподобалася стаття? Поділіться з друзями!