AVR Урок 16. Интерфейс TWI (I2C). Часть 3

 

 

 

 

Урок 16

Часть 3

 

Интерфейс TWI (I2C)

 

 

В предыдущей части занятия мы продолжили знакомство с шиной I2C и уже создали проект для того, чтобы занятия проработать на практике. Также мы познакомились с интересой микросхемой EEPROM AT24C32, работающей на данной шине.

Продолжаем изучение шины.

Шину мы инициализировали в проекте, выставив ей скрость с помощью регистра TWBR, теперь давайте поближе познакомимся с управляющим регистром — TWCR

 

image09

 

Как мы видим, в данном регистре присутствует насколько битов.

 

TWINT — это бит прерываний. Можно его назвать битом не управляющим, а статусным, так как устанавливается он аппаратно в тот момент, когда определённое задание на шине завершится и будет ожидаться реакция программы. А вот сбрасывается данный флаг не аппаратно, а только программно — записью в него логической 1.

TWEA — бит или флаг, разрешающий подтверждение. Если мы его не установим, то мы не будем просить подтверждение от ведомого устройства, а в случае, если контроллер наоборот является ведомым устройством, то с очередной посылкой мы не отправим бит подтверждения в конце какой-то посылки.

TWSTA — бит установки или генерирования условия "Старт".

TWSTO — бит установки или генерирования условия "Стоп".

TWWC — бит ошибочной записи. Устанавливается при попытки записи в адресный буфер, когда флаг TWINT ещё не установился. Ещё называется он флагом коллизий. Данный бит сбросится, когда TWINT будет равен 1.

TWEN — бит, активирующий шину I2C. Если мы его устанавливаем, то шина I2C начинает пытаться выполнять задание в зависимости от условий.

TWIE — бит, который разрешает прерывания.

 

Теперь статусный регистр TWSR

 

image10

 

Пять старших битов регистра содержат код статуса операции, которая выполнялась перед тем, как мы читаем регистр. Как правило мы с помощью маскирования сбрасываем три младших бита в 0, ну конечно не в самом регистре, а в переменной, в которую мы его считали и затем уже исследуем полученный результат. В даташите на контроллер содержится перечень в виде нескольких таблиц различных кодов статуса. Несколько их потому, что есть несколько условий — ведущее или ведомое устройство и чтение или запись происходила.

Ну а два младших бита — TWPS1 и TWPS0 — это биты для делителя частоты шины, с которыми мы уже знакомились немного в 1 части занятия.

Вот такие вот могут быть варианты комбинаций данных битов и зависимость делителя от этих комбинаций

 

image11

 

Займёмся теперь непосредственно шиной.

Как же всё работает:

 

image12

 

Нам для начала любой посылки необходимо сгенерировать условие СТАРТ, чтобы ведущие устройства "проснулись" и начали приём, а потом уже "думали", не их ли адрес к ним пришёл. Условие СТАРТ генерируется путём перехода из высокого логического состояния шины SDA в низкое (отрицательного фронта), а затем черз некоторое время должно то же самое произойти и с шиной SCL. Вот тогда ведущий и поймёт, что по шине началась какая-то передача. А если контроллер у нас ведомый, то мы наоборот должны отследить данный процесс на наших проводах.

Но у нас шина аппаратная и париться на этот счёт нам не нужно, ибо всё контроллер сделает сам.

Соответственно, как мы видим из графика наверху, условие СТОП генерируется наоборот. Сначала положительный фронт на шине SCL, а затем на SDA.

 

 

В случае, если контроллер у нас ведомый, то мы, для того, чтобы сгенерировать условие СТАРТ, должны сделать следующее.

Вот таким вот образом у меня подключен модуль с микросхемой

 

image13

 

Вернёмся в проект и напишем для генерации условия СТАРТ отдельную функцию в файле twi.c

 

void I2C_StartCondition(void)

{

  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);

  while(!(TWCR&(1<<TWINT)));//подождем пока установится TWIN

}

 

Вот такая вот интересная функция. Что же здесь происходит?

А происходит следующее.

Мы сначала устанавливаем определённые биты в регистре управленя, говоря при этом шине о том, что мы посылаем условие СТАРТ (TWSTA), а также запускаем шину (TWEN). Ну а бит TWINT мы соответственно устанавливаем в единицу. А в ноль он, соответственно установится тогда, когда данное задание закончится. Вот для этого и существует вторая строка, где мы висим в цикле, пока он, собственно, и не установится. Именно в ноль! А не в единицу. Об этом говорит восклицательный знак в условии.

Давайте сразу и воспользуемся данной функцией, соответственно сначала создав на неё прототип, а затем вызвав в функции main(). Сначала мы, конечно, будем во внешнюю память EEPROM писать, так как читать из неё ещё нечего. Поэтому начнём в main() писать следующий код

 

I2C_Init();

 

//Чтение

I2C_StartCondition(); //Отправим условие START

 

Ну и, раз уж у нас есть чем, то давайте считаем статус операции и посмотрим успешно ли всё у нас прошло.

Для этого мы просто отправим значение статусного регистра в шину USART. Младшие три бита мы маскировать не будем, они у нас и так все в нулях.

 

I2C_StartCondition(); //Отправим условие START

USART_Transmit(TWSR);//читаем статусный регистр

 

Запустим терминальную программу, нажмем там Connect, соберём код и прошьём контроллер.

И вот мы что там видим

 

image15

 

Посмотрим в таблице данный статус

 

image16

 

То есть условие СТАРТ у нас сгенерировано и отправлено.

Остальные эксперементы с шиной I2C мы будем проделывать в следующей части.

 

Предыдущая часть Программирование МК AVR Следующая часть

 

Техническая документация на микросхему AT24C32

 

Программатор и модуль RTC DS1307 с микросхемой памяти можно приобрести здесь:

Программатор (продавец надёжный) USBASP USBISP 2.0

Модуль RTC DS1307 с микросхемой памяти

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

AVR Интерфейс TWI (I2C)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*