Подключение нескольких 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
001 | #include <Wire.h> |
002 | long rez; |
003 | byte scan_code,dl; |
004 | byte sr[8]; // массив разрядов индикатора |
005 |
006 | //массив изображений 7 сегментных символов от 0 до 9 и пустота |
007 | byte simv[11]={ |
008 | B00111111, //0 |
009 | B00000110, //1 |
010 | B01011011, //2 |
011 | B01001111, //3 |
012 | B01100110, //4 |
013 | B01101101, //5 |
014 | B01111101, //6 |
015 | B00000111, //7 |
016 | B01111111, //8 |
017 | B01101111, //9 |
018 | B00000000, //пустота |
019 | }; |
020 |
021 | void setup () { |
022 | //Serial.begin(9600); |
023 | |
024 | pinMode(A3, OUTPUT); // *********** ПОРТ УПРАВЛЕНИЯ I2C ХАБОМ ************* |
025 |
026 | |
027 | Wire.begin(); |
028 | // *********инициализация таймеров генератора************ |
029 |
030 |
031 | pinMode (9,OUTPUT); // выход генератора |
032 | TCCR1A=1<<COM1A0; //подключить выход OC1A первого таймера |
033 | TCCR1B=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ый-основной дисплей и клавиатуру |
063 | Wire.beginTransmission(0x24); //обращаемся к любому порту 0х24-0х27 |
064 | Wire.write(0b01000001); //включаем:яркость 4,8 битный режим, отображение ON |
065 | Wire.endTransmission(); // закрываем сессию |
066 | digitalWrite(A3, 0); // 0- выбирает 2ой-дополнительный дисплей |
067 | Wire.beginTransmission(0x24); //обращаемся к любому порту 0х24-0х27 |
068 | Wire.write(0b01000001); //включаем:яркость 4,8 битный режим, отображение ON |
069 | Wire.endTransmission(); // закрываем сессию |
070 | digitalWrite(A3, 1); // возвращаемся к основному дисплею |
071 | // ************************************************** |
072 | } |
073 |
074 | void 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 | //Выделяем разряды и записываем их в массив разрядов индикатора |
103 | sr[0]=(rez%10); |
104 | sr[1]=(rez%100/10); |
105 | sr[2]=(rez%1000/100); |
106 | sr[3]=(rez%10000/1000); |
107 | sr[4]=(rez%100000/10000); |
108 | sr[5]=(rez%1000000/100000); |
109 | sr[6]=(rez%10000000/1000000); |
110 | sr[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 | |
121 | Wire.beginTransmission(0x37); //Пишем в 4 разряд |
122 | Wire.write(simv[sr[0]]); |
123 | Wire.endTransmission(); // закрываем сессию |
124 |
125 | Wire.beginTransmission(0x36); //Пишем в 3 разряд |
126 | Wire.write(simv[sr[1]]); |
127 | Wire.endTransmission(); // закрываем сессию |
128 |
129 | Wire.beginTransmission(0x35); //Пишем вo 2 разряд |
130 | Wire.write (simv[sr[2]]); |
131 | Wire.endTransmission(); // закрываем сессию |
132 |
133 | Wire.beginTransmission(0x34); //Пишем в 1 разряд |
134 | Wire.write(simv[sr[3]]); // |
135 | Wire.endTransmission(); // закрываем сессию |
136 |
137 |
138 | digitalWrite(A3, 0); // ********* ПЕРЕКЛЮЧАЕМСЯ НА ВТОРОЙ ДИСПЛЕЙ ********** |
139 |
140 |
141 | Wire.beginTransmission(0x37); //Пишем в 4 разряд |
142 | Wire.write(simv[sr[4]]); |
143 | Wire.endTransmission(); // закрываем сессию |
144 |
145 | Wire.beginTransmission(0x36); //Пишем в 3 разряд |
146 | Wire.write(simv[sr[5]]); |
147 | Wire.endTransmission(); // закрываем сессию |
148 |
149 | Wire.beginTransmission(0x35); //Пишем вo 2 разряд |
150 | Wire.write (simv[sr[6]]); |
151 | Wire.endTransmission(); // закрываем сессию |
152 |
153 | Wire.beginTransmission(0x34); //Пишем в 1 разряд |
154 | Wire.write(simv[sr[7]]); // |
155 | Wire.endTransmission(); // закрываем сессию |
156 |
157 | digitalWrite(A3, 1); // ********** ВОЗВРАЩАЕМСЯ НА ОСНОВНОЙ ДИСПЛЕЙ ************ |
158 | |
159 | delay(200); |
160 | //_________________ * ГЕНЕРАТОР * _________________ |
162 |
163 | static uint32_t enc=1; //переменная счёта энкодера |
164 | uint32_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 | } |
Если честно, я так и не понял, откуда берется высокий уровне на входе SDA МК, когда он ожидает подтверждения приема байта от ведомого.
... И не надо так кричать, тут и с первого раза все слышно.
В данном случае эмиттерный повторитель работает в качестве ключа, и обеспечивает двунаправленную трансляцию. Во всяком случае при длине проводо около 10 см все работает. Как будет при длинной линии не знаю.
... И не надо так кричать, тут и с первого раза все слышно.
Прошу прощения , на форуме недавно, почему-то создалось несколько тем. Сообщил модераторам, удалили.
Все, дошло. Высокий уровень будет сформирован через R1 или R2 на переходе БК Q1 или Q2 в зависимости от уровня на выходе CS.
создание сотни тем с одинаковыми названиями.
Вопрос, а вроде можно шину SDA пустить через CD4051. выйдет что при этом можно до 8 I2C устройств с одинаковым адресом? или я что-то упустил?)
Вопрос, а вроде можно шину SDA пустить через CD4051. выйдет что при этом можно до 8 I2C устройств с одинаковым адресом? или я что-то упустил?)
Должно работать.