Я уже писал ранее про то, как можно подключить ЖК-дисплей на контроллере hd44780 к launchpad, в том варианте использовалось довольно много выходов микроконтроллера, что при ограниченном числе ножек в варианте DIP-исполнения усложняет программу, если необходимо на одни и те же выводы «повесить» различные функции.



Решение лежит близко к поверхности, вариант 1 — это использование сдвигового регистра 74hc595, вариант 2 — использование специального «расширителя портов» pcf8574, на деле являющимся контроллером ввода/вывода, управляемого по шине I2C. Чтобы «поиграться», был куплен вот такой вариант готово платы с pcf8574:

«Чумазая» от флюса плата, была промыта и покрыта лаком «plastic»:

Поиск в интернетах рабочего примера привёл на сайт 43oh.com, где готовый модуль на pcf8574 использовался для подключения индикатора на hd44780, однако только ни один из найденных вариантов не работал. Следствие показало, что во всех вариантах распайка модуля отличалась от моего, соответственно после «прозвонки» контактов выявилась такая картина подключения дисплея к «расширителю» pcf8574:

LCD D4 -> P4
LCD D5 -> P5
LCD D6 -> P6
LCD D7 -> P7
LCD RS -> P0
LCD RW -> P1
LCD EN  -> P2

На выводе P3 контроллера pcf8574 -управление подсветкой дисплея, как следствие — существует возможность программно управлять подсветкой.

Вид платы с обратной стороны:

Адресация контроллера pcf8574. На плате установлен контроллер без индекса «А», согласно даташиту ее базовый адрес 0х40, у контроллера pcf8574 I2C-адрес определяется логическими уровнями на выводах A0-A1. По умолчанию, если не запаивать перемычки на плате, то на всех этих выводах присутствует логическая единица. Это означает, что контроллер pcf8574 имеет вот такой адрес:  0b01001110 = 0x4E.

Реализация отправки данных по I2C отличается от приведённой в примерах для контроллера, и полностью копирует код с сайт 43oh.com (будем использовать второй контроллер из комплекта launchpad, — msp430g2452 и его встроенный последовательный интерфейс USI):

#include "i2c.h"

#define SDA     BIT7 //P1.7
#define SCL     BIT6 //P1.6
#define LED     BIT0 //P1.0

void i2c_init(void){
P1DIR |= SCL | SDA | LED; // Set SCL, SDA and LED as Output
P1REN |= SCL | SDA; // Set Pull-Ups on SCL and SDA

// enable SDA, SCL, SCLK, i2c mode, MSB, output enabled, hold in reset
USICTL0 = USIPE7 | USIPE6 | USIMST | USIOE | USISWRST;

// USICTL0 Upper 8bit Register of 16bit USICTL Register
// USIPE7   = P1.7 USI Mode, i2c SDA enabled
// USIPE6   = P1.6 USI Mode, i2c SCL enabled
// USIPE5   = P1.5 USI Mode, i2c Clock Input? (Not Set)
// USILSB   = LSB Mode (Not Set = MSB)
// USIMST   = Master Mode
// USIGE    = Output Latch (Not Set = Clock Controlled)
// USIOE    = Data Output Enable
// USISWRST = USI Software Reset (Set to allow changing settings)

// SMCLK / 128, and Reverse Clock Polarity
USICKCTL = USIDIV_7 + USISSEL_2 + USICKPL;

// USICKCTL 8bit USI Clock Control Register
// USIDIVx  = Clock Divider (Bit7-5, USIDIV_7 = Divide by 128)
// USISSELx = Clock Source (For Master Mode, Bit4-2, USISSEL_2 = SMCLK)
// USICKPL  = Clock Polarity (0 = Inactive Low, 1 = Inactive High)
// USISWCLK = Software Clock State
// I2C Mode
USICTL1 = USII2C;
// USICTL1 Lower 8bit Register of 16bit USICTL Register
// USICKPH   = Clock Phase (0 = Data Changed, then Captured, 1 = Data Captured, then Changed)
// USII2C    = I2C mode
// USISTTIE  = START condition Interrupt
// USIIE     = USI Counter Interrupt
// USIAL     = Arbitration Lost Notification
// USISTP    = STOP condition Notification
// USISTTIFG = START condition Int. Flag
// USIIFG    = USI Counter Int. Flag
// release from reset
USICTL0 &= ~USISWRST;
}

void i2c_start(void) {
// Send i2c START condition
USISRL = 0x00; // Load USISRL Lower Byte Shift Register MSB with 0 for i2c START
USICTL0 |= USIGE | USIOE; // Force Output Latch, And Enable Data Output Bit (High to Low SDA while SCL is High)
USICTL0 &= ~USIGE; // Clear Output Latch (Return to Clock Control)
}

void i2c_stop(void){
// Prepare i2c STOP condition
USICTL0 |= USIOE; // Enable Data Output Bit (Turn SDA into Output)
USISRL = 0x00; // Load USISRL Lower Byte Shift Register MSB with 0 for i2c STOP
USICNT = 1; // Load USICNT Counter with number of Bits to Send. USIIFG Auto-Cleared
// Data TXed by USI I2C
while((USICTL1 & USIIFG) != 0x01); // Delay, Wait for USIIFG, Counter down to 0
// Send i2c STOP condition
USISRL = 0xFF; // Load USISRL Lower Byte Shift Register MSB with 1 for i2c STOP
USICTL0 |= USIGE; // Force Output Latch (Low to High SDA while SCL is High)
USICTL0 &= ~USIOE & ~USIGE ; // Clear Data Output Enable Bit and Output Latch (Release SCL)
}

uint8_t i2c_write8(uint8_t c) {
// TX
USICTL0 |= USIOE; // Enable Data Output Bit (Turn SDA into Output)
USISRL = c; // Load USISRL Lower Byte Shift Register with 8 Bit data (Byte)
USICNT = 8; // Load USICNT Counter with number of Bits to Send. USIIFG Auto-Cleared
// Data TXed by USI I2C
while((USICTL1 & USIIFG) != 0x01); // Delay, Wait for USIIFG, Counter down to 0
// RX
// Data TXed. Ready to Receive (n)ACK from i2c Slave
USICTL0 &= ~USIOE; // Clear Data Output Enable Bit (Turn SDA into Input)
USICNT = 1; // Load USICNT Counter with number of Bits to Receive. USIIFG Auto-Cleared
// Data RXed by USI I2C
while((USICTL1 & USIIFG) != 0x01); // Delay, Wait for USIIFG, Counter down to 0
c = USISRL; // LSB of USISRL Holds Ack Status of 0 = ACK (0x00) or 1 = NACK (0x01)
return c; // Return Data
}

Инициализацией дисплея — обычная, из примера работы с hd44780:

void lcd_init() {
EXPANDER_OUTPUT = 0x00;   // Clear Port Expander to 0x00
i2c_start();
expander_write(EXPANDER_ADDRESS); // Alert Expander
EXPANDER_OUTPUT &= ~RS; //Set RS low for Command
// Pause for the powering of the LCD
pause(0);
pause(0);
pause(0);
pause(0);
// Init Bytes
send_nibble(0x30);
send_nibble(0x30);
send_nibble(0x30);
// Function Set (4Bit Mode, 2 Lines, 5x10 Characters)
send_nibble(0x20);
send_nibble(0x20);
send_nibble(0xF0);
// Display On
send_nibble(0x00);
send_nibble(0xF0);
// Display Clear
send_nibble(0x00);
send_nibble(0x10);
// Entry Mode
send_nibble(0x00);
send_nibble(0x60);
i2c_stop();
}

бутерброд:



Остальное — дело техники, реализован необходимый минимум методов, время испытать библиотеку в железе!

Работает!

Загрузить текущую версию библиотеки pcf8574t, проект в CCS 5.4.