Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лек 11 - Інтерфейс I2С.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
233.47 Кб
Скачать

Применение

I²c находит применение в устройствах, предусматривающих простоту разработки и низкую себестоимость изготовления при относительно неплохой скорости работы.

Список возможных применений:

  • доступ к модулям памяти NVRAM, к низкоскоростным ЦАП/АЦП;

  • регулировка контрастности, насыщенности и цветового баланса мониторов;

  • регулировка звука в динамиках;

  • управление светодиодами, в том числе в мобильных телефонах;

  • чтение информации с датчиков мониторинга и диагностики оборудования, например, термостат центрального процессора или скорость вращения вентилятора охлаждения;

  • чтение информации с часов реального времени (кварцевых генераторов);

  • управление включением/выключением питания системных компонент;

  • информационный обмен между микроконтроллерами;

Робота з twi на avr

шина I2C глазами микроконтроллера AVR как всегда представляет собой несколько регистров, а именно:

  • TWBR — TWI Bit Rate Register: В этом регистре настраивается частота (скорость) шины, так же на частоту влияет биты TWPS0..1 в регистре TWSR

  • TWCR — TWI Control Register: Через этот регистр происходит все управление шиной

  • TWSR — TWI Status Register: За исключением первых трех бит (TWPS0..1 и зарезервированного) — регистр отражает состояние шины

  • TWDR — TWI Data Register: Как не сложно догадаться — регистр данных. Именно из него данные уходят по шине, и именно в него контроллер помещает полученные байты.

Частота шины рассчитывается по формуле: FSCL = FCPU/(16+2(TWBR)*4TWPS). И это единственное, что нужно сделать при инициализации.

Вся работа TWI сводится к алгоритму:

  1. Записать значение в регистр TWCR (а при передачи данных предварительно поместить байтик в TWDR)

  2. Дождаться флага TWINT в том же регистре TWCR (при работе с прерываниями — этот флаг вызовет прерывание по-вектору TWI)

  3. Получить статус из регистра TWSR — в зависимости от статуса, что-то делать или не делать дальше

.

Биты регистра TWCR имеют следующее назначение: TWEN – бит разрешения работы модуля TWI. При установке бита в состояние 1 выводы SDA, SCL подключаются к внешним выводам микроконтроллера РС1, РСО соответственно для всех ранее названных моделей микроконтроллеров, кроме ATmegaSx (выводы РС4, РС5) и Atmega 64х, 128x(PDl, PDO);

TWSTA – флаг состояния Start. При установке бита в единичное состояние микроконтроллер может сформировать состояние Start, если шина свободна. Если шина занята, модуль ожидает появления состояния Stop и лишь после этого захватывает шину, формируя состояние Start;

TWSTO – флаг состояния Stop. Установка флага в состояние 1 приводит к формированию на шине состояния Stop;

TWEA – бит разрешения подтверждения. При установке бита в 1 устройство формирует сигнал подтверждения, когда это необходимо;

TWIE и TWINT – флаги разрешения и прерывания от модуля TWI. Запрос прерывания генерируется, если TWINT = 1 и TWIE = = 1. Сброс флага TWINT может быть осуществлен только при записи в него логической 1;

TWWC – флаг, устанавливаемый в 1 при попытке записи в регистр данных TWDR, когда флаг прерывания TWINT сброшен.

Биты регистра TWSR:

TWS7…TWS3 – код состояния модуля TWI;

TWPS1:TWPS0 – коэффициент деления предделителя контроллера скорости передачи.

При работе модуля в качестве ведомого скорость обмена зависит от импульсной последовательности, поступающей в микроконтроллер через вывод SCL.

Модуль TWI может работать в следующих режимах:

- ведущий с передачей байтов данных;

- ведущий с приемом байтов данных;

- ведомый с приемом байтов данных;

- ведомый с передачей байтов данных.

Процедура передачи одного байта данных от ведущего к ведомому представляет собой определенную последовательность действий.

1. В регистр ТWCR выводится команда для формирования состояния Start. Для этого необходимо установить в 1 бит TWSTA (TWSTA = 1), сбросить флаг TWINT (TWINT = 1) и установить бит активизации модуля TWI (TWEN = 1). После формирования состояния Start флаг TWINT устанавливается в 1. Для перехода к следующему действию выполняется проверка кода состояния $08 в регистре TWSR. (Ожидание установки флага TWINT можно заменить обработкой запроса прерывания. – Прим. авт.) Программная реализация функции старта представлена далее в программе 5.6 процедурой Send Start.

2. Содержимое пакета с адресом и нулевым значением бита направления записывается в регистр TWDR. Передача инициализируется сбросом флага TWINT. После завершения передачи адреса и получения бита подтверждения флаг TWINT устанавливается в 1, а в регистре TWSR устанавливается код статуса $18. Программная реализация функции записи представлена в программе процедурой SendAdr.

3. После проверки кода статуса в регистр данных TWDR загружается байт данных для передачи и сбрасывается флаг TWINT. По окончании передачи данных и получения бита подтверждения флаг TWINT устанавливается в 1, а в регистре TWSR устанавливается код статуса $28. Эти действия обеспечивают передачу от ведущего устройства ведомому как команд, так и данных. Программная реализация функции вывода данных (а также команд) представлена в программе процедурой Send Сот Data.

4. После успешного завершения передачи выполняются команды для формирования состояния Stop. Программная реализация функции представлена в программе процедурой Stop.

Кратко определим последовательность действий, выполняемых при приеме одного байта данных ведущим устройством:

1) в регистр TWCR выводится команда для формирования состояния Start; после формирования состояния Start флаг TWINT устанавливается в 1. Для перехода к следующему действию выполняется проверка кода состояния ($08) в регистре TWSR. (Ожидание установки флага TWINT также можно заменить обработкой запроса прерывания. – Прим. авт.);

2) содержимое пакета с адресом и единичным значением бита направления записывается в регистр TWDR и инициализируется передача. После завершения передачи адреса и получения бита подтверждения флаг TWINT устанавливается в 1, а в регистре TWSR устанавливается код статуса ($40);

3) после сброса флага TWINT (разрешения приема) и получения байта данных от ведомого данные из регистра TWDR переписываются в один из регистров общего назначения. При успешном приеме код статуса в регистре TWSR принимает значение $50. При необходимости формируется бит подтверждения приема;

4) после завершения приема выполняется команда для формирования состояния Stop.

Последовательность действий, выполняемых при приеме одного байта данных ведомым устройством, можно определить следующим образом:

1) в регистр TWCR выводится команда, сбрасывающая флаг TWINT;

2) после приема первого байта с адресом ведомого устройства формируется запрос прерывания, проверяется код статуса в регистре TWSR; если он равен $60, прием собственного адреса выполнен успешно;

3) передается бит подтверждения путем установки TWEN = 1 и выполняется сброс флага TWINT;

4) проверяется код статуса в регистре TWSR (если он равен $80, значит в регистр TWDR принят байт данных); передается бит подтверждения (TWEN = 1) и выполняется сброс флага TWINT;

Действия 4-го шага повторяются, пока не будет принято все сообщение. При поступлении состояния Stop в регистре TWSR формируется код статуса $А0 (конец пакета).

Подобным образом можно представить действия ведомого устройства при передаче данных. Подробное описание всех вариантов обмена и формируемые при этом значения статусных кодов можно найти в технической документации применяемой модели микроконтроллера.

Вся работа TWI сводится к алгоритму:

  1. Записать значение в регистр TWCR (а при передачи данных предварительно поместить байтик в TWDR)

  2. Дождаться флага TWINT в том же регистре TWCR (при работе с прерываниями — этот флаг вызовет прерывание по-вектору TWI)

  3. Получить статус из регистра TWSR — в зависимости от статуса, что-то делать или не делать дальше.

К этой не хитрой последовательности сводится вся логика работы шины, формирование стартов-рестартов-стопов, передача байта, прием байта и формирование ответа ACK.

Для простоты понимания, что и когда надо записывать в TWCR оформим небольшую функцию:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

#define TWI_START 0

#define TWI_RESTART 1

#define TWI_STOP 2

#define TWI_TRANSMIT 3

#define TWI_RECEIVE_ACK 4

#define TWI_RECEIVE_NACK 5

 

uint8_t twi(uint8_t action){

switch(action){

case TWI_START:

case TWI_RESTART:

TWCR = _BV(TWSTA) | _BV(TWEN) | _BV(TWINT) | _BV(TWIE);

break;

case TWI_STOP:

TWCR = _BV(TWSTO) | _BV(TWEN) | _BV(TWINT) | _BV(TWIE);

break;

case TWI_TRANSMIT:

TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWIE);

break;

case TWI_RECEIVE_ACK:

TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA)| _BV(TWIE);

break;

case TWI_RECEIVE_NACK:

TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWIE);

break;

}

if(action != TWI_STOP)while (!(TWCR & _BV(TWINT)));

return (TWSR & 0xF8);

}

Функция получает требуемое действие в качестве аргумента, дожидается его выполнения и возвращает результат выполнения. Коды возврата довольно непонятно описаны в Datasheet, и очень хорошо у DI HALT’a (ссылка выше по тексту). Данные для передачи необходимо заранее загрузить в регистр TWDR перед выполнением

twi(TW_TRANSMIT)

После успешного получения байта с помощью

twi(TW_RECEIVE_ACK)

или

twi(TW_RECEIVE_NACK)

так же следует напрямую прочитать из TWDR Пример чтения (без всяких проверок и контроля выполнения) 128 байтов из EEPROM 24C01S:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

TWSR &= ~(_BV(TWPS0)|_BV(TWPS1)); // биты предделителя

TWBR=114; //Настраиваем частоту шины

//(при 8MHz F_CPU получаем 8000000/(2*(16+114)) = 32kHz)

uint8_t arr[128];

twi(TWI_START); //формируем сигнал START

TWDR=0xA0; //Загружаем адрес EEPROM+W

twi(TWI_TRANSMIT); //Передаем адрес

TWDR=0x00; //Загружаем адрес байта

twi(TWI_TRANSMIT); //Передаем

twi(TWI_RESTART); //Формируем рестарт (RESTART)

TWDR=0xA1; //Загружаем адрес EEPROM+R

twi(TWI_TRANSMIT); //Передаем

uint8_t i; //Принимаем 127 байт из EEPROM, формируя после каждого ответ ACK

for(i=0;i<127;i++)

{

twi(TWI_RECEIVE_ACK);

arr[i]=TWDR;

}

twi(TWI_RECEIVE_NACK);//Читаем последний байт, формируем NACK - больше данные не нужны

arr[127] = TWDR;

twi(TWI_STOP); //Формируем сигнал STOP

Это простейший и неправильный пример. Неправильного в нем — после каждого выполнения функции twi() необходимо проверять код возврата. После выполнения контроллером любого действия код выполнения записывается в регистр статуса: TWSR, из-за наличия в этом же регистре настроек предделителя необходимо замаскировать первые три бита:

uint8_t result = TWSR & 0b11111000;

или

uint8_t result = TWSR & 0xF8;

Для удобства (или неудобства, как посмотреть), в Datasheet (и соответственно во всех остальных статьях и документах) коды возврата указаны с замаскированными 3 битами. (т.е. можно сравнивать TWSR & 0xF8 со значениями в Datasheet, сдвигать ничего никуда не нужно) Каждое действие может вернуть несколько кода:

START/RESTART:

  • 0×08 — сигнал START передан

  • 0×10 — сигнал REPEATED START передан

Передача адреса (первого байта после START/RESTART):

  • 0×18 — Адрес для записи передан, ответ (ACK) получен

  • 0×20 — Адрес для записи передан, устройство не откликнулось

  • 0×38 — Контроллер потерял шину (вылез еще один контроллер)

  • 0×40 — Адрес для чтения передан, ответ (ACK) получен

  • 0×48 — Адрес для чтения передан, устройство не откликнулось

Передача данных (второго и последующих байтов) возвращает:

  • 0×28 — Байт отправлен, ACK получен

  • 0×30 — Байт отправлен, ACK не получен

  • 0×38 — Потеря шины