From: Manfred Steiner Date: Sun, 28 Jul 2024 16:35:11 +0000 (+0200) Subject: Test-Software Unit LCD (20x2 oder 20x4) X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=c96aadd58b9996def342b679ad6ddb87d35031db;p=nano-x-base.git Test-Software Unit LCD (20x2 oder 20x4) --- diff --git a/software/test_2024-07-23/src/main.cpp b/software/test_2024-07-23/src/main.cpp index 002c340..c9fa880 100644 --- a/software/test_2024-07-23/src/main.cpp +++ b/software/test_2024-07-23/src/main.cpp @@ -14,6 +14,7 @@ #include "units/r2r.hpp" #include "units/motor.hpp" #include "units/portexp.hpp" +#include "units/lcd.hpp" extern "C" { void __cxa_pure_virtual () { @@ -48,6 +49,7 @@ extern "C" { R2r r2r; Motor motor; PortExp portExp; + Lcd lcd; } @@ -98,7 +100,7 @@ int main () { printf("======================================"); - TestUnit *unit[] = { &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp }; + TestUnit *unit[] = { &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd }; for (uint8_t i = 0; i < sizeof(unit) / sizeof(unit[0]); i++) { TestUnit *pu = unit[i]; diff --git a/software/test_2024-07-23/src/units/lcd.cpp b/software/test_2024-07-23/src/units/lcd.cpp new file mode 100644 index 0000000..0781b6a --- /dev/null +++ b/software/test_2024-07-23/src/units/lcd.cpp @@ -0,0 +1,224 @@ +#include +#include +#include + +#include "lcd.hpp" +#include "../main.hpp" + +// 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! + +// #define LCD_3V3 +#ifdef LCD_3V3 + #define DATA_PIN PINB +#endif + +#define DATA_PORT PORTB +#define DIR_DATA_PORT DDRB + +#define PORT_RS PD7 +#define SET_RS_PIN (PORTD |= (1 << PORT_RS)) +#define CLR_RS_PIN (PORTD &= ~(1 << PORT_RS)) +#define SET_DIR_RS (DDRD |= (1 << PORT_RS)) +#define CLR_DIR_RS (DDRD &= ~(1 << PORT_RS)) + +#define PORT_RW PD6 +#define SET_RW_PIN (PORTD |= (1 << PORT_RW)) +#define CLR_RW_PIN (PORTD &= ~(1 << PORT_RW)) +#define SET_DIR_RW (DDRD |= (1 << PORT_RW)) +#define CLR_DIR_RW (DDRD &= ~(1 << PORT_RW)) + +#define SET_E_PIN (PORTA |= (1 << PA3)) +#define CLR_E_PIN (PORTA &= ~(1 << PA3)) +#define SET_DIR_E (DDRA |= (1 << PA3)) +#define CLR_DIR_E (DDRA &= ~(1 << PA3)) + +// Befehle für das Display + +#define DISP_CLEAR 0b00000001 // Display clear +#define DISP_ON 0b00001111 // Display on +#define DISP_OFF 0b00001011 // Display off +#define CURSOR_ON 0b00001111 // Cursor on +#define CURSOR_OFF 0b00001101 // Cursor off +#define BLINK_ON 0b00001111 // Cursor Blink +#define BLINK_OFF 0b00001110 // Cursor No Blink + + +void Lcd::cleanup () { + DDRA &= ~(1 << PA3); + PORTA &= ~(1 << PA3); + DDRD &= ~((1 << DDD7) | (1 << DDD6)); + PORTD &= ~((1 << PORTD7) | (1 << PORTD6)); + PORTB = 0; + DDRB = 0; +} + +int8_t Lcd::run (uint8_t subtest) { + if (subtest == 0) { + // DDRA |= (1 << PA3); + // PORTA &= ~(1 << PA3); + // DDRD |= (1 << DDD7) | (1 << DDD6); + // PORTD &= ~((1 << PORTD7) | (1 << PORTD6)); + // PORTB = 0; + // DDRB = 0xff; + init(); + #ifdef LCD_3V3 + printf("init 3.3V LCD"); + #else + printf("init 5V LCD"); + #endif + + } else if (subtest == 1) { + for (uint8_t i = 0; i < 20 * 4; i++) { + char c = (char)(i + 32); + if (i % 20 == 0) { + setCursor(i / 20 + 1, 1); + } + writeData(c); + while (isBusy()) {}; + } + // setCursor(1, 1); + // writeString(" 1234567890<>,;.:-_#+"); + // setCursor(2, 1); + // writeString("abcdefghijklmnopqrst"); + // setCursor(3, 1); + // writeString("uvwxyzABCDEFGHIJKLMN"); + // setCursor(4, 1); + // writeString("OPQRSTUVWXYZ "); + printf("LCD beschrieben"); + while (wait(1) == EOF) { + } + + } else { + printf("end"); + return -1; + } + wait(500); + return 0; +} + +void Lcd::init () { + CLR_RW_PIN; // write + CLR_RS_PIN; // command + CLR_E_PIN; // E = 0 + + SET_DIR_RW; + SET_DIR_RS; + SET_DIR_E; + + DATA_PORT = 0; + DIR_DATA_PORT = 0xff; + _delay_ms(16); // min 15ms warten für Reset des Displays + + DATA_PORT = 0b00111011; // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display + CLR_RW_PIN; // write + CLR_RS_PIN; // command + SET_E_PIN; // E = 1 (transfer start) + _delay_us(10); // min. 10us + CLR_E_PIN; // E = 0 (transfer end) + _delay_ms(5); // min. 4.1ms + + DATA_PORT = 0b00111011; // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display + CLR_RW_PIN; // write + CLR_RS_PIN; // command + SET_E_PIN; // E = 1 (transfer start) + _delay_us(10); // min. 10us + CLR_E_PIN; // E = 0 (transfer end) + _delay_us(100); // min. 100us + + DATA_PORT = 0b00111011; // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display + CLR_RW_PIN; // write + CLR_RS_PIN; // command + SET_E_PIN; // E = 1 (transfer start) + _delay_us(10); // min. 10us + CLR_E_PIN; // 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()) {}; +} + +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; + #else + _delay_us(200); + return 0; + #endif + +} + +void Lcd::writeCommand (uint8_t cmd) { + DATA_PORT = cmd; + CLR_RW_PIN; // write + CLR_RS_PIN; // command + SET_E_PIN; // E = 1 (transfer start) + _delay_us(10); // min. 10us + CLR_E_PIN; // E = 0 (transfer end) + _delay_us(10); // min. 10us + DATA_PORT = 0; +} + +void Lcd::setDDRamAddr (uint8_t address) { + DATA_PORT = address | 0x80; + CLR_RW_PIN; // write + CLR_RS_PIN; // command + SET_E_PIN; // E = 1 (transfer start) + _delay_us(10); // min. 10us + CLR_E_PIN; // E = 0 (transfer end) + _delay_us(10); // min. 10us + DATA_PORT = 0; +} + +void Lcd::writeString (const char *s) { + while (*s) { + writeData(*s++); + while (isBusy()) {}; + } +} + +void Lcd::writeData (uint8_t data) { + DATA_PORT = data; // Write data to port + SET_RS_PIN; // data + CLR_RW_PIN; // command + SET_E_PIN; // E = 1 (transfer start) + _delay_us(10); // min. 10us + CLR_E_PIN; // E = 0 (transfer end) + _delay_us(10); // min. 10us + CLR_RS_PIN; + DATA_PORT = 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()) {}; +} + diff --git a/software/test_2024-07-23/src/units/lcd.hpp b/software/test_2024-07-23/src/units/lcd.hpp new file mode 100644 index 0000000..11e7749 --- /dev/null +++ b/software/test_2024-07-23/src/units/lcd.hpp @@ -0,0 +1,23 @@ +#ifndef LCD_HPP +#define LCD_HPP + +#include +#include "../main.hpp" + +class Lcd : public TestUnit { + public: + Lcd () {}; + virtual void cleanup (); + virtual int8_t run (uint8_t subtest); + virtual const char *getName () { return "Lcd"; } + + void init (); + 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); +}; + +#endif \ No newline at end of file