Nagits's Blog

programming, fizfak science, etc…

AVR: Передача данных по шине I²C (I2C, IIC, TWI)

Налаживаем обмен данными между двумя контроллерами по шине I²C

С вашего разрешения я не буду вас томить всякими теоретическими копипастами и сразу перейдем к практической части.
Не, серьезно, почти каждый сайт об электронике содержит статью по этому протоколу, причем одну и ту же :).
Шина I²C состоит из двух линий:
  • SCL — линия последовательной передачи синхроимпульсов («при передаче посылок по шине I2C каждый ведущий генерирует свой синхросигнал на линии SCL» — http://ru.wikipedia.org/wiki/I%C2%B2C)
  • SDA — линия последовательной передачи данных
Эти линии обозначены на схемах выводов контроллера (pinout-схемы) в скобочках. К примеру, на mega16: PC1(SDA), PC0(SCL).

ATMEGA16-pinout

Если таких выводов на схеме не наблюдается, то скорее всего, в кристалл этот самый интерфейс шины I²C (точнее, модуль TWI — более подробно о I2C и TWI читайте в статье про 24CXX_EEPROM, см. в конце статьи) не интегрирован, т.е. аппаратной поддержки этого интерфейса нету и такой контроллер не способен обмениваться данными по этой шине.
Для статьи я выбрал два наиболее распространненных контроллера, имеющие этот интерфейс — ATMEGA16(пусть он будет у нас ведущим устройством) и ATMEGA8(а он будет ведомым).
Бибилиотека avr-libc, входящая в состав WinAVR, не содержит каких-либо готовых сорцев для работы с I²C (кстати там есть демонстрационный исходник для работы с «24Cxx I²C EEPROM» — /avr-libc/examples/twitest/twitest.c).
На вооружение я брал 2 различных исходника:
  • один предлагают специалисты компании Atmel в апноутах (AVR315 Использование модуля TWI в качестве ведущего интерфейса I2C и AVR311 Использование модуля TWI в качестве подчиненного интерфейса I2C)
  • другой принадлежит мистеру Pascal Stang, автору известного набора джентльмена Procyon AVRlib.
Более удобным оказался исходник из библиотеки Procyon AVRlib — в одном файле реализована поддержка и Master, и Slave устройств (в отличие от двух различных файлов в апноутах Atmel), а также подкупила простая и удобная процедура приема данных у slave-устройства. Извините, я уже забежал вперед.
Итак, получить Procyon AVRlib можно на сайте http://hubbard.engr.scu.edu/embedded/avr/avrlib/. Нам понадобятся следующие файлы из скачанного архива:
  • i2c.c и i2c.h — главное, что нам надо, однако в этих файлах есть ссылки на другие заголовочные файлы из библиотеки:
  • i2cconf.h — так-то в нем ваще ничо нет :), кроме двух define-ов
  • global.h — в нем определены F_CPU и CYCLES_PER_US + еще 2 заголовочных файла:
  • avrlibdefs.h — часто всеми используемые упрощения clearbit, setbit и тому подобное
  • avrlibtypes.h — здесь переопределены типы, например «typedef unsigned char  u08;» и т.д.
Разумеется, лишнее (а кому и не лишнее) можно убрать — сделать все под себя, под свои принципы и привычки. Пока давайте ничего менять не будем.
Всего нам понадобятся две прошивки — для ведомого устройства ATMEGA16 и для подчиненного ATMEGA8.

Начнем с создания проекта для Master-а (работаю я в AVR Studio). Создаем проект, подключаем i2c.c, i2c.h и все второстепенные файлы (i2cconf.h, …).
В global.h поменяйте F_CPU на свою тактовую, и в файле i2c.c в процедуре void i2cInit(void) закомментируйте лишнее:
sbi(PORTC, 0);	// i2c SCL on ATmega163,323,16,32,etc
sbi(PORTC, 1);	// i2c SDA on ATmega163,323,16,32,etc
//sbi(PORTD, 0);	// i2c SCL on ATmega128,64
//sbi(PORTD, 1);	// i2c SDA on ATmega128,64
Больше ничо менять не нужно, приступим к кодингу главного файла проекта.
/*MASTER*/
......................................................
#define LOCAL_ADDR 0xA0   //адрес мастера ATMEGA16
#define TARGET_ADDR 0x07  //адрес slave-а ATMEGA8
unsigned char buf[100];
int main(void)
{
  _delay_ms(1000); //на момент включения мастера, slave (ATMEGA8) уже должен быть готов к приему данных (далее мы будем тестировать обмен данными в симуляторе Proteus). Поэтому запускаем мастера с секундной задержкой.
  sendStr0("*************TWI MASTER RUNNING*************");
  uart0_init(); // иниц. UART-а для вывода отладочных сообщений
  // initialize i2c function library
  i2cInit();
  // set local device address and allow response to general call
  i2cSetLocalDeviceAddr(LOCAL_ADDR, TRUE);
  //отсылаем строку по шине I2C
  unsigned char mBuf[20];
  sprintf(mBuf,"%s","hello!");
  mBuf[strlen(mBuf)]=0x00;//по привычке сделаем последний символ строки нулевым
  i2cMasterSend(TARGET_ADDR,strlen(mBuf)+1/*(0x00)*/,&mBuf[0]);
  sprintf(buf,"master sended: %s (length %d)",mBuf,strlen(mBuf)+1/*(0x00)*/);
  transmitString(buf);TX_NEWLINE;
  while(1)
  {
    _delay_ms(100);
  }
}
Теперь обязательно нужно рассказать о проблеме, с которой я столкнулся. Не знаю почему, но с включенной оптимизацией данная прошивка у меня неверно работала — успешно передавался только первый байт. Отключение оптимизации всего проекта конечно приводило к желаемому результату — но это не вариант, т.к. размер прошивки увеличивается как минимум в 2 раза, да и сам компилятор предупреждает что при отключенной оптимизации девайс будет работать медленно, и за задержки delay он ответственности не несет. Первое время это было для меня головной болью, но выход я нашел достаточно быстро: нужно отключить оптимизацию не для всего проекта, а только для одного файла — i2c.c. Не знаю, возможно это зависит и от версии WinAVR — попробуйте, может у вас заработает и без отключения оптимизации для i2c.c.
Теперь надо создать еще один проект для подчиненного ATMEGA8, подключить те же самые файлы и так же настроить.
/*SLAVE*/
......................................
#define LOCAL_ADDR 0x07 //адрес slave-а ATMEGA8
#define TARGET_ADDR 0xA0 //адрес мастера ATMEGA16
unsigned char buf[100];
// При завершении приема данных по шине I2C вызывается эта процедура
void i2cSlaveReceiveService(u08 receiveDataLength, u08* receiveData)
{
  sprintf(buf,"slave received: %s (length %d)",receiveData,receiveDataLength);
  transmitString(buf);TX_NEWLINE;
}
int main(void)
{
  sendStr0("*************TWI SLAVE RUNNING*************");
  uart0_init();// иниц. UART-а для вывода отладочных сообщений
  // initialize i2c function library
  i2cInit();
  // set local device address and allow response to general call
  i2cSetLocalDeviceAddr(LOCAL_ADDR, TRUE);
  //Про нее я уже заикнулся - простая и удобная процедура приема данных. По сути прерывание при приеме данных.
  i2cSetSlaveReceiveHandler( i2cSlaveReceiveService );
  while(1)
  {
    _delay_ms(100);
  }
}
Ну вот, обе прошивки готовы. Теперь протестируем все в симуляторе Proteus.
Из компонентов нам понадобятся ATMEGA16, ATMEGA8, resistor, из виртуальных устройств — два терминала и SPI-отладчик (SPI DEBUGGER).
Соединяем линии SCL и SDA контроллеров. На эти линии надо еще повесить резисторы 4.7 кОм на + питания. SPI-отладчик подсоединяем к SCL и SDA соответственно. Подключаем терминалы. Настраиваем частоту контроллеров, битрейт в терминалах. Все, пожалуй.
Демонстрирую результат:

Симуляция обмена в proteus

Архив с проектом  http://www.box.net/shared/nuac0pytxh

UPD1: Если хотите подробно разобраться с I2C и TWI и написать свою библиотеку для этого интерфейса, читайте статью https://nagits.wordpress.com/2010/12/18/avr_i2c_eeprom/.

Реклама

Written by nagits

Октябрь 9, 2010 в 20:21

Опубликовано в AVR, I2C

Tagged with , , ,

комментариев 20

Subscribe to comments with RSS.

  1. спасибо за либу все ок, проблема в массиве [ОСНОВНОМ] там собака порылась, удачи

    glasp

    Январь 12, 2011 at 14:17

  2. проблема в том, что в TWDR Slave данные не хотят залазить, а в остальном …… всё хорошо всё хорошо!

    glasp

    Январь 11, 2011 at 22:45

  3. Доброго здоровья после праздников!
    поясните пожалуйста , если возможно, передачу данных слевом мастеру при запросе мастером SLA+R в Вашем примере. Идея состоит в том, что бы мастер опрашивал N подчинённых выбирая по усмотрению прог-мы данные, обрабатывал их и при получении аварийного отправлял на все подчинённые свои рекомендации. Если имеется готовый проект приблизительно в эту тему буду очень благодарен. Спасибо за Ваше участие.

    glasp

    Январь 11, 2011 at 19:41

    • Взаимно)
      Честно говоря, не совсем понимаю, что надо пояснить). Вашу идею понял, но о5-таки не понимаю в чем проблема. Если вопрос еще актуален, будьте добры, поконкретнее..

      nagits

      Январь 11, 2011 at 20:27

  4. спасибо, я новенький в этом деле, но оч как нужно….Если не сложно выложете пожалуйста кусочек кода что б я мог понять что он както работает и отзывается(совсем остальным думаю уже как то разберусь).Да я поставил резисторный делитель, поидеи все должно быть Ок.(использую мегу 128 повесил контакты на scl- 0 и sda- 1, пишу на AVRcodevision)заранее спасибо

    Mirik

    Январь 11, 2011 at 03:55

  5. да у меня возникли проблемы с программной частью….схему подключил как по даташиту(хотя основная проблема в том что у меня контроллер то 5в а там 3в в акселерометре((( не спалю?) а в программной части не пойму что нужно ему отправить что б он активировался и начал слать данные???

    Mirik

    Январь 9, 2011 at 15:30

    • 1) разумеется, нужно понизить напряжение, хотя бы делитель поставьте..
      2) готовые решения по программной части вы вряд ли найдете. И вряд ли кто-то вам сделает (такие вещи уже обычно за бесплатно не делаются). Самое верное решение — а) разобраться в работе I2C и TWI, а затем б) сделать все самому ручками по даташиту (разделы SINGLE BYTE READ, SINGLE BYTE WRITE)

      nagits

      Январь 9, 2011 at 21:42

      • спасибо, я новенький в этом деле, но оч как нужно….Если не сложно выложете пожалуйста кусочек кода что б я мог понять что он както работает и отзывается(совсем остальным думаю уже как то разберусь).Да я поставил резисторный делитель, поидеи все должно быть Ок.(использую мегу 128 повесил контакты на scl- 0 и sda- 1, пишу на AVRcodevision)заранее спасибо

        Mirik

        Январь 11, 2011 at 03:54

  6. доброго времени суток,уже месяц пытаюсь зделать нечто)))и все без резульатно(((
    вобщем у меня есть мега128 и mma7455 (аксилирометр),необходимо подключить его по i2c (их не один должен быть)но как это зделать? пишу на с codevisionVR…. помогите разобратся, заранее спасибо!

    Mirik

    Январь 9, 2011 at 05:02

    • А в чем конкретно то проблема? Я скачал даташит, там есть схема подключения акселерометра по I2C. Для этого интерфейса на mma задействованы ножки 13 и 14. Подключить таких штук к микроконтроллеру с одним I2C интерфейсом вы сможете только 2 штуки, наскока я понял, если постоянная часть адреса mma7455 на заводе зашивается одна и та же. Для изменения переменной части адреса задействована ножка 4 (почему только одна ? :-(, при том что есть еще на корпусе аж целых 3 n\a), вот отсюда и ограничение в 2 девайса.

      А как вешать на шину I2C несколько ведомых, наверное вам известно — https://nagits.files.wordpress.com/2010/12/121810_1006_avr2.gif?w=614 (из статьи AVR: РАБОТАЕМ С ВНЕШНЕЙ ПАМЯТЬЮ I2C EEPROM типа 24CXX).

      8 и 9 ножки отведены для каких-то прерываний, если их будете подключать, то их понадобится 4 штуки для двух акселерометров

      nagits

      Январь 9, 2011 at 13:34

      • Ну а с программной частью если проблемы, то читайте даташит и какую-нибудь статью, например эту AVR: РАБОТАЕМ С ВНЕШНЕЙ ПАМЯТЬЮ I2C EEPROM типа 24CXX https://nagits.wordpress.com/2010/12/18/avr_i2c_eeprom/ (здесь подробно рассказываю о модуле TWI в AVR для работы с шиной I2C)

        nagits

        Январь 9, 2011 at 13:38

  7. Доброго здоровья!
    Спасибо за статью актуальна.
    Интересует возможность подключения к примеру десяти подчиненных мег

    glasp

    Декабрь 8, 2010 at 22:47

    • Взаимно)
      Если я правильно понял вопрос, то да, вы можете подключить и 100 подчиненных мег — делается по схеме http://t1.gstatic.com/images?q=tbn:ANd9GcQZ2MCZ2gstwUzEB6VcHh-nQeRAZJw-4WkmdCczWBcr8VJqq7vu.

      Я так прикинул, в принципе все ограничивается 255-тью контроллерами — из-за допустимого диапазона адресов 0x00 — 0xFF, но мне кажется это программное ограничение не составит особого труда преодолеть, если вдруг найдется хардкор-мен))

      nagits

      Декабрь 8, 2010 at 23:09

  8. >Если нужны готовые проекты, стучитесь на email – вышлю
    Чо-то много писем стало приходить))) Поленился вначале выложить проект на хостинг, не думал, что заинтересует..
    Короче, выложил архив с проектом по адресу http://www.box.net/shared/nuac0pytxh

    nagits

    Декабрь 1, 2010 at 21:57

  9. )

    DreamS

    Декабрь 1, 2010 at 18:12

  10. Буду очень признателен если замылите мне этот проэкт.
    priymak.i@gmail.com
    Игорь

    заранее благодарен)

    DreamS

    Декабрь 1, 2010 at 17:57

  11. Если нужны готовые проекты, стучитесь на email — вышлю

    nagits

    Октябрь 9, 2010 at 20:30

    • удобнее было бы на какой нибудь кодо-хостинг залить типо github (наглый пиар)

      brunql

      Октябрь 19, 2010 at 15:58

      • Благодарю за совет, но это будет лишним для меня. А вот за идею подсветки синтаксиса отдельное спасибо

        nagits

        Октябрь 19, 2010 at 21:04

    • интересует именно симуляция в протеус-е

      DreamS

      Декабрь 1, 2010 at 18:01


Обсуждение закрыто.

%d такие блоггеры, как: