Подключение нескольких 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

 

 

 

001#include <Wire.h>
002 long rez;
003 byte scan_code,dl;
004 byte sr[8];// массив разрядов индикатора
005 
006//массив изображений 7 сегментных символов от 0 до 9 и пустота
007byte simv[11]={
008B00111111, //0
009B00000110, //1
010B01011011, //2
011B01001111, //3
012B01100110, //4
013B01101101, //5
014B01111101, //6
015B00000111, //7
016B01111111, //8
017B01101111, //9
018B00000000, //пустота
019};
020 
021void setup() {
022//Serial.begin(9600); 
023  
024 pinMode(A3, OUTPUT);// *********** ПОРТ УПРАВЛЕНИЯ I2C ХАБОМ *************
025 
026   
027  Wire.begin();
028// *********инициализация таймеров генератора************
029 
030 
031pinMode (9,OUTPUT);      // выход генератора
032TCCR1A=1<<COM1A0;        //подключить выход OC1A первого таймера
033TCCR1B=0;                //
034 
035// адреса регистров управления и данных ТМ1650
036// 1-0х24
037// 2-0х25
038// 3-0х26
039// 4-0х27
040// *********инициализация дисплея************
041//___________________________________________
042//b7 b6 b5 b4 b3 b2 b1 b0 IФункция   I опис. I
043//___________________________________________
044//x  0  0  0      x  x    I          I   8   I
045//x  0  0  1      x  x    I          I   1   I
046//x  0  1  0      x  x    I          I   2   I
047//x  0  1  1      x  x    I яркость  I   3   I
048//x  1  0  0      x  x    I          I   4   I
049//x  1  0  1      x  x    I          I   5   I
050//x  1  1  0      x  x    I          I   6   I
051//x  1  1  1      x  x    I          I   7   I
052//____________________________________________
053//x           0   x  x    I  режим   I 8ceгм I
054//x           1   x  x    I 7/8 bit  I 7ceгм I
055//____________________________________________
056//x               x  x  0 Ibit ON/OFFI  OFF  I
057//x               x  x  1 I  дисплея I   ON  I
058//____________________________________________
059 
060   
061                     // ********** ИНИЦИАЛИЗАЦИЯ  ДИСПЛЕЕВ *************
062   digitalWrite(A3, 1);            //  1- выбирает 1ый-основной дисплей и клавиатуру
063Wire.beginTransmission(0x24);      //обращаемся к любому порту 0х24-0х27
064   Wire.write(0b01000001);         //включаем:яркость 4,8 битный режим, отображение ON
065Wire.endTransmission();            // закрываем сессию
066   digitalWrite(A3, 0);            //  0- выбирает 2ой-дополнительный дисплей
067Wire.beginTransmission(0x24);      //обращаемся к любому порту 0х24-0х27
068   Wire.write(0b01000001);         //включаем:яркость 4,8 битный режим, отображение ON
069Wire.endTransmission();            // закрываем сессию
070   digitalWrite(A3, 1);            // возвращаемся к основному дисплею
071//                     **************************************************
072}
073 
074void loop() {
075  
076  //********************* чтение клавиатуры *************************
077 readkl:
078 Wire.beginTransmission(0x25);        // обращаемся к клавиатуре(к любому порту 0х24-0х27)
079 Wire.requestFrom((0x25), 1);         //запрашиваем один байт
080  scan_code = Wire.read();            // читаем скан код
081 Wire.endTransmission();              // закрываем сессию
082 if (scan_code <69) goto readkl;
083 if (scan_code ==70 )scan_code =1;
084 if (scan_code ==69 )scan_code =2;
085 if (scan_code ==79 )scan_code =3;
086 if (scan_code ==101)scan_code =4;
087 if (scan_code ==87 )scan_code =5;
088 if (scan_code ==117)scan_code =6;
089 if (scan_code ==103)scan_code =7;
090 if (scan_code ==102)scan_code =8;
091 if (scan_code ==119)scan_code =9;
092 if (scan_code ==78 )scan_code =0;
093 if (scan_code ==110)rez=0;sr[1]=0;sr[2]=0;sr[3]=0;sr[4]=0;           // обнулить
094 if (scan_code ==94 ){rez=rez/10; goto wuw;}// коррекция
095 if (scan_code <12 ){ rez=rez*10; rez= rez+scan_code; }
096 
097 
098  
099  wuw:
100  //Serial.println(rez);
101 
102//Выделяем разряды и записываем их в массив разрядов индикатора
103sr[0]=(rez%10);
104sr[1]=(rez%100/10);
105sr[2]=(rez%1000/100);
106sr[3]=(rez%10000/1000);
107sr[4]=(rez%100000/10000);
108sr[5]=(rez%1000000/100000);
109sr[6]=(rez%10000000/1000000);
110sr[7]=(rez%100000000/10000000);
111  
112// адреса разрядов индикатора
113// 1-0х34
114// 2-0х35
115// 3-0х36
116// 4-0х37
117 
118 
119//           ******** ПИШЕМ В ОСНОВНОЙ ДИСПЛЕЙ *********
120  
121Wire.beginTransmission(0x37);//Пишем в 4 разряд
122  Wire.write(simv[sr[0]]);
123Wire.endTransmission();             // закрываем сессию
124 
125Wire.beginTransmission(0x36);//Пишем в 3 разряд
126  Wire.write(simv[sr[1]]);
127Wire.endTransmission();             // закрываем сессию
128 
129Wire.beginTransmission(0x35);//Пишем вo 2 разряд
130  Wire.write (simv[sr[2]]);
131Wire.endTransmission();             // закрываем сессию
132 
133Wire.beginTransmission(0x34);//Пишем в 1 разряд
134  Wire.write(simv[sr[3]]);//
135Wire.endTransmission();             // закрываем сессию
136 
137 
138 digitalWrite(A3, 0);//  ********* ПЕРЕКЛЮЧАЕМСЯ НА ВТОРОЙ ДИСПЛЕЙ **********
139 
140 
141Wire.beginTransmission(0x37);//Пишем в 4 разряд
142  Wire.write(simv[sr[4]]);
143Wire.endTransmission();             // закрываем сессию
144 
145Wire.beginTransmission(0x36);//Пишем в 3 разряд
146  Wire.write(simv[sr[5]]);
147Wire.endTransmission();             // закрываем сессию
148 
149Wire.beginTransmission(0x35);//Пишем вo 2 разряд
150  Wire.write (simv[sr[6]]);
151Wire.endTransmission();             // закрываем сессию
152 
153Wire.beginTransmission(0x34);//Пишем в 1 разряд
154  Wire.write(simv[sr[7]]);//
155Wire.endTransmission();             // закрываем сессию
156 
157 digitalWrite(A3, 1);//  ********** ВОЗВРАЩАЕМСЯ НА ОСНОВНОЙ ДИСПЛЕЙ ************
158  
159 delay(200);
160//_________________ * ГЕНЕРАТОР * _________________
162 
163static uint32_t enc=1; //переменная счёта энкодера
164uint32_t ocr; uint32_t divider; float freq;
165 
166 enc = rez; //передаем значение частоты в герцах в ГЕНЕРАТОР
167            //расчёт прескалера и OCR по нужной частоте
168   divider=1; ocr = (F_CPU / enc /2 /divider);
169   if (ocr >65536) { divider=8; ocr = F_CPU / enc /2 /divider;
170       if (ocr >65536) { divider=64; ocr = F_CPU / enc /2 /divider;
171           if (ocr >65536)  {divider=256; ocr = F_CPU / enc /2 /divider;
172               if (ocr >65536) { divider=1024; ocr = F_CPU / enc /2 /divider;
173                   if (ocr >65536){ocr=65536; }}}}} OCR1A=ocr-1;
174              //запись в регистр прескалера           
175   switch (divider) {
176     case 1: TCCR1B=1|(1<<WGM12); break;
177      case 8: TCCR1B=2|(1<<WGM12); break;
178       case 64: TCCR1B=3|(1<<WGM12); break;
179        case 256: TCCR1B=4|(1<<WGM12); break;
180         case 1024: TCCR1B=5|(1<<WGM12); break;  }
181 
182 
183}

 

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 устройств с одинаковым адресом? или я что-то упустил?)

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