Подключение нескольких 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 устройств с одинаковым адресом? или я что-то упустил?)
Должно работать.