Форум РадиоКот https://radiokot.ru/forum/ |
|
Подключение LCD1602 + PCF8574 к ATmega8 https://radiokot.ru/forum/viewtopic.php?f=57&t=198164 |
Страница 1 из 1 |
Автор: | Denis-1307 [ Пт май 30, 2025 12:13:44 ] |
Заголовок сообщения: | Подключение LCD1602 + PCF8574 к ATmega8 |
Доброго сем времени суток! Решил разобраться с подключением ЖК дисплея (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 и проекта в протеусе Вложение: Вложение:
|
Автор: | veso74 [ Пт май 30, 2025 13:20:20 ] |
Заголовок сообщения: | Re: Подключение LCD1602 + PCF8574 к ATmega8 |
строка 98: Код: val = (data | (1<<3) | (1<<2)) & ~(1<<0); //установка 3-го бита, включение подсветки дисплея в Код: val = ((data & 0b11110000) | (1<<3) | (1<<2)) & ~(1<<0); //установка 3-го бита, включение подсветки дисплея
|
Автор: | Denis-1307 [ Пт май 30, 2025 14:12:47 ] |
Заголовок сообщения: | Re: Подключение LCD1602 + PCF8574 к ATmega8 |
строка 98: Код: val = (data | (1<<3) | (1<<2)) & ~(1<<0); //установка 3-го бита, включение подсветки дисплея в Код: val = ((data & 0b11110000) | (1<<3) | (1<<2)) & ~(1<<0); //установка 3-го бита, включение подсветки дисплея Спасибо, заработало. На реальном железе на дисплее все отображается нормально. Различные символы, знаки, все отображается так как надо. Протеус нормально отображает лишь "A, a, 1 и !". При отправке других символов, знаков на дисплее полная ерунда. Главное что в железе все работает как надо. И еще вопрос. А можно поподробнее объяснить, зачем с байтом передаваемой команды надо делать вот это: data & 0b11110000 ? Update Сделал вот так: data & 0b11110000 и при передаче байта данных, и в протеусе все начало отображаться нормально. Теперь еще болле стало интересно для чего необходимо так делать? |
Автор: | veso74 [ Пт май 30, 2025 15:50:37 ] |
Заголовок сообщения: | Re: Подключение LCD1602 + PCF8574 к ATmega8 |
См. "битовая маска" в булевой алгебры. Значение бит 1 произошло от значения data, а этого не должно быть. Обычно проще сбросить все биты на ноль (которые следуют за изменением) с побитово И (&), а затем добавить новые значения с помощью побитово ИЛИ (|). (частично пользуюсь переводчиком) |
Автор: | Starichok51 [ Пт май 30, 2025 16:07:31 ] |
Заголовок сообщения: | Re: Подключение LCD1602 + PCF8574 к ATmega8 |
Denis-1307 писал(а): Теперь еще болле стало интересно для чего необходимо так делать? потому что байт передается за 2 раза - по 4 старших бита.поэтому нужно сначала сбросить 4 младших бита, а потом к байту добавить нужные биты управления. а когда передаешь 4 младших бита, то сначала байт сдвигается влево 4 раза (чтобы младшие биты заняли позицию старших), и младшие биты после сдвигов освобождаются сами. |
Автор: | Denis-1307 [ Пт май 30, 2025 16:10:51 ] |
Заголовок сообщения: | Re: Подключение LCD1602 + PCF8574 к ATmega8 |
Спасибо, понял. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |