В этом уроке мы научимся определять адреса устройств на шине I2C, аппаратно устанавливая состояния Start/Stop на шине I2C и передавая байт данных с адресом устройства и битом RW.
Нам понадобится:
- Arduino х 1шт.
- LCD дисплей LCD1602 IIC/I2C(синий) или LCD1602 IIC/I2C(зелёный) х 1шт.
- Trema Shield х 1шт.
- Trema-модуль i2C Hub х 1шт.
- Trema-модуль кнопка c проводом х 1шт.
- Шлейф «мама-мама»для шины I2С х 2шт.
- Устройства и модули с шиной I2C, адреса которых Вы хотите узнать, до 126 шт.
Для реализации проекта нам необходимо установить одну библиотеку:
- Библиотека LiquidCrystal_I2C_V112 (для работы с дисплеем LCD1602 по шине I2C)
О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE, а о том, как работать с LCD дисплеями, на странице Wiki - Работа с символьными ЖК дисплеями.
Видео:
Схема подключения:
- Подключение LCD дисплея осуществляется к аппаратным выводам шины I2C.
- Кнопка подключается к цифровому выводу 2.
Алгоритм работы:
- При однократном нажатии на кнопку - выводится очередной адрес.
- При удержании кнопки - производится чтение адресов, всех подключенных к шине 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, если кнопка не нажата.


Обсуждение