В начало | Зарегистрироваться | Заказать наши киты почтой
 
 
 
 

Программная реализация протокола I2C на AVR в CodeVisionAVR

📆27 августа 2016   ✒️Electronik83   🔎21.735   💬10  
Программная реализация протокола I2C на AVR в CodeVisionAVR Пару лет назад, изучая Atmega8, я захотел программно реализовать работу с устройствами на шине i2c, но как-то не задалось. С аппаратным i2c, напротив, не было никаких проблем и затея как-то забылась.

Но недавно я прочитал статью на Датагоре «Несколько функций для програмной реализации протокола I2C на AVR», в которой автор выложил свой пример программной реализации протокола под IAR. Я в тот же миг переписал всё в CodeVision, но, к сожалению, у меня опять не заработало как надо.
Решил набраться терпения и разобраться сам.

Разбираемся с протоколом i2c

Любой протокол можно разобрать по кирпичикам. Так вот, в данном протоколе таким «кирпичиком» является передача/приём одного бита. Схематично передачу одного бита я изобразил на рисунке.


На этом рисунке я изобразил поведение линии SCL при передаче одного бита и длиной в один такт, а также пояснил некоторые понятия. С SCL вроде бы всё ясно, надо разобраться с SDA.
Так вот, при записи бита, надо на линии SDA выставлять значение, в соответствии с содержанием этого бита. Причём делать это лучше всего в середине паузы. Сразу появился вот такой код:
// пишем бит в шину
void i2c_wr_bit(char b) {
delay_us(i2c_time/2); // формируем первую половину паузы
if (b) wrsda; else rdsda;  // пишем бит...    
delay_us(i2c_time/2); // завершаем паузу
rdscl;                // выдаем фронт в линию SCL     
delay_us(i2c_time);   // формируем сам импульс
wrscl;                // выдаем спад в линию SCL
}


Далее рассмотрим чтение бита из шины. Нужно точно также протактировать линию SCL и прочитать значение линии SDA сразу после фронта импульса SCL. Вот код:
// читаем бит из шины
char i2c_rd_bit() {
char ret=1;          // временая переменная
rdsda;               // SDA - на чтение
delay_us(i2c_time);  // формируем паузу между импульсами  
rdscl;               // выдаем фронт SCL    
if (i2c_read) ret=0; // читаем SDA                                 
delay_us(i2c_time);  // формируем фронт
wrscl;               // формируем спад SCL
return ret;          // вернули, что прочитали...
}


Теперь пора рассмотреть все дефайны, которых, как известно, мало не бывает:
#include <mega328p.h>  // нужно для Атмегушки
#include <delay.h>     // нужно для задержек
// задержка в микросекундах (2 задержки на такт передачи)  
#define i2c_time 10 
//i2c порт
#define sdaprt PORTB.0 // порт для SDA         
#define sdaddr DDRB.0  // направлене для SDA 
#define sdapin PINB.0  // для чтения SDA
#define sclprt PORTB.1 // порт для SCL
#define sclddr DDRB.1  // направление для SCL                           
// управление битами шины
#define clrsda sdaprt=0; // переводим в 0 линию SDA
//#define setsda sdaprt=1; // оставил на всякий случай
#define clrscl sclprt=0; // переводим в 0 линию SCL 
//#define setscl sclprt=1; // оставил на всякий случай
#define rdscl  sclddr=0; // переводим SCL линию на вход
#define wrscl  sclddr=1; // переводим SCL линию на выход
#define rdsda  sdaddr=0; // переводим SDA линию на вход
#define wrsda  sdaddr=1; // переводим SDA линию на выход 
#define i2c_read sdapin  // для чтения SDA


Далее нужно научиться передавать байт. Тут ничего сложного:
// передача байта на шину
char i2c_wr(char data)  {
  //Функция возвращает 1, если есть ответ ACK
  char i; // счетчик для цикла. Если объявлять глобально, могут быть глюки
  for (i=0; i<8; i++) {         // выдаем в шину 8 бит
    i2c_wr_bit((data&0x80)==0); // отдаем бит
    data<<=1;  }                // двигаем байт
  // читаем «акнолидж» (подтверждение приёма)
  return i2c_rd_bit();          // вернули, что прочитали  
}


Хотелось бы пояснить, что шина i2c устроена так, что при передаче байта мы должны отправить восемь бит данных и потом прочитать бит — так называемый «акнолидж» (ack). Это такой бит подтверждения, посылаемый устройством на шине, который сигнализирует нам, что устройство благополучно «проглотило» наш байт.
При работе с устройствами этот бит, как правило, говорит устройству о конце/продолжении передачи при чтении нескольких байт из него. Так же иногда этот «акнолидж» надо иногда передавать устройству, особенно при чтении данных с него.

С записью байта понятно, разберемся с чтением. Тут ситуация в точности наоборот — мы сначала читаем восемь бит байта, а потом выдаем этот «акнолидж».
Реализация приема байта:
// прием байта с шины
char i2c_rd(char a)  {
  //если ack=1, то выдается подтверждение ack в шину
  char i, data=0;                // счетчик и принимаемый байт
  for (i=0; i<8; i++) {          // цикл приема бит
    if (!i2c_rd_bit()) data++;   // читаем бит
    if(i!=7) data<<=1;  }        // двигаем байт
  i2c_wr_bit(a);  // выдаем «акнолидж» (подтверждение приема)
  return data;    // вернули, что прочли
}


Теперь пропишем пресловутые функции старт/стоп, как требует протокол:
// старт i2c
void i2c_go(void)  {
  delay_us(i2c_time);  // ждем, пока предидущие сигналы устаканятся
  rdsda; rdscl;        // отпускаем шину
  delay_us(i2c_time);  // формируем паузу:)
  wrsda;  clrsda;      // давим SDA и ставим 0
  delay_us(i2c_time);  // задержка...
  wrscl;  clrscl;      // давим SCL и ставим 0
  delay_us(i2c_time);  // задержка...
}
// стоп i2c
void i2c_end(void)  {
  wrsda;               // давим SDA
  delay_us(i2c_time);  // ждем..
  rdscl;               // давим SCL
  delay_us(i2c_time);  // ждем..
  rdsda;               // отдаем SDA
}


Проверим код с помощью записи/считывания AT24C08

Для проверки я решил использовать Ардуино Nano и микросхему памяти AT24C08. Обратите внимание, аналоги, например чип ST24C08, имеют немного другую распиновку, сверяйтесь с даташитами.
Для контроля работы сначала хотел использовать последовательный порт, но потом решил, что это лишнее и решил обойтись обычным светодиодом, ведь он уже распаян на Ардуинке. Работу с микросхемой AT24C08 расписывать не буду, всё есть в документации к ней.

Идея проверки состоит в том, что мы сначала записываем в микросхему два байта кода, а потом читаем их и сравниваем с оригиналом. Если записанные и считанные байты совпадают, то мы зажигаем светодиод. Это и будет говорить о полной работоспособности протокола.


Теперь код:
// главная функция
void main(void)  {
DDRB.5=1;
delay_ms(100);   // ждем, пока питание устаканится
while (1)  {
char t=0;
delay_ms(100); // ждем немного
PORTB.5=0; // гасим тестовый светодиод
// пишем байт 0xF7 в память микросхемы по адресу 05
i2c_go();
i2c_wr(0xA0);  // i2c адрес микросхемы
i2c_wr(0x05);  // адрес в памяти
i2c_wr(0xF7);  // данные
i2c_end();
// пишем байт 0x3B в память микросхемы по адресу 06
i2c_go();
i2c_wr(0xA0);  // i2c адрес микросхемы
i2c_wr(0x06);  // адрес в памяти
i2c_wr(0x3B);  // данные
i2c_end();
// читаем память..
i2c_go();
i2c_wr(0xA0);  // i2c адрес микросхемы
i2c_wr(0x05);  // адрес для чтения
i2c_go();      // так надо........
i2c_wr(0xA1);  // запуск чтения
if (i2c_rd(1)==0xF7) t++; // принимаем данные с линии
if (i2c_rd(0)==0x3B) t++; // аск передаем 0, т.к. это последний байт для чтения
i2c_end();
// если все данные прочитаны верно
if (t==2) PORTB.5=1;  // включаем тестовый светодиод
}
}


Написанный код я сначала тестирую в Протеусе (ISIS 7 Proteus). Привожу осциллограмму работы:


На осциллограмме видно, что синхросигнал линии SCL получен ровный, данные на линии SDA выставляются верно. Но есть и минус: всплески сигнала на линии SDA. Я долго выяснял, откуда они взялись. Оказалось, что этот всплеск возникает сразу после передачи/приёма бита «акнолидж» (ACK). Устранить этот недостаток мне так и не удалось, оставил, как есть. На работу данный всплеск не должен влиять.
Может на досуге ещё подумаю над этим или кто-нибудь из опытных читателей подскажет в комментариях.

Тестируем протокол в железе

Переходим к тесту в железе. Воткнул в беспаечную макетную плату (breadboard) платку ARDUINO NANO, микросхему AT24C08 и соединил всё проводками. Я для прошивки Ардуинки  использую стандартный Ардуиновский бутлоадер (загрузчик) и программу XLoader, а вы можете использовать привычный вам способ.

При первом запуске у меня пошел дым. Что-то не так! Оказалось, что я перепутал распиновку микросхемы памяти AT24C08. Обидно. В Ардуино у меня сгорел диод по питанию и микросхема памяти вышла из строя. Я заменил и то и другое.

Прошил, включаю: светодиод «молчит». Потыкал тестером и понял, что совершенно забыл про подтягивающие резисторы. Воткнул их. Молчок. Немного подумав и покурив даташит на AT24C08, подал на вывод памяти WP (Write Protect — защита записи, pin 7) не ноль, а единицу.

И, вуаля, всё заработало:


Итого

На фото видно, что тестовый светодиод горит. Это означает, что всё сработало! Наш код можно сохранить и поместить в папку с примерами.

Всем удачи, а меня с почином. Это первая моя статья.
В скором времени планирую написать статью о протоколе SPI.

Камрад, рассмотри датагорские рекомендации

🌼 Полезные и проверенные железяки, можно брать

Опробовано в лаборатории редакции или читателями.




 

Читательское голосование

Нравится

Статью одобрили 38 читателей.

Для участия в голосовании зарегистрируйтесь и войдите на сайт с вашими логином и паролем.
 

Поделись с друзьями!

 

 

Связанные материалы

 

Схема на Датагоре. Новая статья Несколько функций для програмной реализации протокола I2C на AVR... Добрый день, дорогие друзья! Решил поделиться с вами несколькими функция для работы по протоколу...
Схема на Датагоре. Новая статья Программная реализация протокола SPI на AVR в CodeVisionAVR... Всем коллегам и согражданам привет! Увлёкся я изучением протоколов. Про реализацию протокола I2C у...
Схема на Датагоре. Новая статья Немного про шину 1-Wire и цифровой термометр DS18b20... Здравствуйте, друзья. Хочу предложить вашему вниманию несколько простых функций для работы с шиной...
Схема на Датагоре. Новая статья Визуализация для микроконтроллера. Часть 2. TFT дисплей 1.8" (128х160) на ST7735... Следующий из рассматриваемых нами модулей обладает полноцветным дисплеем под управлением...
Схема на Датагоре. Новая статья Визуализация для микроконтроллера. Часть 1. OLED дисплей 0.96" (128х64) на SSD1306... Добрый день, друзья! Эта статья открывает цикл, посвящённый средствам визуального отображения...
Схема на Датагоре. Новая статья Проект DMX512. Микроконтроллер управляет профессиональным шоу. Ч.1... DMX512 (англ. Digital Multiplex) - стандарт, описывающий метод цифровой передачи данных между...
Схема на Датагоре. Новая статья Цифровое телевидение, ч.1... Говорят про это много, но техническую сторону вопроса освещают нечасто. Поскольку работа моя...
Схема на Датагоре. Новая статья Блок управления аудиоусилителем с лестничным регулятором громкости и ДУ... Сделал я усилитель SE на ГУ-50 и как обычно встал вопрос о регуляторе громкости. Ставить обычный...
Схема на Датагоре. Новая статья Цифровой регулятор громкости с опторазвязкой цифровой и аналоговой части... Фото 1. Собранный регулятор Думаю, каждый, кто занимался сборкой усилителя, сталкивался с выбором...
Схема на Датагоре. Новая статья Библиотеки для подключения COG-индикаторов TIC-55 и TIC-3321 к микроконтроллерам AVR... …простите, а вы не подскажите, как пройти в библиотеку? Небольшая предысторияПрежде, я уже имел...
Схема на Датагоре. Новая статья Беспроводной канал связи 2,4 ГГц на базе трансивера nRF24L01+ от Nordic Semiconductor. Часть 1... Доброго вам дня, уважаемые граждане и гости Датагор.ру - этого замечательного сообщества увлечённых...
Схема на Датагоре. Новая статья Генератор v.2.0 с непрерывным режимом для проверки телефонных линий... Учитывая пожелания трудящихся, в том числе монтеров–связистов, в генератор для проверки телефонных...
 

Комментарии, вопросы, ответы, дополнения, отзывы

 

<
Читатель Датагора

Datagor

<
Читатель Датагора

erbol

<
Читатель Датагора

galrad

<
Читатель Датагора

Datagor

<
Читатель Датагора

erbol

<
Читатель Датагора

StalKer-NightMan

<
Читатель Датагора

Electronik83

<
Читатель Датагора

Datagor

<
Читатель Датагора

erbol

<
Читатель Датагора

Александр

Добавить комментарий, вопрос, отзыв 💬

Камрады, будьте дружелюбны, соблюдайте правила!

  • Смайлы и люди
    Животные и природа
    Еда и напитки
    Активность
    Путешествия и места
    Предметы
    Символы
    Флаги
 
 
В начало | Зарегистрироваться | Заказать наши киты почтой