В данном уроке мы настроим микроконтроллер Atmega8 в качестве Slave для шины I2C(TWI), а так же плату Arduino Nano в качестве Master шины I2C.
Для начала займемся микроконтроллером Atmega8.
Для настройки шины I2С нам понадобится регистр TWCR:
******************
TWINT — флаг прерывания. Сброс его означает что конечный автомат провернется дальше, а прерывание будет снова уловлено.
TWEA — Enable ACK. Разрешение ответа ACK. Если его включить, то автомат TWI будет отзываться на свой адрес, а также давать ACK во всех случаях когда этого требует протокол. Скажем, после прием байта. Если нам надо послать NACK то бит не ставим.
TWSTA — Сформировать старт. Причем не факт, что прямо сейчас. От текущего состояния зависит. Например, если этот бит поставить в 0х38 состоянии, то старт будет сформирован когда шина освободится. Контроллер TWI умный и сам все хорошо знает.
TWSTO — сделать Stop. Опять же аналогично. После записи в этот бит модуль отваливается от сессии передачи. МК становится неадресованным ведомым.
TWWC — конфликт записи. Сигнализирует о том, что кто то из прикладной программы записал в TWDR данные. Тогда как в TWDR полагается писать только при поднятом TWINT (в нашем случае это будет толкьо в обработчике прерывания).
TWEN — блок TWI включен. Только и всего.
TWIE — прерывания от TWI разрешены.
Подчиненный:
#include <Wire.h>
#define GPIO0 2
#define GPIO1 3
#define GPIO11 11
#define GPIO12 12
int i =0;
int out[8]={0,0,0,0,0,0,0,0};
void setup() {
Wire.begin(10); /* задаем на шине i2c 10 адрес */
Wire.onReceive(receiveEvent); /* регистрируем полученное событие */
Wire.onRequest(requestEvent); /* регистрируем запрошенное событие */
Serial.begin(9600); /* открываем серийный порт для дебаггинга */
pinMode(GPIO0, OUTPUT);
pinMode(GPIO1, OUTPUT);
pinMode(GPIO11, INPUT);
digitalWrite(GPIO11, HIGH);
pinMode(GPIO12, INPUT);
digitalWrite(GPIO12, HIGH);
}
void loop() {
delay(100);
}
// Функция для извлечения любых принимаемых данных от мастера на шину
void receiveEvent(int howMany) {
i=0;
while (0 <Wire.available()) {
out[i] = Wire.read(); /* получаем байт как число*/
switch (i){
case 0:
{
if (out[0]==1) digitalWrite(GPIO0, HIGH);
else digitalWrite(GPIO0, LOW);
}
break;
case 1:
{
if (out[1]==1) digitalWrite(GPIO1, HIGH);
else digitalWrite(GPIO1, LOW);
}
break;
case 2:
{
if (out[i]==1) out[i]=1;
else out[i]=0;
}
break;
case 3:
{
if (out[i]==1) out[i]=1;
else out[i]=0;
}
break;
case 4:
{
if (out[i]==1) out[i]=1;
else out[i]=0;
}
break;
case 5:
{
if (out[i]==1) out[i]=1;
else out[i]=0;
}
break;
case 6:
{
if (out[i]==1) out[i]=1;
else out[i]=0;
}
break;
case 7:
{
if (out[i]==1) out[i]=1;
else out[i]=0;
}
break;
}
Serial.print(out[i]); /* выводим символ в серийный порт */
i++;
}
Serial.println(); /* переходим на новую строку */
}
// Отправляем данные на мастер.
void requestEvent() {
Wire.write(digitalRead(GPIO0));
Wire.write(digitalRead(GPIO1));
Wire.write(1);
Wire.write(1);
Wire.write(0);
Wire.write(1);
Wire.write(1);
Wire.write(0);
Wire.write(digitalRead(GPIO11));
Wire.write(digitalRead(GPIO12));
Wire.write(0);
Wire.write(0);
Wire.write(0);
Wire.write(1);
Wire.write(1);
Wire.write(1);
}