//------------------------------------------------------------------ // LCD.h fürt das Soccerbot-Display // // Die Ansteuerung geschieht über I2C-Interface. // Das Display wird im 4-Bit-Modus betrieben. // Standardmäßig wird der Cursor angezeigt und blinkt. // // Strings können mit lcd.print(const char* data) ausgegeben werden. // Umlaute werden erkannt und die richtigen Zeichen zugewiesen. // // Messwerte (Integer) können mit lcd.print_integer(int data) ausgegeben werden. // Einzelne ASCII-Zeichen können mit lcd.print_ascii(uint8_t data) ausgegeben werden. // // Die Wartezeit WAIT3 wird unbedingt benötigt, um eine stabile Befehls- und Zeichenausgabe // zu gewährleisten. versuche mit WAIT3=0 führten zu chaotischem Verhalten! // Eine Vergrößerung der WAIT-Werte ist problemlos möglich. #ifndef LCD_h #define LCD_h #define ON 1 #define OFF 0 #include "stdlib.h" #include "qfixI2C.h" #include "qfixI2CDefs.h" #include "string.h" #include "qfixSoccerBoard.h" SoccerBoard board; static const uint8_t DISPLAY_ROWS = 2; // 2 Zeilen static const uint8_t DISPLAY_LENGTH = 16; // Das Pollin-Display hat 16 Zeichen pro Zeile static const uint8_t MAX_DISPLAY_LENGTH = 40; // 40 Zeichen kann der Chip HD44780 maximal static const uint8_t DISPLAY_MODE = 0x28; //Modus: 4-Bit-Interface, 2 Zeilen, 5*7 Font static const uint8_t CURSOR_MODE = 0x0F; //Display an, Cursor an, Blinken static const uint8_t CURSOR_HOME = 0x02; static const uint8_t CURSOR_SCROLL_RIGHT = 0x14; static const uint8_t DISPLAY_CLEAR = 0x01; // Nur während der Initialisierung im 8-Bit-Mode zu verwendende Befehle: static const uint8_t SOFT_RESET = 0x03; // Soft-Reset bei Initialisierung (Schaltet erstmal definiert den 8-Bit-Modus ein) static const uint8_t FOUR_BIT_MODE = 0x02; // Eigentlich müsste es 0x20 sein - aber während der Initialisierungsphase gibt es Besonderheiten // Physische Pins des Pollin-LC-Displays: static const uint8_t RS_PIN = 0x10; static const uint8_t RW_PIN = 0x20; static const uint8_t ENABLE_PIN = 0x40; static const uint8_t BACKLIGHT_PIN = 0x80; // Backlight on static const uint8_t HIGH_ZERO_MASK = 0x0F; // Zur Maskierung der oberen 4 Bit bei uint8_t-Datentyp // Wartezeiten (Die HD44780-Chips des LC-Displays sind am Anfang etwas "lahm" static const int WAIT1 = 500;// 500 Millisekunden Wartezeit bei Initialisierung static const int WAIT2 = 50;// 50 Millisekunden Wartezeit bei Initialisierung static const int WAIT3 = 1; // 1 Millisekunde Wartezeit uint8_t backlight_status=OFF; /** * \class LCD * \brief Represents the Pollin LCD-display. * \author Stefan Enderle, Niels Nikolaisen * * The class LCD represents the * physical LCD-display and can be used to output text and integers * or numbers. * The I2C bus is completely abstracted. */ class LCD { private: I2C i2c; uint8_t id; public: /** Default constructor. If only one LCD-display is used, * this constructor can be used. It sets the internal ID to 0. */ LCD(); /** Constructor with given ID. * If two or more LCD-displays are used, * this constructor must be used. It sets the internal ID to the given value. */ LCD(uint8_t ID); /** Change logical device ID */ void changeID(uint8_t newID); /** Inits the display */ void init(); /** Clears the display */ void clear(); /** Cursor on first position row 1 */ void cursorhome(); /** Sends one command to display */ void sendcommand(uint8_t command); /** Sends one command to display */ void sendchar(const char character); /** Sends an Integer to Display (Messwert-Ausgabe) */ void print_integer(int data); /** prints the string data at the current cursor position. */ void print(const char* data); /** Prints the string data at position line/col. The string * must end with 0. */ void print(uint8_t line, uint8_t col, const char* data); /** prints the integer data at the current cursor position. */ void print(int data); /** Prints the integer data at position line/col. */ void print(uint8_t line, uint8_t col, int data); /** Puts on the backlight. * \see lightOff */ void lightOn(); /** Puts off the backlight. * \see lightOff */ void lightOff(); /** Resets the LCD and shows the welcome screen. * Note: The LCD firmware must be 1.2 or higher. * \see lightOff */ void reset(); /** Positioning the Cursor * Note: The LCD firmware must be 1.2 or higher. * \see lightOff */ void locate(uint8_t Zeile, uint8_t Position); }; LCD::LCD() : i2c(), id(0) { ::msleep(10); reset(); } LCD::LCD(uint8_t ID) : i2c(), id(ID) { ::msleep(10); reset(); } void LCD::init() { board.msleep(WAIT1); // Wait - siehe Datenblatt! for (int i=0; i<4; i++) { //3 * Soft-Reset - laut Datenblatt unbedingt vorgeschrieben! i2c.send(I2C_ADDR_LCD, ENABLE_PIN | SOFT_RESET); // Enable HIGH schalten und High-Nibbel "3" senden board.msleep(WAIT2); i2c.send(I2C_ADDR_LCD, SOFT_RESET); // Enable LOW schalten board.msleep(WAIT2); } //Der erste Schreibzugriff nach dem Reset ist ein 8 Bit- //Zugriff!! Also nur einmal schreiben, noch nicht Low-High Nibble! //4-Bit-Modus einstellen: i2c.send(I2C_ADDR_LCD, FOUR_BIT_MODE | ENABLE_PIN); // Enable HIGH schalten und High-Nibbel "2" senden board.msleep(WAIT2); i2c.send(I2C_ADDR_LCD, FOUR_BIT_MODE); // Enable LOW schalten board.msleep(WAIT2); // Ab hier HIGH- und LOW-Nibbel schreiben (4-Bit-Mode) - mit der Funktion sendcommand() // Funktionen des Displays festlegen: sendcommand(DISPLAY_MODE); board.msleep(WAIT2); sendcommand(CURSOR_MODE); board.msleep(WAIT2); lightOn(); } void LCD::clear() { sendcommand(DISPLAY_CLEAR); } void LCD::cursorhome() { sendcommand(CURSOR_HOME); } void LCD::sendcommand(uint8_t command) { uint8_t High_Nibble; uint8_t Low_Nibble; uint8_t Send_Data; High_Nibble = command >> 4; // 4 Bit Rechtsverschiebung High_Nibble = High_Nibble & HIGH_ZERO_MASK; //Obere 4 Bit mit 0 maskieren - nur wichtig bei Datentypen > 8 Bit! Low_Nibble = command & HIGH_ZERO_MASK; //Obere 4 Bit mit 0 maskieren if (backlight_status == OFF) Send_Data = High_Nibble | ENABLE_PIN; // nur Enable setzen else Send_Data = High_Nibble | ENABLE_PIN | BACKLIGHT_PIN; // Enable + Backlight setzen i2c.send(I2C_ADDR_LCD, Send_Data); board.msleep(WAIT3); if (backlight_status == OFF) Send_Data = High_Nibble; //Enable auf LOW else Send_Data = High_Nibble | BACKLIGHT_PIN; //Enable auf LOW i2c.send(I2C_ADDR_LCD, Send_Data);//Enable Datenübernahme board.msleep(WAIT3); if (backlight_status == OFF) Send_Data = Low_Nibble | ENABLE_PIN; // Enable HIGH setzen else Send_Data = Low_Nibble | ENABLE_PIN | BACKLIGHT_PIN; // Enable HIGH setzen i2c.send(I2C_ADDR_LCD, Send_Data); board.msleep(WAIT3); if (backlight_status == OFF) Send_Data = Low_Nibble | RS_PIN; //Enable auf LOW else Send_Data = Low_Nibble | RS_PIN | BACKLIGHT_PIN; //Enable auf LOW und Backlight auf HIGH i2c.send(I2C_ADDR_LCD, Send_Data);//Enable Datenübernahme board.msleep(WAIT3); //lightOff(); } void LCD::sendchar(const char character) { uint8_t High_Nibble; uint8_t Low_Nibble; uint8_t Send_Data; High_Nibble = character>> 4; // 4 Bit Rechtsverschiebung High_Nibble = High_Nibble & HIGH_ZERO_MASK; //Obere 4 Bit mit 0 maskieren - nur wichtig bei Datentypen > 8 Bit! Low_Nibble = character & HIGH_ZERO_MASK; //Obere 4 Bit mit 0 maskieren if (backlight_status == OFF) Send_Data = High_Nibble | ENABLE_PIN | RS_PIN; // Enable und RS High setzen else Send_Data = High_Nibble | ENABLE_PIN | RS_PIN | BACKLIGHT_PIN; // Enable und RS High setzen i2c.send(I2C_ADDR_LCD, Send_Data); board.msleep(WAIT3); if (backlight_status == OFF) Send_Data = High_Nibble | RS_PIN; //Enable auf LOW; RS muss HIGH bleiben! else Send_Data = High_Nibble | RS_PIN | BACKLIGHT_PIN; //Enable auf LOW; RS muss HIGH bleiben! i2c.send(I2C_ADDR_LCD, Send_Data);//Enable Datenübernahme board.msleep(WAIT3); if (backlight_status == OFF) Send_Data = Low_Nibble | ENABLE_PIN | RS_PIN; // Enable und RS High setzen else Send_Data = Low_Nibble | ENABLE_PIN | RS_PIN | BACKLIGHT_PIN; // Enable und RS High setzen i2c.send(I2C_ADDR_LCD, Send_Data); board.msleep(WAIT3); if (backlight_status == OFF) Send_Data = Low_Nibble | RS_PIN; //Enable auf LOW; RS muss HIGH bleiben! else Send_Data = Low_Nibble | RS_PIN | BACKLIGHT_PIN; //Enable auf LOW; RS muss HIGH bleiben! i2c.send(I2C_ADDR_LCD, Send_Data);//Enable Datenübernahme board.msleep(WAIT3); } void LCD::print(const char* data) { int array_len = strlen(data); char ASCII_Zeichen[array_len]; for(int j = 0; j < array_len; j++) { ASCII_Zeichen[j] = data[j]; switch(ASCII_Zeichen[j]) //Umlaute austauschen - Hochkomma statt Gänsefüßchen, da char*-Datentyp! { case 'ä' : ASCII_Zeichen[j] = 225; //siehe Datenblat HD44780 - LCD-Treiber-Chip! break; case 'ö' : ASCII_Zeichen[j] = 239; //Vereinfachend werden nur Kleinbuchsataben der Zeichentabelle ROM-Code A00 verwendet break; case 'ü' : ASCII_Zeichen[j] = 245; break; case 'Ä' : ASCII_Zeichen[j] = 225; break; case 'Ö' : ASCII_Zeichen[j] = 239; break; case 'Ü' : ASCII_Zeichen[j] = 245; break; case 'ß' : ASCII_Zeichen[j] = 226; break; } } if(array_len>DISPLAY_LENGTH) //Zu lange Strings werden gnadenlos abgeschnitten! { array_len = DISPLAY_LENGTH; } for(int i = 0; i < array_len; i++) { sendchar(ASCII_Zeichen[i]); } } void LCD::print_integer(int data) { char buffer [16]; itoa (data,buffer,10); // Wandlung in Dezimalzahl // itoa (i,buffer,16); // Wandlung in HEX // itoa (i,buffer,2); // Wandlung in Binär print(buffer); } void LCD::lightOn() { backlight_status = ON; } void LCD::lightOff() { backlight_status = OFF; sendcommand(DISPLAY_CLEAR); } void LCD::changeID(uint8_t newID) { } void LCD::reset() { } void LCD::locate(uint8_t Zeile, uint8_t Position) { cursorhome(); int i; if (Zeile==1) { // Zeile=1 for(i=1; i1 for(i=1; i<(Position+40); i++) { sendcommand(CURSOR_SCROLL_RIGHT); } } } #endif