Подключение нескольких I2C устройств с одинаковыми адресами

svm
Offline
Зарегистрирован: 06.11.2016

При проектировании генератора, возникла проблема - необходимо вывести на индикатор 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;  }


}

 

ptr
Offline
Зарегистрирован: 28.05.2016

Если честно, я так и не понял, откуда берется высокий уровне на входе SDA МК, когда он ожидает подтверждения приема байта от ведомого.

 

inspiritus
Offline
Зарегистрирован: 17.12.2012

... И не надо так кричать, тут и с первого раза все слышно.

svm
Offline
Зарегистрирован: 06.11.2016

В данном случае эмиттерный повторитель работает в качестве ключа, и обеспечивает двунаправленную трансляцию. Во всяком случае при длине проводо около 10 см все работает. Как будет при длинной линии не знаю.

svm
Offline
Зарегистрирован: 06.11.2016

inspiritus пишет:

... И не надо так кричать, тут и с первого раза все слышно.

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

ptr
Offline
Зарегистрирован: 28.05.2016

Все, дошло. Высокий уровень будет сформирован через R1 или R2 на переходе БК Q1 или Q2 в зависимости от уровня на выходе CS.

Клапауций 234
Offline
Зарегистрирован: 24.10.2016

создание сотни тем с одинаковыми названиями.

svyatokha
Offline
Зарегистрирован: 20.08.2019

Вопрос, а вроде можно шину SDA пустить через CD4051. выйдет что при этом можно до 8 I2C устройств с одинаковым адресом? или я что-то упустил?)

svm
Offline
Зарегистрирован: 06.11.2016

svyatokha пишет:

Вопрос, а вроде можно шину SDA пустить через CD4051. выйдет что при этом можно до 8 I2C устройств с одинаковым адресом? или я что-то упустил?)

Должно работать.