Печать

PCF8574 - расширитель портов ввода/вывода

Автор: AntonChip Опубликовано . Опубликовано в Программирование на Си

Рейтинг:   / 7
ПлохоОтлично 
PCF8574 содержит 8-битный порт ввода-вывода общего назначения, чтение или запись данных осуществляется любым микроконтроллером или другим устройством по шине I2C. Расширитель имеет низкий потребляемый ток и выходы с регистром-защелкой с высокими характеристиками по току для прямой передачи сигнала на светодиоды и т.п. Также в устройстве есть линия прерывания (INT), которая может быть подключена к логике прерывания микроконтроллера. Посылая сигнал прерывания по этой линии, дистанционный ввод - вывод сообщает микроконтроллеру о поступающих на его порты данных, без необходимости поддерживать связь через I2C-шину. Это значит, что PCF8574 может оставаться простым "подчиненным" устройством.

Структурная схема PCF8574

Структурная схема PCF8574

Далее разберемся о программных способах работы с данной микросхемой. Для правильной адресации всех устройств на шине I2C существуют slave-адреса, у PCF8574 они такие:

Есть две разновидности микросхемы PCF8574 — с буквой «А» и без буквы. Отличаются они только четырьмя старшими битами slave-адреса. Таким образом, если на одной шине будет присутствовать 8 микросхем PCF8574 и 8 микросхем PCF8574A, конфликта это не вызовет. Биты А2 - А0 задаются с помощью внешних выводов микросхем.

Запись в порт осуществляется по схеме, представленной на рисунке ниже. «Запись» в данном случае означает, что данные с шины I2C появятся на параллельном порте Р0 - Р7.

Запись данных в PCF8574

Обратите внимание: данные появляются на выходе порта спустя время t после возникновения сигнала АСК (а также записи в порт). Микроконтроллер должен успеть считать предыдущие данные на линиях Р0 - Р7 до появления следующего байта данных.

Запись данных в PCF8574

Чтение с порта происходит по схеме, показанной на рисунке ниже. Напоминаем, что микросхема по-прежнему остается в режиме slave-устройства, то есть сигнал SCL генерируется master-устройством.

Чтение данных из PCF8574

Чтение данных с порта происходит в момент появления сигнала АСК. В промежутках между сигналами АСК данные менять нет смысла, поскольку они будут потеряны. При приеме последнего байта отсылаем условие NACK, таким образом говоря slave-устройству, что отсылать данные уже не надо.

Чтение данных из PCF8574

Практический пример

Далее заставим микроконтроллер Attiny45 управлять LCD дисплеем и одновременно обрабатывать данные от 8-ми кнопочной клавиатуры. На схеме видно что к одной PCF8574 подключен LCD 16x2, к другой подключены 8 кнопок, в то же время расширители между собой и контроллером образуют шину I2C. Обязательно ставим подтягивающие резисторы на линии SCL и SDA. Контроллер Attiny45 работает на частоте 8МГц, делитель на 8 не включаем.

PCF8574 - расширитель портов ввода/вывода

Алгоритм программы такой. В этом примере я использовал библиотеку для работы с программной шиной I2C, ее преимущество в том, что протокол I2C можно организовать на любых выводах любого контроллера. А недостатком такого решения является постоянная загрузка памяти контроллера, а также любое прерывание может прервать обмен информацией по шине. Но можно использовать и аппаратный I2C. В бесконечном цикле постоянно опрашивается клавиатура, т.е. идет чтение IC3, если кнопки не нажаты высвечивается надпись "NO KEY". Если нажата одна из 8-ми кнопок высвечивается "KEY #1" и т.д. Обратите внимание что на расширителях установлены разные slave-адреса.

#include <avr/io.h>
#include <util/delay.h>
#include "I2C.h"
#define RS	(1 << 0)
#define E	(1 << 2)
unsigned char lcd_bufer, ack;
// Функция записи в PCF8574
void PCF8574_Write(unsigned char data)
{
do
{
ack = 0;
i2c_start();              //  Условие старт
i2c_write(0x40);          //  Проверка адреса PCF8574
ack |= i2c_ack();         //  Подтверждение от ведомого 
i2c_write(data);          //  Запись данных в PCF8574
ack |= i2c_ack();         //  Подтверждение от ведомого 
i2c_stop();               //  Условие стоп
}
while(ack);
}
// Функция чтения из PCF8574
unsigned char PCF8574_read(void)
{
unsigned char data;
do
{
ack = 0;
i2c_start();              //  Условие старт
i2c_write(0x43);          //  Проверка адреса PCF8574
ack |= i2c_ack();         //  Подтверждение от ведомого 
data = i2c_read();        //  Чтение данных из PCF8574
i2c_nack();               //  Неподтверждение от ведомого 
i2c_stop();               //  Условие стоп
}
while(ack);
return data;
}
// Функция передачи команды в LCD	
void lcd_com(unsigned char value)
{	
lcd_bufer = value & 0xF0;
lcd_bufer &= ~RS;
    
lcd_bufer |= E;
PCF8574_Write(lcd_bufer);
lcd_bufer &= ~E;
PCF8574_Write(lcd_bufer);
_delay_us(100);
	
lcd_bufer = (value & 0x0F)<<4;
lcd_bufer &= ~RS;
lcd_bufer |= E;
PCF8574_Write(lcd_bufer);
lcd_bufer &= ~E;
PCF8574_Write(lcd_bufer);
if(value & 0b11111100)
_delay_us(100);
else _delay_ms(2);
} 
// Функция передачи данных в LCD
void lcd_data(unsigned char value)
{
lcd_bufer = (value & 0xF0);
lcd_bufer |= RS;
lcd_bufer |= E;
PCF8574_Write(lcd_bufer);
lcd_bufer &= ~E;
PCF8574_Write(lcd_bufer);
_delay_us(100);
	
lcd_bufer = (value & 0x0F)<<4;
lcd_bufer |= RS;
lcd_bufer |= E;
PCF8574_Write(lcd_bufer);
lcd_bufer &= ~E;
PCF8574_Write(lcd_bufer);
_delay_ms(2);
}
// Функция вывода строки на LCD
void lcd_string(unsigned char *data, unsigned char nBytes)
{
if(!data) return;
for(unsigned char i = 0; i < nBytes; i++)
{
lcd_data(data[i]);
}
}
// Функция инициализации LCD
void lcd_init(void)
{
PCF8574_Write(0b00000000);
_delay_ms(40);
lcd_bufer = 0b00110000;
PCF8574_Write(lcd_bufer);
lcd_bufer |= E;
PCF8574_Write(lcd_bufer);
lcd_bufer &= ~E;
PCF8574_Write(lcd_bufer);
_delay_ms(5);
lcd_bufer |= E;
PCF8574_Write(lcd_bufer);
lcd_bufer &= ~E;
PCF8574_Write(lcd_bufer);
_delay_us(100);
lcd_bufer |= E;
PCF8574_Write(lcd_bufer);
lcd_bufer &= ~E;
PCF8574_Write(lcd_bufer);
_delay_us(100);
lcd_bufer = 0b00100000;
PCF8574_Write(lcd_bufer);
lcd_bufer |= E;
PCF8574_Write(lcd_bufer);
lcd_bufer &= ~E;
PCF8574_Write(lcd_bufer);
_delay_us(100);
lcd_com(0x28); // шина 4 бит, LCD - 2 строки
lcd_com(0x08); // полное выключение дисплея
lcd_com(0x01); // очистка дисплея
_delay_us(100);
lcd_com(0x06); // сдвиг курсора вправо
lcd_com(0x0C); // включение дисплея, курсор не видим
}
int main(void)
{
DDRB |= (1 << PB1)|(1 << PB0); //  SDA, SCL
PORTB |= (1 << PB1)|(1 << PB0); //  Подключаем подтягивающие резисторы
lcd_init();
char key;
while(1)
{
  key = PCF8574_read(); // Считываем код нажатой кнопки
  if(key == 0b11111110) // Если нажата кнопка №1
  {
  lcd_com(0x80);
  lcd_string("KEY #1", 6); // Выводим номер кнопки на LCD 
  }
  else if(key == 0b11111101)
  {
  lcd_com(0x80);
  lcd_string("KEY #2", 6);
  }
  else if(key == 0b11111011)
  {
  lcd_com(0x80);
  lcd_string("KEY #3", 6);
  }
  else if(key == 0b11110111)
  {
  lcd_com(0x80);
  lcd_string("KEY #4", 6);
  }
  else if(key == 0b11101111)
  {
  lcd_com(0x80);
  lcd_string("KEY #5", 6);
  }
  else if(key == 0b11011111)
  {
  lcd_com(0x80);
  lcd_string("KEY #6", 6);
  }
  else if(key == 0b10111111)
  {
  lcd_com(0x80);
  lcd_string("KEY #7", 6);
  }
  else if(key == 0b01111111)
  {
  lcd_com(0x80);
  lcd_string("KEY #8", 6);
  }
  else
  {
  lcd_com(0x80);
  lcd_string("KEY NO", 6);
  }
}
}

Файлы:
Проект AVRStudio4 и Proteus
Дата 11.01.2015 Размер файла 58.05 KB Закачек 894

Комментарии  

0 #1 80N60 30.01.2015 03:54
Здравствуйте!
А не подскажете, lcd_gotoxy() - как в Вашем примере задается?
Спасибо!
Сообщить модератору
0 #2 AntonChip 30.01.2015 10:24
Цитирую 80N60:
Здравствуйте!
А не подскажете, lcd_gotoxy() - как в Вашем примере задается?
Спасибо!

Командой lcd_com(0x80);
в данном случае символ выводится в первое знакоместо первой строки
Сообщить модератору
0 #3 80N60 03.02.2015 21:37
А не подскажете как определить другие знакоместа?
Спасибо!
Сообщить модератору
0 #4 AntonChip 03.02.2015 22:31
Цитирую 80N60:
А не подскажете как определить другие знакоместа?
Спасибо!

Сообщить модератору
0 #5 Alexfire 22.02.2015 20:23
Здравствуйте. Возникла ошибка при компиляции в AS6.2 "undefined reference" в функциях записи и чтения. например такая: undefined reference to `i2c_start'. Подскажите, где копать?
Сообщить модератору
0 #6 Alexfire 22.02.2015 22:44
А ларчик просто открывался! Импорт из AVR Studio 4.....
Сообщить модератору

Рекомендуем посмотреть