Скидки, ограниченное предложение! Полный список акционных товаров

Урок 24. Узнаём адреса устройств на шине I2C

Необходимые детали
Видео уроки

В этом уроке мы научимся определять адреса устройств на шине I2C, аппаратно устанавливая состояния Start/Stop на шине I2C и передавая байт данных с адресом устройства и битом RW.

Нам понадобится:

Для реализации проекта нам необходимо установить одну библиотеку:

  • Библиотека LiquidCrystal_I2C_V112 (для работы с дисплеем LCD1602 по шине I2C)

Видео:

Схема подключения:

  • Подключение LCD дисплея осуществляется к аппаратным выводам шины I2C.
  • Кнопка подключается к цифровому выводу 2.

Определение адресов устройств на шине I2C

Алгоритм работы:

  • При однократном нажатии на кнопку - выводится очередной адрес.
  • При удержании кнопки - производится чтение адресов, всех подключенных к шине I2C устройств.

Код программы:

// Подключаем библиотеки:
#include <Wire.h>                                                             // подключаем библиотеку для работы с шиной I2C (для работы с дисплеем)
#include <LiquidCrystal_I2C.h>                                                // подключаем библиотеку для работы с LCD дисплеем
// Объявляем переменные и константы:
LiquidCrystal_I2C lcd(0x27,16,2);                                             // объявляем  переменную для работы с LCD дисплеем, указывая параметры дисплея (адрес I2C = 0x27, количество столбцов = 16, количество строк = 2)
const uint8_t     PIN_button_SET = 2;                                         // указываем  номер вывода arduino, к которому подключена кнопка SET
      uint8_t     SEC_button_SET;                                             // переменная содержащая десятые доли секунд времени удержания кнопки SET
      uint8_t     NUM_found_ADDR;                                             // количество найденных адресов
      uint8_t     MAS_found_ADDR[127];                                        // массив     найденных адресов
      uint8_t     OUT_found_ADDR = 1;                                         // выводимый  адрес из списка найденных
void setup(){
  pinMode(PIN_button_SET, INPUT);                                             // конфигурируем вывод кнопки, как вход
  lcd.init();                                                                 // инициируем LCD дисплей
  lcd.backlight();                                                            // включаем подсветку LCD дисплея
  lcd.clear(); lcd.setCursor(0, 0); lcd.print(F("iArduino.ru"));              // выводим текст "iArduino.ru"
  delay(2000);                                                                // ждём 2 секунды
  lcd.clear(); lcd.setCursor(0, 0); lcd.print(F("Please click..."));          // выводим текст "Please click..."
}
void loop(){
  if(digitalRead(PIN_button_SET)){                                            //  Если нажата кнопка, то ...
    lcd.clear();                                                              //  Стираем экран
    SEC_button_SET=0;                                                         //  Обнуляем счётчик удержания кнопки
    while(digitalRead(PIN_button_SET)){                                       //  Создаём цикл, пока кнопка не будет отпушена
      delay(10);                                                              //  Пропускаем 10мс
      if(SEC_button_SET<100){SEC_button_SET++;}                               //  Если прошло меньше 1 секунды, инкрементируем счетчик удержания кнопки
      else{lcd.setCursor(0, 0); lcd.print(F("Start Search..."));}             //  Выводим на экран текст "Start Search..."
    }                                                                         //  Как только кнопка отпущена, выполняем одно из двух действий ...
    if(SEC_button_SET<100){                                                   //  Если кнопка SET удерживалась меньше 1 секунды, то показываем значение очередного адреса ...
      OUT_found_ADDR++; if(OUT_found_ADDR>NUM_found_ADDR){OUT_found_ADDR=1;}  //  Инкрементируем номер выводимого адреса
    }else{                                                                    //  Если кнопка SET удерживалась дольше 1 секунды, то читаем адреса устройств на шине I2C...
      NUM_found_ADDR=0;                                                       //  Сбрасываем количество найденных адресов
      OUT_found_ADDR=1;                                                       //  Сбрасываем номер выводимого адреса
      for(uint8_t i=1; i<127; i++){                                           //  Проходим по всем доступным адресам (от 1 до 126)
      if(func_START()){                                                       //  Устанавливаем состояние СТАРТ
      if(func_SEND(i)){                                                       //  Отправляем байт адреса с битом RW=0 (операция записи)
      if(i!=0x27){                                                            //  Если найден адрес 0x27, то пропускаем его, т.к. это адрес LCD дисплея
        MAS_found_ADDR[NUM_found_ADDR]=i; NUM_found_ADDR++;                   //  Добавляем адрес в массив
      }}} func_STOP();}                                                       //  Устанавливаем состояние СТОП
    }                                                                         //  Выводим данные на LCD дисплей
    lcd.clear();       lcd.setCursor(0, 0); lcd.print(F("ALL"));       lcd.setCursor(4, 0); lcd.print(F("ADDR = "  )); lcd.print(NUM_found_ADDR);
    if(NUM_found_ADDR){lcd.setCursor(0, 1); lcd.print(OUT_found_ADDR); lcd.setCursor(4, 1); lcd.print(F("ADDR = 0x")); lcd.print(MAS_found_ADDR[(OUT_found_ADDR-1)],HEX);}
  }
}
bool func_START()         {uint16_t i=0;              TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTA); while(!(TWCR & _BV(TWINT))){i++; if(i>=60000){return false;}} if((TWSR & 0xF8)!=0x08){return false;} return true;}
bool func_SEND (uint8_t j){uint16_t i=0; TWDR = j<<1; TWCR = _BV(TWINT) | _BV(TWEN);              while(!(TWCR & _BV(TWINT))){i++; if(i>=60000){return false;}} if((TWSR & 0xF8)!=0x18){return false;} return true;}
void func_STOP ()         {uint16_t i=0;              TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWSTO); while(!(TWCR & _BV(TWSTO))){i++; if(i>=60000){break;       }} delayMicroseconds(20);                             }

Алгоритм работы программы:

Код в функции loop() начинает выполняться только при условии, если нажата кнопка. Если таковое событие произошло, то начинает исполняться цикл while() выход из которого осуществляется при отпускании кнопки. В самом цикле происходит подсчёт времени удержания кнопки.

После отпускания кнопки, программа выполняет одно из двух действий:

  • Если кнопка удерживалась меньше 1 секунды, то происходит увеличение порядкового номера выводимого адреса.
  • Если кнопка удерживалась дольше 1 секунды, то происходит чтение всех доступных адресов на шине I2C.

Чтение адресов на шине I2C происходит в цикле for() от 1 до 127, где индекс цикла соответствует проверяемому адресу. Проверка на существование адреса осуществляется следующим образом:

  • Вызывается функция func_START, которая устанавливает состояние СТАРТ на шине I2C и возвращает результат установки данного состояния.
  • Если состояние СТАРТ установлено, то вызывается функция func_SEND, которая передает свой аргумент как байт адреса с битом RW=0 и если на шине зафиксирован ответ ACK, то возвращает результат true, иначе false.
  • Если на шине зафиксирован результат ACK, то переданный адрес сохраняется в массив найденных адресов, за исключением адреса 0x27 который является адресом LCD дисплея.
  • Вызывается функция func_STOP, которая устанавливает состояние СТОП на шине I2C.

И последнее действие программы - вывод данных на дисплей, не зависимо от того, как долго удерживалась кнопка.

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

Обсуждение

Присоединяйся

Другие уроки

На главную