Подключение нескольких I2C устройств с одинаковыми адресами
- Войдите на сайт для отправки комментариев
При проектировании генератора, возникла проблема - необходимо вывести на индикатор 8 разрядов, а вналичии есть два четырехразрядных индикатора на микросхемах TM 1650 или FD650В. Проблема в том, что они управляются по шине I2C и имеют одинаковые адреса. Для решения конкретной задачи (генератор до 4000 Гц), это вполне устраивало, и первый вариант успешно со своей задачей справился http://arduino.ru/forum/programmirovanie/kontroller-led-i-klaviatury-fd650v-kak-im-upravlyat#comment-232263Далее захотелось использовать генератор по максимуму (до 8 МГц), для этого нужно было увеличить число разрядов до 8. Порывшись в инете нашел в основном теорию и использование специальных микросхем, которых в наличии нет. В результате появилась такая конструкция:
Подключается к аппаратному порту I2C ардуино, а дисплеи к выходному разъему. CSL идет напрямую, а SDA rjvvкоммутируются транзисторами Q1 и Q2. Переключение осуществляется логическими 0 или 1 с пина А3. В принципе можно поменять CSL и SDA при этом работоспособность сохраняется. Управление можно тоже взять с любого свободного выхода. Остальные I2C устройства с уникальными адресами подключаются стандартно.
При необходимости количество устройств с одинаковыми адресами можно увеличить используя дешифратор.
Пример применения в скетче. Отличия от скетча с четырехразрядной индикации в строках 24,62,66,70,138-157
#include <Wire.h> long rez; byte scan_code,dl; byte sr[8];// массив разрядов индикатора //массив изображений 7 сегментных символов от 0 до 9 и пустота byte simv[11]={ B00111111, //0 B00000110, //1 B01011011, //2 B01001111, //3 B01100110, //4 B01101101, //5 B01111101, //6 B00000111, //7 B01111111, //8 B01101111, //9 B00000000, //пустота }; void setup() { //Serial.begin(9600); pinMode(A3, OUTPUT);// *********** ПОРТ УПРАВЛЕНИЯ I2C ХАБОМ ************* Wire.begin(); // *********инициализация таймеров генератора************ pinMode (9,OUTPUT); // выход генератора TCCR1A=1<<COM1A0; //подключить выход OC1A первого таймера TCCR1B=0; // // адреса регистров управления и данных ТМ1650 // 1-0х24 // 2-0х25 // 3-0х26 // 4-0х27 // *********инициализация дисплея************ //___________________________________________ //b7 b6 b5 b4 b3 b2 b1 b0 IФункция I опис. I //___________________________________________ //x 0 0 0 x x I I 8 I //x 0 0 1 x x I I 1 I //x 0 1 0 x x I I 2 I //x 0 1 1 x x I яркость I 3 I //x 1 0 0 x x I I 4 I //x 1 0 1 x x I I 5 I //x 1 1 0 x x I I 6 I //x 1 1 1 x x I I 7 I //____________________________________________ //x 0 x x I режим I 8ceгм I //x 1 x x I 7/8 bit I 7ceгм I //____________________________________________ //x x x 0 Ibit ON/OFFI OFF I //x x x 1 I дисплея I ON I //____________________________________________ // ********** ИНИЦИАЛИЗАЦИЯ ДИСПЛЕЕВ ************* digitalWrite(A3, 1); // 1- выбирает 1ый-основной дисплей и клавиатуру Wire.beginTransmission(0x24); //обращаемся к любому порту 0х24-0х27 Wire.write(0b01000001); //включаем:яркость 4,8 битный режим, отображение ON Wire.endTransmission(); // закрываем сессию digitalWrite(A3, 0); // 0- выбирает 2ой-дополнительный дисплей Wire.beginTransmission(0x24); //обращаемся к любому порту 0х24-0х27 Wire.write(0b01000001); //включаем:яркость 4,8 битный режим, отображение ON Wire.endTransmission(); // закрываем сессию digitalWrite(A3, 1); // возвращаемся к основному дисплею // ************************************************** } void loop() { //********************* чтение клавиатуры ************************* readkl: Wire.beginTransmission(0x25); // обращаемся к клавиатуре(к любому порту 0х24-0х27) Wire.requestFrom((0x25), 1); //запрашиваем один байт scan_code = Wire.read(); // читаем скан код Wire.endTransmission(); // закрываем сессию if (scan_code <69) goto readkl; if (scan_code ==70 )scan_code =1; if (scan_code ==69 )scan_code =2; if (scan_code ==79 )scan_code =3; if (scan_code ==101)scan_code =4; if (scan_code ==87 )scan_code =5; if (scan_code ==117)scan_code =6; if (scan_code ==103)scan_code =7; if (scan_code ==102)scan_code =8; if (scan_code ==119)scan_code =9; if (scan_code ==78 )scan_code =0; if (scan_code ==110)rez=0;sr[1]=0;sr[2]=0;sr[3]=0;sr[4]=0; // обнулить if (scan_code ==94 ){rez=rez/10; goto wuw;}// коррекция if (scan_code <12 ){ rez=rez*10; rez= rez+scan_code; } wuw: //Serial.println(rez); //Выделяем разряды и записываем их в массив разрядов индикатора sr[0]=(rez%10); sr[1]=(rez%100/10); sr[2]=(rez%1000/100); sr[3]=(rez%10000/1000); sr[4]=(rez%100000/10000); sr[5]=(rez%1000000/100000); sr[6]=(rez%10000000/1000000); sr[7]=(rez%100000000/10000000); // адреса разрядов индикатора // 1-0х34 // 2-0х35 // 3-0х36 // 4-0х37 // ******** ПИШЕМ В ОСНОВНОЙ ДИСПЛЕЙ ********* Wire.beginTransmission(0x37);//Пишем в 4 разряд Wire.write(simv[sr[0]]); Wire.endTransmission(); // закрываем сессию Wire.beginTransmission(0x36);//Пишем в 3 разряд Wire.write(simv[sr[1]]); Wire.endTransmission(); // закрываем сессию Wire.beginTransmission(0x35);//Пишем вo 2 разряд Wire.write (simv[sr[2]]); Wire.endTransmission(); // закрываем сессию Wire.beginTransmission(0x34);//Пишем в 1 разряд Wire.write(simv[sr[3]]);// Wire.endTransmission(); // закрываем сессию digitalWrite(A3, 0);// ********* ПЕРЕКЛЮЧАЕМСЯ НА ВТОРОЙ ДИСПЛЕЙ ********** Wire.beginTransmission(0x37);//Пишем в 4 разряд Wire.write(simv[sr[4]]); Wire.endTransmission(); // закрываем сессию Wire.beginTransmission(0x36);//Пишем в 3 разряд Wire.write(simv[sr[5]]); Wire.endTransmission(); // закрываем сессию Wire.beginTransmission(0x35);//Пишем вo 2 разряд Wire.write (simv[sr[6]]); Wire.endTransmission(); // закрываем сессию Wire.beginTransmission(0x34);//Пишем в 1 разряд Wire.write(simv[sr[7]]);// Wire.endTransmission(); // закрываем сессию digitalWrite(A3, 1);// ********** ВОЗВРАЩАЕМСЯ НА ОСНОВНОЙ ДИСПЛЕЙ ************ delay(200); //_________________ * ГЕНЕРАТОР * _________________ //http://arduino.ru/forum/proekty/generator-s-reguliruemoei-chastotoi-na-arduino?page=3 static uint32_t enc=1; //переменная счёта энкодера uint32_t ocr; uint32_t divider; float freq; enc = rez; //передаем значение частоты в герцах в ГЕНЕРАТОР //расчёт прескалера и OCR по нужной частоте divider=1; ocr = (F_CPU / enc /2 /divider); if (ocr >65536) { divider=8; ocr = F_CPU / enc /2 /divider; if (ocr >65536) { divider=64; ocr = F_CPU / enc /2 /divider; if (ocr >65536) {divider=256; ocr = F_CPU / enc /2 /divider; if (ocr >65536) { divider=1024; ocr = F_CPU / enc /2 /divider; if (ocr >65536){ocr=65536; }}}}} OCR1A=ocr-1; //запись в регистр прескалера switch (divider) { case 1: TCCR1B=1|(1<<WGM12); break; case 8: TCCR1B=2|(1<<WGM12); break; case 64: TCCR1B=3|(1<<WGM12); break; case 256: TCCR1B=4|(1<<WGM12); break; case 1024: TCCR1B=5|(1<<WGM12); break; } }
Если честно, я так и не понял, откуда берется высокий уровне на входе SDA МК, когда он ожидает подтверждения приема байта от ведомого.
... И не надо так кричать, тут и с первого раза все слышно.
В данном случае эмиттерный повторитель работает в качестве ключа, и обеспечивает двунаправленную трансляцию. Во всяком случае при длине проводо около 10 см все работает. Как будет при длинной линии не знаю.
... И не надо так кричать, тут и с первого раза все слышно.
Прошу прощения , на форуме недавно, почему-то создалось несколько тем. Сообщил модераторам, удалили.
Все, дошло. Высокий уровень будет сформирован через R1 или R2 на переходе БК Q1 или Q2 в зависимости от уровня на выходе CS.
создание сотни тем с одинаковыми названиями.
Вопрос, а вроде можно шину SDA пустить через CD4051. выйдет что при этом можно до 8 I2C устройств с одинаковым адресом? или я что-то упустил?)
Вопрос, а вроде можно шину SDA пустить через CD4051. выйдет что при этом можно до 8 I2C устройств с одинаковым адресом? или я что-то упустил?)
Должно работать.