//***************************************************************************** // ssd1803a_spi.c // //***************************************************************************** #include "ssd1803a_spi.h" #include #include #include "ssd1803a_spi.h" #include #include #define LCD_CS_1 PORTB |= (1 << LCD_CS_PIN); #define LCD_CS_0 PORTB &= ~(1 << LCD_CS_PIN); #define LCD_RESET_1 PORTD |= (1 << LCD_RST_PIN); #define LCD_RESET_0 PORTD &= ~(1 << LCD_RST_PIN); /* Bottom-View DDRAM-Basisadressen der 4 Zeilen (5-Dot-Font, Standard) */ static const uint8_t row_offset[4] = {0x00, 0x20, 0x40, 0x60}; static const uint8_t row_offset_invers[4] = {0x0A, 0x2A, 0x4A, 0x6A}; unsigned int ui_x,ui_y,ui_cursormode,ui_oldcursormode,DHMode,LCD_180GRAD,LCD_ROWS; // ---------- SPI-Basis ---------- //***************************************************************************** // LCD - SPI Init // Input: - // Output: - //***************************************************************************** void spi_init(void) { //Output PINS SPI_DDR |= (1 << LCD_CS_PIN) | (1 << SPI_MOSI) | (1 << SPI_SCK); LCD_RST_DDR = (1 << LCD_RST_PIN); SPCR = (1< 2MHz/16 ~ 125kHz // | (1< 4-Zeilen-Modus lcd_command(0x1E); // Bias Set: BS1=1 (zusammen mit BS0 -> 1/6 Bias) if (LCD_180GRAD) { lcd_command(TAB1); // Function Set: DL=1, N=1, RE=1 lcd_command(0x05); // Display um 180 Grad drehen } // --- Schritt 2: in Register-Bank IS=1 wechseln --- lcd_command(TAB2); // Function Set: RE=0, IS=1 lcd_command(0x1B); // Internal OSC: BS0=1, F2:0=011 (540 kHz, POR) lcd_command(0x6E); // Follower Control: Divider on, Rab=110 _delay_ms(200); // Spannungswandler/Booster stabilisieren lassen lcd_command(0x55); // Power/Icon/Contrast: Booster on, C5:C4 lcd_command(0x7A); // Contrast Set: C3:C0 (EA-Empfehlung) // --- Schritt 3: zurueck in Basis-Registerbank --- if (DHMode) lcd_command(TAB0 | 0x04); // Function Set: RE=0, IS=0 else lcd_command(TAB0); lcd_command(0x0C); // Display an, Cursor aus, Blinken aus _delay_ms(20); lcd_clear(); ui_cursormode = CURSOR_OFF; ui_oldcursormode = CURSOR_OFF+1; } //***************************************************************************** // LCD - write // Input: - // Output: - // // rs = 0 -> Instruction Register, rs = 1 -> Data Register. RW ist immer 0 // (nur Schreiben, kein Busy-Flag-Polling implementiert -> stattdessen // feste Delays nach kritischen Befehlen). //***************************************************************************** static void lcd_write(uint8_t rs, uint8_t value) { uint8_t start_byte; if (rs) start_byte = 0x5F; //Data else start_byte = 0x1F; //Command LCD_CS_0; spi_transfer(start_byte); spi_transfer(value & 0x0F); // Low-Nibble zuerst spi_transfer((value >> 4) & 0x0F); // dann High-Nibble LCD_CS_1; _delay_us(50); // typ. Befehlsausfuehrungszeit lt. Datenblatt 39µs } void lcd_command(uint8_t cmd) { lcd_write(0, cmd); } void lcd_data(uint8_t data) { lcd_write(1, data); } // ---------- Oeffentliche Hilfsfunktionen ---------- //***************************************************************************** // LCD - clear // Input: - // Output: - //***************************************************************************** void lcd_clear(void) { lcd_command(DISPLAY_CLEAR); // Clear Display, setzt auch I/D=1 (Auto-Inkrement) _delay_ms(2); lcd_cursor(); } //***************************************************************************** // LCD - goto // Input: - // Output: - //***************************************************************************** void lcd_goto(uint8_t row, uint8_t col) { if (row > LCD_ROWS) row = LCD_ROWS; if (col > LCD_COLS) col = LCD_COLS; if (row < 1) row = 1; if (col < 1) col = 1; ui_x = col; ui_y = row; row -= 1; col -= 1; if (LCD_180GRAD) lcd_command(0x80 | (row_offset_invers[row] + col)); else lcd_command(0x80 | (row_offset[row] + col)); } //***************************************************************************** // LCD - write_char // Input: - // Output: - //***************************************************************************** void lcd_write_char(char c) { if ((ui_x <= LCD_COLS) && (ui_y <= LCD_ROWS)) { lcd_data((uint8_t) c); ui_x++; } } //***************************************************************************** // LCD - write_str // Input: - // Output: - //***************************************************************************** void lcd_write_str(uint8_t row, uint8_t col, const char *str) { uint8_t cnt = 0; lcd_goto(row,col); cnt = col; while (*str) { lcd_write_char(*str++); cnt++; if (cnt > LCD_COLS) break; } } //***************************************************************************** // LCD - set_contrast // Input: - // Output: - //***************************************************************************** void lcd_set_contrast(uint8_t contrast) { uint8_t c_high,c_low; c_low = 0x7A | (contrast & 0x0F); // C3..C0 c_high = 0x55 | ((contrast >> 4) & 0x03); // C5,C4 lcd_command(TAB2); // RE=0, IS=1 lcd_command(c_high); // Power/Icon/Contrast: Bon=1 lcd_command(c_low); // Contrast Set if (DHMode) lcd_command(TAB0 | 0x04); // Function Set: RE=0, IS=0 else lcd_command(TAB0); } //***************************************************************************** // LCD - Display_drehen // Input: - // Output: - //***************************************************************************** void lcd_Display_drehen(uint8_t x) { lcd_clear(); lcd_command(TAB0); // lcd_command(TAB1); // Function Set: DL=1, N=1, RE=1 #ifdef LCD_ROTATING if (x) x = 0; else x = 1; #endif if (x) { lcd_command(0x05); // Display um 180 Grad drehen LCD_180GRAD = 1; } else { lcd_command(0x06); LCD_180GRAD = 0; } if (DHMode) lcd_command(TAB0 | 0x04); // Function Set: RE=0, IS=0 else lcd_command(TAB0); lcd_clear(); lcd_goto(1,1); } //***************************************************************************** // LCD - Displayfunktionen // Input: Fktnr. // Output: - //***************************************************************************** void lcd_funktion(unsigned char uc_Fkt) { switch(uc_Fkt & 0x0F) { case 0x00: lcd_command(CURSOR_HOME); //Home ui_x = 1; ui_y = 1; break; case 0x01: lcd_clear(); break; case 0x02: lcd_command(DISPLAY_OFF); //Display aus break; case 0x03: ui_cursormode = CURSOR_OFF; //Display an, Cursor off lcd_cursor(); break; case 0x04: ui_cursormode = CURSOR_ON; //Cursor an lcd_cursor(); break; case 0x05: ui_cursormode = CURSOR_BLINK; //Cursor an, blink, Unterstrich lcd_cursor(); break; case 0x06: lcd_command(DISPLAY_ON); //Display an break; case 0x07: break; case 0x08: DHMode = 0; lcd_command(TAB1); // Function Set: DL=1, N=1, RE=1 lcd_command(0x09); // Extended Function Set: NW=1 -> 4-Zeilen-Modus lcd_command(TAB0); lcd_clear(); break; case 0x09: DHMode = 1; lcd_command(TAB1); // Function Set: DL=1, N=1, RE=1 lcd_command(0x1F); // Extended Function Set: NW=1 -> 3-Zeilen-Modus lcd_command(0x3C); // DH=1 lcd_command(TAB0 | 0x04); lcd_clear(); break; case 0x0A: DHMode = 1; lcd_command(TAB1); // Function Set: DL=1, N=1, RE=1 lcd_command(0x17); // Extended Function Set: NW=1 -> 3-Zeilen-Modus lcd_command(0x3C); // DH=1 lcd_command(TAB0 | 0x04); lcd_clear(); break; case 0x0B: DHMode = 1; lcd_command(TAB1); // Function Set: DL=1, N=1, RE=1 lcd_command(0x13); // Extended Function Set: NW=1 -> 3-Zeilen-Modus lcd_command(0x3C); // DH=1 lcd_command(TAB0 | 0x04); lcd_clear(); break; case 0x0C: DHMode = 1; lcd_command(TAB1); // Function Set: DL=1, N=1, RE=1 lcd_command(0x1B); // Extended Function Set: NW=1 -> 2-Zeilen-Modus lcd_command(0x3C); // DH=1 lcd_command(TAB0 | 0x04); lcd_clear(); break; case 0x0D: lcd_Display_drehen(0); break; case 0x0E: lcd_Display_drehen(1); break; } //switch } //***************************************************************************** // LCD - Cursorfkt. // Input: - // Output: - //***************************************************************************** void lcd_cursor(void) { if (ui_cursormode != ui_oldcursormode) { ui_oldcursormode = ui_cursormode; switch(ui_cursormode) { case CURSOR_OFF: lcd_command(DISPLAY_ON); //Display an, Cursor off lcd_command(CURSOR_OFF); break; case CURSOR_BLINK: lcd_command(DISPLAY_ON | CURSOR_BLINK); //Display an, Cursor BLINK,Unterstrich break; case CURSOR_ON: lcd_command(DISPLAY_ON | CURSOR_ON); //Display an, Cursor BLINK2 break; } } } //***************************************************************************** // LCD - Backspace // Input: - // Output: - //***************************************************************************** void lcd_backspace(void) { if (ui_x > 1) ui_x--; lcd_goto(ui_y,ui_x); lcd_write_char(0x20); if (ui_x > 1) ui_x--; lcd_goto(ui_y,ui_x); } //***************************************************************************** // LCD - newline naechste Zeile // Input: - // Output: - //***************************************************************************** void lcd_newline(void) { if (ui_y < LCD_ROWS) ui_y++; lcd_goto(ui_y,ui_x); } //***************************************************************************** // LCD - Return Zeilenanfang // Input: - // Output: - //***************************************************************************** void lcd_return(void) { ui_x = 1; lcd_goto(ui_y,ui_x); } //***************************************************************************** // LCD - Display loeschen // Input: Zeile // Output: - //***************************************************************************** void lcd_lineclear(uint8_t uc_zeile) { uint8_t uc_n; lcd_goto(1,uc_zeile); for(uc_n = 0; uc_n < LCD_COLS; uc_n++) { lcd_write_char(0x20); } lcd_goto(uc_zeile,1); } //***************************************************************************** // LCD - Zeichensatz // Input: - // Output: - //***************************************************************************** void lcd_Zeichensatz(ZEICHENSATZ_t Zeichensatz) { lcd_command(TAB1); lcd_command(ROMSEL); lcd_data(Zeichensatz); lcd_command(TAB0); } //***************************************************************************** // LCD - Zeichen erzeugen // Input: Zeichenadresse 0..7,Pattern 8 Byte // Output: - //***************************************************************************** void lcd_createchar(unsigned char uc_adr,char * pc_pattern) { unsigned char uc_cgram = 0; unsigned char uc_cnt; if (uc_adr < 8) { uc_cgram = uc_adr * 8; } lcd_command(CGRAM | uc_cgram); for (uc_cnt=0; uc_cnt < 8; uc_cnt++) { lcd_data(pc_pattern[uc_cnt]); } lcd_goto(ui_y,ui_x); }