Следующим экспериментом в серии выступает применение протокола передачи I2C. Здесь нет описания самого протокола, этого добра в сети хватает 🙂 в статье содержится инструкция по установке связи между микроконтроллером PIC16f628a и так называемым “расширителем” портов мк PCA9539.
Итак:
Задача: Установка связи по протоколу I2C.
Исходный материал: PIC16f628a, PCA9539, devboard.
Вкратце о том, зачем это мне: у меня сейчас на стадии разработки проект часы/термометр, и я выбирал средство индикации для него. Остановился на двух дисплеях: трехразрядный семисегментник и четырехразрядный семисегментник. Для управления ими нужно 8+4+8+3 = 23 бита с нашими 16 портами это нереально. Сначала я думал использовать для этого сдвиговый регистр, но потом мне прилетели халявные образцы от NXP и я решил заюзать их. В данном случае будет использоваться 7+2 = 9 портов, причем 2 порта для шины I2C будут использоваться и для связи с термометром и часами реального времени.
Для начала посмотрим внутрь нашего io expander’a:
Помимо 16 портов здесь присутствует два бита ручного указания адреса, а также вывод прерываний. Фактически, адрес конкретно устройства здесь формируется только двумя битами А0 и А1:
В моем случае я эти биты подтянул на землю, то есть адрес устройства выглядит так:
То есть начало передачи для нашей индикации должно начинаться с такого байта.
Далее должен следовать командный байт, который указывает куда именно собираемся записывать информацию (конфигурационный бит, непосредственно порты и т.д.).
*Цифры ниже приведены в десятичной системе
0 | Входной порт 0 |
1 | Входной порт 1 |
2 | Выходной порт 0 |
3 | Выходной порт 1 |
4 | Инверсия полярности порта 0 |
5 | Инверсия полярности порта 1 |
6 | Конфигурационный порт 1 |
7 | Конфигурационный порт 2 |
При работе с данной микросхемой нужно помнить, что регистры всегда работают в паре, то есть если вы пишите в порт 0 данные, то придется их записывать и порт 1, командный бит по сути просто указывает на то, в какой из портов данные будут записываться сначала.
После командного байта записываются два нужных нам байта. В общем случае запись в выходные порты выглядит примерно так:
Остановимся пока на только на записи в микросхему, с чтением будем разбираться чуть позже. Переходим непосредственно к коду. Здесь главная фишка в том, что мы оперируем не непосредственно состояниями выходов порта, а лишь изменением направления данного порта (ввод/вывод). Поэтому не забываем вначале нашей программы добавлять следующие строки:
#define SCL TRISB6 #define SDA TRISB5 #define SCL_IN RB6 #define SDA_IN RB5
Задержка для тактирования:
void i2c_delay (void) { __delay_us(10); }
Далее процедура старта:
void i2c_start(void) // { SCL = 1; SDA = 1; i2c_delay(); SDA = 0; i2c_delay(); SCL = 0; }
Процедура окончания:
void i2c_stop (void) { SDA = 0; i2c_delay(); SCL = 1; i2c_delay(); SDA = 1; i2c_delay(); }
Процедура записи выглядит так:
bit i2c_tx(unsigned char d) { char x; static bit b; for (x=0; x<8; x++) { //передача 8 бит данных i2c_delay(); if (d&0x80) SDA = 1; else SDA = 0; i2c_delay(); SCL = 1; d <<= 1; i2c_delay(); SCL = 0; } i2c_delay(); i2c_delay(); SDA = 1; //готовимся получить ACK бит SCL = 1; i2c_delay(); b = SDA_IN; //получаем ACK бит SCL = 0; return b; //Возвращаем значение бита ACK через функцию }
Итак, для записи в микросхему у нас есть все что нужно. В качестве примера будем выводить двухзначное число на дисплей, которое будет увеличиваться на единицу по нажатию на кнопку. Для вывода на дисплей создадим отдельную функцию:
void dispo(unsigned char temp) { unsigned char i = 0; i = trunc(temp/10); maj= 0; min =0; i2c_start(); i2c_tx(0b11101000); i2c_tx(0b00000010); i2c_tx(digit[i]); i2c_tx(digit[i]); i2c_stop(); maj= 1; min = 0; __delay_ms(5); i = temp - (trunc(temp/10)*10); maj= 0; min = 0; i2c_start(); i2c_tx(0b11101000); i2c_tx(0b00000010); i2c_tx(digit[i]); i2c_tx(digit[i]); i2c_stop(); maj= 0; min = 1; __delay_ms(5); }
Надо также помнить, что перед записью в порты их нужно сконфигурировать на выход, записав нули в конфигурационные биты. Нажатие на кнопку обрабатывается прерыванием. Результат работы:
Чтение будет рассмотрено в другой статье и из другого девайса (как только он прилетит из китая).
Исходники здесь.
Уведомление: PIC мк. Эксперимент №17. Часы-термометр. « PIC микроконтроллеры
…………перед записью в порты их нужно сконфигурировать на выход……..
i2c_start();
i2c_tx(0b11101000); //Address
i2c_tx(0b00000110); //command 00000110=6 ->Конфигурационный порт 1
i2c_tx(0b00000000);
i2c_tx(0b00000000);
i2c_stop();
Незаб(и)вать!
Да, я об этом написал, но не приводил просто в коде, спасибо за замечание 🙂
Да, еще забыл добавить, позднее я понял что использование функции trunc() здесь избыточно, как и использование математической либы и + на видео версия софта без защиты от дребезга
А если в ответ на адрес приходит NACK, то это траблы в коде или же в аппаратной части?
Оба варианта могут быть верны.
1. В случае неправильного указания адреса, естественно ничего не придет (проверяйте анализатором)
2. Косяк соединения, тут вы хоть в воздух две шины подключите nack будет постоянно 🙂
Косяков в соединении не обнаружил. Прогнал в режиме дебагера, выяснилось, что со стороны слейва линию никто прижимать не собирается. Дошел до чтения, и там у меня насобирались одни лишь единички. Может ли это быть из-за задержек, у меня задержки тоже на 10 мкс(частота камня 20 МГц). Резюки на 10 к. Неужели микруха приказала долго жить?
Если есть другая микросхема, можно попробовать на ней какую-нибудь простую команду.
Ну или же код в протеус и посмотреть работает ли там все адекватно.
PS. С адресом то все в порядке? Может не тот адрес указываете вот она и не реагирует.
У микрухи DS1621 адрес начинается 1001, и еще три адресных входа, которые настраиваешь сам, ну я их и повесил на землю, то есть адрес 1001000(R/W). Если слать на запись, то выглядит i2c_tx(0x90). В протеусе все отлично работает, без вопросов.
Ну тогда самый быстрый способ проверки точно другую микросхему подключить, если тоже не работает – еще раз проверять схему ее подключения, может в разводке косяк есть.
Ну тогда завтра так и сделаю, спасибо за помощь.
Да не за что.
Уведомление: Pic Lab, PIC16, Experiment #13, Software I2C | diymicro.org