Доброго сем времени суток!
Решил разобраться с подключением ЖК дисплея (winstar 1602) с расширителем портов PCF8574 к микроконтроллеру ATmega8.
Собрал вот такую схему в протеусе. Один диспей подключен напрямую к ножкам контроллера (я на него выводил значение регистра статуса модуля TWI). Второй дисплей подключен через PCF8574.
Спойлер

Написал вот такой код в AtmelStudio
Спойлер
Код:
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
//пользовательские определения
#define RS_1 PORTD |= (1<<2); //передача данных
#define RS_0 PORTD &= ~(1<<2); //передача команд
#define E_1 PORTD |= (1<<3); //установка высокого потенциала на разрешающем пине Е
#define E_0 PORTD &= ~(1<<3); //установка низкого потенциала на разрешающем пине Е
//переменные
unsigned char TWI_Status = 0;
//прототипы функций
void LCD_pin_setup(void); //функция настройки пинов подлючения ЖК дисплея
void LCD_commands(unsigned char command); //функция передачи команд
void LCD_data(unsigned char data); //функция передачи данных
void LCD_settings(void); //функция настройки ЖК дисплея
void set_cursor(unsigned char y, unsigned char x); //функция установки курсора в строке и на заданной позиции этой строки
void print_string(char words[]); //функция вывода строк на дисплей
//прототипы функций для ЖК дисплея с модулем TWI
void TWI_Settings(void); //функция настроек модуля TWI
void TWI_Start(void); //функция формирования условия "Старт" для модуля TWI
void TWI_Stop(void); //функция формирования условия "Стоп" для модуля TWI
void TWI_Write_byte(unsigned char data); //функция передачи байта по шине TWI
void LCD_TWI_command(unsigned char data); //функция передачи команд ЖК дисплею по интерфейсу TWI
void LCD_TWI_data(unsigned char data); //функция передачи данных ЖК дисплею по интерфейсу TWI
void LCD_TWI_settings(void); //функция настройки ЖК дисплея подключенного к микроконтроллеру по TWI (I2C) модулю
int main(void)
{
LCD_pin_setup();
LCD_settings();
TWI_Settings();
TWI_Start(); //отправка условия Старт
TWI_Write_byte(0b01001110); //отправка адреса микросхемы PCF + бит записи
LCD_TWI_settings();
TWI_Stop();
TWI_Start(); //отправка условия Старт
TWI_Write_byte(0b01001110); //отправка адреса микросхемы PCF + бит записи
LCD_TWI_data('A');
LCD_TWI_data('B');
LCD_TWI_data('C');
TWI_Stop();
TWI_Status = TWSR; //значение регистра статуса модуля TWI
set_cursor(1,0); //установка курсора в позицию
print_string("TWI status - "); //печать строки
char str[16];
itoa(TWI_Status, str, 16); //преобразование значения переменной статуса TWI в символьный массив
print_string(str); //печать значения переменной статуса TWI
set_cursor(2,0); //установка курсора в позицию
LCD_data('A');
LCD_data('B');
LCD_data('C');
while (1)
{
}
}
//============== функции для ЖК дисплея подключенного к микроконтроллеру через модуль TWI (I2C)
void TWI_Settings(void) //функция настроек модуля TWI
{
TWBR = 2;
TWSR &= ~((1<<TWPS1) | (1<<TWPS0));
}
void TWI_Start(void) //функция формирования условия "Старт" для модуля TWI
{
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
while(!(TWCR & (1<<TWINT)))
;
}
void TWI_Stop(void) //функция формирования условия "Стоп" для модуля TWI
{
TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
}
void TWI_Write_byte(unsigned char data) //функция записи байта по шине TWI
{
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);
while(!(TWCR & (1<<TWINT)))
;
}
void LCD_TWI_command(unsigned char data) //функция передачи команд ЖК дисплею по интерфейсу TWI
{
unsigned char val;
val = (data | (1<<3) | (1<<2)) & ~(1<<0); //установка 3-го бита, включение подсветки дисплея
TWI_Write_byte(val);
_delay_us(50);
val &= ~(1<<2);
TWI_Write_byte(val);
_delay_us(50);
val = ((data << 4) | (1<<3) | (1<<2)) & ~(1<<0); //установка 3-го бита, включение подсветки дисплея
TWI_Write_byte(val);
_delay_us(50);
val &= ~(1<<2);
TWI_Write_byte(val);
_delay_us(50);
}
void LCD_TWI_data(unsigned char data) //функция передачи данных ЖК дисплею по интерфейсу TWI
{
unsigned char val;
val = data | (1<<3) | (1<<2) | (1<<0); //установка 3-го бита, включение подсветки дисплея
TWI_Write_byte(val);
_delay_us(50);
val &= ~(1<<2);
TWI_Write_byte(val);
_delay_us(50);
val = (data << 4) | (1<<3) | (1<<2) | (1<<0); //установка 3-го бита, включение подсветки дисплея
TWI_Write_byte(val);
_delay_us(50);
val &= ~(1<<2);
TWI_Write_byte(val);
_delay_us(50);
}
void LCD_TWI_settings(void) //функция настройки ЖК дисплея подключенного к микроконтроллеру по TWI (I2C) модулю
{
_delay_ms(15);
LCD_TWI_command(0b00110000);
_delay_ms(5);
LCD_TWI_command(0b00110000);
_delay_us(110);
LCD_TWI_command(0b00110000);
_delay_ms(1);
LCD_TWI_command(0b00000010);
_delay_ms(2);
LCD_TWI_command(0b00101000); //четырех битный интерфейс, дисплей двух строчный, размер шрифта 5*8
_delay_ms(1);
LCD_TWI_command(0b00001101); //включение дисплея, выключение курсора, курсор моргает (младший бит - 1 моргает, 0 не мограет)
_delay_ms(1);
LCD_TWI_command(0b00000001); //очистка дисплея
_delay_ms(2);
LCD_TWI_command(0b00000110); //инкрементирование и сдвиг курсора в право
_delay_ms(1);
}
//============== функции для ЖК дисплея подключенного напрямую к микроконтроллеру =================
void LCD_pin_setup(void) //функция настройки пинов подлючения ЖК дисплея
{
DDRD |= (1<<7) | (1<<6) | (1<<5) | (1<<4) | (1<<3) | (1<<2);
PORTD &= ~((1<<7) | (1<<6) | (1<<5) | (1<<4) | (1<<3) | (1<<2));
}
void LCD_commands(unsigned char command) //функция передачи команд
{
PORTD = command;
RS_0; //низкий потенциал на выводе RS
E_1; //высокий потенциал на выводе Е
_delay_us(50);
E_0; //низкий потенциал на выводе Е
_delay_us(50);
PORTD = (command << 4);
RS_0; //низкий потенциал на выводе RS
E_1; //высокий потенциал на выводе Е
_delay_us(50);
E_0; //низкий потенциал на выводе Е
_delay_us(50);
}
void LCD_data(unsigned char data) //функция передачи данных
{
PORTD = data;
RS_1; //высокий потенциал на выводе RS
E_1; //высокий потенциал на выводе Е
_delay_us(50);
E_0; //низкий потенциал на выводе Е
_delay_us(50);
PORTD = (data << 4);
RS_1; //высокий потенциал на выводе RS
E_1; //высокий потенциал на выводе Е
_delay_us(50);
E_0; //низкий потенциал на выводе Е
_delay_us(50);
}
void LCD_settings(void) //функция настройки ЖК дисплея
{
_delay_ms(15);
LCD_commands(0b00110000);
_delay_ms(5);
LCD_commands(0b00110000);
_delay_us(110);
LCD_commands(0b00110000);
_delay_ms(1);
LCD_commands(0b00000010);
_delay_ms(2);
LCD_commands(0b00101000); //четырех битный интерфейс, дисплей двух строчный, размер шрифта 5*8
_delay_ms(1);
LCD_commands(0b00001100); //включение дисплея, выключение курсора, курсор не моргает
_delay_ms(1);
LCD_commands(0b00000001); //очистка дисплея
_delay_ms(2);
LCD_commands(0b00000110); //инкрементирование и сдвиг курсора в право
_delay_ms(1);
}
void set_cursor(unsigned char y, unsigned char x) //функция установки курсора в строке (параметр y = 1 или 2) и на заданной позиции этой строки (параметр х от 0 до 15)
{
switch(y)
{
case 1: LCD_commands(x | 0b10000000);
break;
case 2: LCD_commands((x + 0x40) | 0b10000000);
break;
}
}
void print_string(char words[]) //функция вывода строк на дисплей
{
unsigned char z;
for (z = 0; words[z] != '\0'; z++)
{
LCD_data(words[z]);
}
}
И при запуске симуляции в протеусе получаю вот такой результат.
Спойлер

На дисплее подключенном на прямую к микроконтроллеру все отображается как надо, а на дисплее подключенном по TWI пустота и курсор смещенный на четыре символа в право. Хотя отправлялись три одиночных символа.
Если отправлять одиночный символ, то один дисплей покажет то что было отправлено, а второй совсем другой символ.
Спойлер

Уважаемые коты, помогите разобраться, что я мог сделать не так. Сильно тапками не пинайте, в программировании не очень силен.
Заранее всем спасибо за оказанную помощь!
P.S.
В железе работает так же как и в протеусе.
Прилагаю архив проекта в AtmelStudio 7 и проекта в протеусе
Вложение:
LCD display.zip [38.25 KiB]
Скачиваний: 11
Вложение:
LCD.zip [15.12 KiB]
Скачиваний: 10