From 0fcf3e4396b47ea364324bca13ae3fdf033765bb Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Fri, 13 Sep 2024 19:03:33 +0200 Subject: [PATCH] ... --- .../test_2024-07-23/src/units/lcd.cpp | 452 +++++++++++++----- .../test_2024-07-23/src/units/lcd.hpp | 33 +- 2 files changed, 365 insertions(+), 120 deletions(-) diff --git a/software/nano-644/test_2024-07-23/src/units/lcd.cpp b/software/nano-644/test_2024-07-23/src/units/lcd.cpp index 8640690..02df19d 100644 --- a/software/nano-644/test_2024-07-23/src/units/lcd.cpp +++ b/software/nano-644/test_2024-07-23/src/units/lcd.cpp @@ -7,12 +7,15 @@ #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - // Nano-644 + // Nano-644 / Nano-1284 // --------------------------------------------------------------- - // PA3 ..... E --> LCD Enable (Verbindung via J25 erforderlich) - // PD6 ..... R/W --> Read/Write: Read=1, Write=0 - // PD7 ..... RS --> Register Select: Command=0, Data=1 - // PB7:0 ... Data --> Achtung von 5V LCD nicht lesen! + + // Nano-X-Base V1a V2a Beschreibung + // --------------------------------- ------- + // E ........... PA3 PA3 LCD Enable (Verbindung via J25 erforderlich) + // R/W .......... PD6 PD6 Read/Write: Read=1, Write=0 + // RS ........... PD7 PD7 Register Select: Command=0, Data=1 + // Data ......... PB7:0 PB7:0 Achtung von 5V LCD nicht lesen! // #define LCD_3V3 @@ -26,9 +29,9 @@ DDRD |= (1 << PD7) | (1 << PD6); initLcd(); #ifdef LCD_3V3 - printf_P(PSTR("init 3.3V LCD")); + printf_P(PSTR("init 3.3V LCD (%d)"), status); #else - printf_P(PSTR("init 5V LCD")); + printf_P(PSTR("init 5V LCD (%d)"), status); #endif } @@ -44,6 +47,12 @@ void Lcd::clrRW () { PORTD &= ~(1 << PD6); } void Lcd::setE () { PORTA |= (1 << PA3); } void Lcd::clrE () { PORTA &= ~(1 << PA3); } + void Lcd::dataDirectionIn () { DDRB = 0x00; } + void Lcd::dataDirectionOut () { DDRB = 0xff; } + + uint8_t Lcd::getData () { + return PINB; + } void Lcd::setData (uint8_t data) { PORTB = data; @@ -121,25 +130,35 @@ #define BLINK_ON 0b00001111 // Cursor Blink #define BLINK_OFF 0b00001110 // Cursor No Blink +#define LCD_PULSE_LENGTH 15 +#define LCD_CMD_DISPLAY_CLEAR 0x01 // Display clear +#define LCD_CMD_CURSOR_HOME 0x02 // Move cursor digit 1 +#define LCD_CMD_SET_ENTRY_MODE 0x04 // Entry Mode Set +#define LCD_CMD_DISPLAY_ON_OFF 0x08 // Display on/off +#define LCD_CMD_SHIFT 0x10 // Display shift +#define LCD_CMD_SET_FUNCTION 0x20 // 4/8 Bits... +#define LCD_CMD_SET_CGRAM_ADDR 0x40 // Character Generator ROM +#define LCD_CMD_SET_DDRAM_ADDR 0x80 // Display Data RAM +#define LCD_BUSY_FLAG 0x80 + + + int8_t Lcd::run (uint8_t subtest) { if (subtest == 0) { for (uint8_t i = 0; i < 20 * 4; i++) { char c = (char)(i + 32); if (i % 20 == 0) { - setCursor(i / 20 + 1, 1); + setCursor(i / 20, 0); } - writeData(c); - while (isBusy()) {}; + putChar(c); + waitOnReady(); + } + printf_P(PSTR("LCD ")); + if (status == 1) { + printf_P(PSTR("OK")); + } else { + printf_P(PSTR("ERROR(%d)"), status); } - // setCursor(1, 1); - // writeString(" 1234567890<>,;.:-_#+"); - // setCursor(2, 1); - // writeString("abcdefghijklmnopqrst"); - // setCursor(3, 1); - // writeString("uvwxyzABCDEFGHIJKLMN"); - // setCursor(4, 1); - // writeString("OPQRSTUVWXYZ "); - printf_P(PSTR("LCD beschrieben")); while (wait(1) == EOF) { } @@ -151,114 +170,321 @@ int8_t Lcd::run (uint8_t subtest) { return 0; } +// void Lcd::initLcd () { +// _delay_ms(16); // min 15ms warten für Reset des Displays + +// if (mode8Bit) { +// setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display +// clrRW(); // write +// clrRS(); // command +// setE(); // E = 1 (transfer start) +// _delay_us(10); // min. 10us +// clrE(); // E = 0 (transfer end) +// _delay_ms(5); // min. 4.1ms + +// setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display +// clrRW(); // write +// clrRS(); // command +// setE(); // E = 1 (transfer start) +// _delay_us(10); // min. 10us +// clrE(); // E = 0 (transfer end) +// _delay_us(100); // min. 100us + +// setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display +// clrRW(); // write +// clrRS(); // command +// setE(); // E = 1 (transfer start) +// _delay_us(10); // min. 10us +// clrE(); // E = 0 (transfer end) +// _delay_us(100); // min. 100us + +// } else { +// setData( 0b0010 << 4 ); // 4bit Modus, 5x7 Zeichen, Mehrzeilen Display +// } + +// writeCommand(DISP_OFF); // Display aus +// while(isBusy()) {}; +// writeCommand(DISP_ON); // Display ein +// while(isBusy()) {}; +// writeCommand( BLINK_OFF & CURSOR_OFF); // Blink aus und Cursor aus +// while(isBusy()) {}; +// writeCommand(DISP_CLEAR);// Clear display +// while(isBusy()) {}; +// } + +// uint8_t Lcd::isBusy () { +// #ifdef LCD_3V3 +// // DIR_DATA_PORT = 0; +// // SET_RW_PIN; // read +// // CLR_RS_PIN; // command +// // SET_E_PIN; // E = 1 (transfer start) +// // _delay_us(10); +// // uint8_t busy = DATA_PIN & 0x80; // read bit 7 (busy bit) +// // CLR_E_PIN; // E = 0 (transfer end) +// // CLR_RW_PIN; +// // DIR_DATA_PORT = 0xff; +// // return busy != 0; +// _delay_us(200); +// #else +// _delay_us(200); +// #endif +// return 0; +// } + +// void Lcd::writeCommand (uint8_t cmd) { +// setData(cmd); +// clrRW(); // write +// clrRS(); // command +// setE(); // E = 1 (transfer start) +// _delay_us(10); // min. 10us +// clrE(); // E = 0 (transfer end) +// setData(0); +// } + +// void Lcd::setDDRamAddr (uint8_t address) { +// setData(address | 0x80); +// clrRW(); // write +// clrRS(); // command +// setE(); // E = 1 (transfer start) +// _delay_us(10); // min. 10us +// clrE(); // E = 0 (transfer end) +// _delay_us(10); // min. 10us +// setData(0); +// } + +// void Lcd::writeString (const char *s) { +// while (*s) { +// writeData(*s++); +// while (isBusy()) {}; +// } +// } + +// void Lcd::writeData (uint8_t data) { +// setData(data); +// setRS(); // data +// clrRW(); // write +// setE(); // E = 1 (transfer start) +// _delay_us(10); // min. 10us +// clrE(); // E = 0 (transfer end) +// _delay_us(10); // min. 10us +// clrRS(); +// setData(0); +// } + +// void Lcd::setCursor (uint8_t row, uint8_t column) { +// uint8_t b; +// if (column > 20) { +// return; +// } +// switch (row) { +// case 1: b = 0x00 + column - 1; break; +// case 2: b = 0x40 + column - 1; break; +// case 3: b = 0x14 + column - 1; break; +// case 4: b = 0x54 + column - 1; break; +// default: return; +// } +// setDDRamAddr(b); +// while (isBusy()) {}; +// } + + + void Lcd::initLcd () { + + setData(0x00); + dataDirectionOut(); + + // setE(); + // _delay_us(200); + // clrE(); + // for (uint8_t i = 0; i < 16; i++) { + // setData(i << 4); + // _delay_us(200); + // } + + // for (uint8_t i = 0; i < 10; i++) { + // clrRS(); + // setRW(); + // _delay_us(200); + // setRS(); + // clrRW(); + // _delay_us(200); + // } + _delay_ms(16); // min 15ms warten für Reset des Displays + status = 0; + for (uint8_t i = 0; i < 4; i++) { + setRegister(LCD_CMD_SET_FUNCTION | 0x08); // 4 Bit, 2 Zeilen, 5x7 + if (i == 0) { + _delay_ms(5); + } else { + _delay_us(100); + } + } - setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display - clrRW(); // write - clrRS(); // command - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - _delay_ms(5); // min. 4.1ms - - setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display - clrRW(); // write - clrRS(); // command - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - _delay_us(100); // min. 100us - - setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display - clrRW(); // write - clrRS(); // command - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - _delay_us(100); // min. 100us - - writeCommand(DISP_OFF); // Display aus - while(isBusy()) {}; - writeCommand(DISP_ON); // Display ein - while(isBusy()) {}; - writeCommand( BLINK_OFF & CURSOR_OFF); // Blink aus und Cursor aus - while(isBusy()) {}; - writeCommand(DISP_CLEAR);// Clear display - while(isBusy()) {}; + setRegister(LCD_CMD_DISPLAY_ON_OFF | 0x04); // display on, cursor off + if (!isReady(50)) { + status = -1; + return; + } + + setRegister(LCD_CMD_DISPLAY_ON_OFF | 0x04); // display on, cursor off + if (!isReady(50)) { + status = -3; + return; + } + + setRegister(LCD_CMD_DISPLAY_CLEAR); + if (!isReady(1200)) { + status = -4; + return; + } + + status = 1; } -uint8_t Lcd::isBusy () { - #ifdef LCD_3V3 - // DIR_DATA_PORT = 0; - // SET_RW_PIN; // read - // CLR_RS_PIN; // command - // SET_E_PIN; // E = 1 (transfer start) - // _delay_us(10); - // uint8_t busy = DATA_PIN & 0x80; // read bit 7 (busy bit) - // CLR_E_PIN; // E = 0 (transfer end) - // CLR_RW_PIN; - // DIR_DATA_PORT = 0xff; - // return busy != 0; - _delay_us(200); - #else - _delay_us(200); - #endif - return 0; + +void Lcd::setRegister (uint8_t cmd) { + + setData(0x00); + dataDirectionOut(); + + clrE(); + clrRW(); + clrRS(); + + setData(cmd & 0xf0); // send High-Nibble + setE(); + _delay_us(LCD_PULSE_LENGTH); + clrE(); + _delay_us(1); + + setData(cmd << 4); // send Low-Nibble + setE(); + _delay_us(LCD_PULSE_LENGTH); + clrE(); + _delay_us(1); } -void Lcd::writeCommand (uint8_t cmd) { - setData(cmd); - clrRW(); // write - clrRS(); // command - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - setData(0); +void Lcd::setDRAddr (uint8_t address) { + waitOnReady(); + setRegister(LCD_CMD_SET_DDRAM_ADDR | address); + waitOnReady(); } -void Lcd::setDDRamAddr (uint8_t address) { - setData(address | 0x80); - clrRW(); // write - clrRS(); // command - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - _delay_us(10); // min. 10us - setData(0); +void Lcd::waitOnReady () { + if (isReady(50) == 0) { + status = -6; + } } -void Lcd::writeString (const char *s) { - while (*s) { - writeData(*s++); - while (isBusy()) {}; + +bool Lcd::isReady (uint16_t us) { + if (status < 0) { + return false; + } + + uint8_t busy; + dataDirectionIn(); + setData(0xff); // enable internal pull up + + do { + uint8_t data = 0; + setRW(); + clrRS(); + + _delay_us(1); + setE(); + _delay_us(LCD_PULSE_LENGTH); + data = getData() & 0xf0; // High Nibble + clrE(); + + _delay_us(1); + setE(); + _delay_us(LCD_PULSE_LENGTH); + data |= getData() >> 4; // Low Nibble + + clrE(); + _delay_us(1); + clrRW(); + + busy = data & LCD_BUSY_FLAG; + us = (us >= 11) ? us - 11 : 0; + } while (us > 0 && busy); + + if (status == 1 && busy) { + status = -5; } + + setData(0x00); + dataDirectionOut(); + + return busy == 0; } -void Lcd::writeData (uint8_t data) { - setData(data); - setRS(); // data - clrRW(); // write - setE(); // E = 1 (transfer start) - _delay_us(10); // min. 10us - clrE(); // E = 0 (transfer end) - _delay_us(10); // min. 10us - clrRS(); - setData(0); + +void Lcd::setDisplayOn () { + waitOnReady(); + setRegister(LCD_CMD_DISPLAY_ON_OFF | 0x04); // display on + waitOnReady(); +} + +void Lcd::setDisplayOff () { + waitOnReady(); + setRegister(LCD_CMD_DISPLAY_ON_OFF); // display off + waitOnReady(); +} + +void Lcd::clear () { + waitOnReady(); + setRegister(LCD_CMD_DISPLAY_CLEAR); + while (!isReady(1200)) { + } } -void Lcd::setCursor (uint8_t row, uint8_t column) { - uint8_t b; - if (column > 20) { - return; - } - switch (row) { - case 1: b = 0x00 + column - 1; break; - case 2: b = 0x40 + column - 1; break; - case 3: b = 0x14 + column - 1; break; - case 4: b = 0x54 + column - 1; break; - default: return; - } - setDDRamAddr(b); - while (isBusy()) {}; +void Lcd::setCursor (uint8_t rowIndex, uint8_t columnIndex) { + if (status != 1 || rowIndex > 1) { + return; + } + if (rowIndex) { + setDRAddr(0x40 + columnIndex); + } else { + setDRAddr(columnIndex); + } } + +void Lcd::putChar (char c) { + if (status != 1) { + return; + } + + waitOnReady(); + + setData(0x00); + dataDirectionOut(); + clrE(); + clrRW(); + setRS(); + + PORTB &= 0x0f; + setData(c & 0xf0); // send High-Nibble + setE(); + _delay_us(LCD_PULSE_LENGTH); + clrE(); + _delay_us(1); + + setData(c << 4); // send Low-Nibble + setE(); + _delay_us(LCD_PULSE_LENGTH); + clrE(); + _delay_us(1); + clrRS(); + _delay_us(1); +} + +void Lcd::puts (const char * str) { + while (*str && status == 1) { + putChar(*str++); + } + waitOnReady(); +} \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/lcd.hpp b/software/nano-644/test_2024-07-23/src/units/lcd.hpp index 3eb4456..0ea1c28 100644 --- a/software/nano-644/test_2024-07-23/src/units/lcd.hpp +++ b/software/nano-644/test_2024-07-23/src/units/lcd.hpp @@ -7,27 +7,46 @@ class Lcd : public TestUnit { public: - Lcd () {}; + Lcd () { mode8Bit = 0; status = 0; }; virtual void init (); virtual void cleanup (); virtual int8_t run (uint8_t subtest); virtual PGM_P getName () { return PSTR("Lcd"); } private: + + bool mode8Bit; + int8_t status; void initLcd (); - uint8_t isBusy (); - void writeCommand (uint8_t); - void setDDRamAddr (uint8_t); - void writeString (const char *s); - void writeData (uint8_t); - void setCursor (uint8_t row, uint8_t column); + // uint8_t isBusy (); + // void writeCommand (uint8_t); + // void setDDRamAddr (uint8_t); + // void writeString (const char *s); + // void writeData (uint8_t); + // void setCursor (uint8_t row, uint8_t column); + + void setRegister (uint8_t cmd); + void setDRAddr (uint8_t address); + void waitOnReady (); + bool isReady (uint16_t us); + void setDisplayOn (); + void setDisplayOff (); + void clear (); + void setCursor (uint8_t rowIndex, uint8_t columnIndex); + void putChar (char c); + void puts (const char * str); + + void setRS (); void clrRS (); void setRW (); void clrRW (); void setE (); void clrE (); + uint8_t getData (); void setData (uint8_t data); + void dataDirectionIn (); + void dataDirectionOut (); }; -- 2.39.5