AVR-GCC. HD44780 LCDs.

Πολλές φορές σε πολλά συστήματα που περιλαμβάνουν κάποιον μικροελεγκτή είναι απαραίτητη κάποια αλληλεπίδραση με τον χρήστη. Ο ποιο απλός τρόπος να επιτύχουμε κάτι τέτοιο είναι μέσω μίας οθόνης υγρών κρυστάλλων που θα παρέχει πληροφορίες στον χρήστη. Ο ποιο κοινός τύπος οθόνης που χρησιμοποιείτε είναι αυτός με το ολοκληρωμένο κύκλωμα HD44780 της Hitachi.

Τεκμηρίωση του HD44780.
Τεκμηρίωση του ATmega8.

Η Επικοινωνία με το HD44780 είναι αρκετά απλή και όλα καλύπτονται αναλυτικά στην τεκμηρίωση του. Τα LCD αυτά μπορούν να λειτουργήσουν με δύο τρόπους. Με τρόπο που τα δεδομένα θα μεταφέρονται μέσω 8 Ι/Ο από τον AVR σε αυτό, και με τρόπο που τα δεδομένα θα μεταφέρονται μέσω 4ων I/O. Στην συντριπτική πλειοψηφία των περιπτώσεων διαλέγουμε τον τρόπο των 4 I/O για να περισσέψουν I/O για άλλες χρήσεις. Ακολουθεί ένας σχετικά απλός κώδικας για το HD44780 σε λειτουργία 4-bit (I/O).

Το πρόγραμμα αποτελείτε από τρία αρχεία. Το main.c που περιέχει το κυρίως πρόγραμμα το lcd.h που περιέχει τις δηλώσεις για τον έλεγχο του LCD και το lcd.c που περιέχει το κυρίως πρόγραμμα για τον έλεγχο του LCD. Πρέπει να σημειωθεί πως υπάρχουν καλύτερες βιβλιοθήκες από την παρακάτω που προσφέρουν περισσότερες επιλογές. Για παράδειγμα υποστήριξη ανάγνωσης αλφαριθμητικών από την μνήμη flash (lcd_puts_P), υποστήριξη ειδικών χαρακτήρων (πχ. Ελληνικούς) κτλ. Μία τέτοια βιβλιοθήκη είναι αυτή του Peter Fleury.

Η βιβλιοθήκη του Peter Fleury.
Peter’s_LCD_lib

Τα αρχεία. lcd.zip

main.c

#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
#include "lcd.h"

/*Η παρακάτω δήλωση ελέγχει αν στον compiler έχουμε βάλει την παράμετρο F_CPU.
  Αν όχι, την περνά. */

#ifndef F_CPU
    #warning "H F_CPU den exei oristei 8a parei thn timh 1000000"
    #define F_CPU 1000000UL  // Use unsigned long (UL)
#endif



int main(void){

    lcd_init();   // Αρχικοποίηση του LCD.

    lcd_clear();  // Καθαρισμός του LCD.


    while(1){

        lcd_data('A');
        _delay_ms(300);

        lcd_data('V');
        _delay_ms(300);

        lcd_data('R');
        _delay_ms(100);

        lcd_data(' ');
        _delay_ms(300);

        lcd_data('L');
        _delay_ms(300);

        lcd_data('C');
        _delay_ms(300);

        lcd_data('D');
        _delay_ms(300);

        lcd_data(' ');
        _delay_ms(100);

        lcd_data('T');
        _delay_ms(300);

        lcd_data('E');
        _delay_ms(300);

        lcd_data('S');
        _delay_ms(300);

        lcd_data('T');
        _delay_ms(1000);

        lcd_setcursor(0,2);
        lcd_str("HD44780 BASED");

        _delay_ms(3000);

        lcd_clear();
        _delay_ms(500);
    };

    return 0;
}

lcd.h

#ifndef LCD_ROUTINES_H
#define LCD_ROUTINES_H



// LCD DB4-DB7 <-->  PORTC Bit PC0-PC3
#define LCD_PORT      PORTC
#define LCD_DDR       DDRC
#define LCD_DB        PC0

// LCD RS      <-->  PORTB Bit PB2     (RS: 1=Data, 0=Command)
#define LCD_RS_PORT   PORTC
#define LCD_RS_DDR    DDRC
#define LCD_RS        PC4

// LCD EN      <-->  PORTB Bit PB0     (EN: 1-παλμός για τα δεδομένα)
#define LCD_E_PORT    PORTC
#define LCD_E_DDR     DDRC
#define LCD_EN        PC5


// Χρόνοι καθυστέρησης LCD (MS=Milliseconds, US=Microseconds)

#define LCD_BOOTUP_MS           15
#define LCD_ENABLE_US           20
#define LCD_WRITEDATA_US        46
#define LCD_COMMAND_US          42

#define LCD_SOFT_RESET_MS1      5
#define LCD_SOFT_RESET_MS2      1
#define LCD_SOFT_RESET_MS3      1
#define LCD_SET_4BITMODE_MS     5

#define LCD_CLEAR_DISPLAY_MS    2
#define LCD_CURSOR_HOME_MS      2


/*
Καθορισμός των διευθύνσεων των γραμμών του LCD.
Οι διευθύνσεις αυτές είναι για LCD 16 χαρακτήρων.
Για διαφορετικό μέγεθος πρέπει να συμβουλευτούμε
την τεκμηρίωση του LCD.
*/

#define LCD_DDADR_LINE1         0x00
#define LCD_DDADR_LINE2         0x40
#define LCD_DDADR_LINE3         0x10
#define LCD_DDADR_LINE4         0x50



// Αρχικοποίηση του LCD. Πρέπει να καλείτε στην αρχή του προγράμματος.
void lcd_init(void);

// Καθαρισμός του LCD.
void lcd_clear(void);

// Τοποθέτηση του κέρσορα στην θέση 0,0.
// Πρώτη σειρά, πρώτος χαρακτήρας.
void lcd_home(void);

// Τοποθέτηση του κέρσορα σε συγκεκριμένη θέση.
void lcd_setcursor(uint8_t x, uint8_t y);

// Επιστέφει τον χαρακτήρα στην τρέχουσα θέση του κέρσορα.
void lcd_data(uint8_t data);

// Τοποθετεί ένα αλφαριθμιτικό στην τρέχουσα
// θέση του κέρσορα.
void lcd_str(const char *data);

// Στέλνει εντολές στο LCD.
void lcd_command(uint8_t data);


// Εντολές και τα ορίσματά τους για το LCD.
// Αποστολή με την συνάρτηση lcd_command.

// Clear Display -------------- 0b00000001
#define LCD_CLEAR_DISPLAY       0x01

// Cursor Home ---------------- 0b0000001x
#define LCD_CURSOR_HOME         0x02

// Set Entry Mode ------------- 0b000001xx
#define LCD_SET_ENTRY           0x04

#define LCD_ENTRY_DECREASE      0x00
#define LCD_ENTRY_INCREASE      0x02
#define LCD_ENTRY_NOSHIFT       0x00
#define LCD_ENTRY_SHIFT         0x01

// Set Display ---------------- 0b00001xxx
#define LCD_SET_DISPLAY         0x08

#define LCD_DISPLAY_OFF         0x00
#define LCD_DISPLAY_ON          0x04
#define LCD_CURSOR_OFF          0x00
#define LCD_CURSOR_ON           0x02
#define LCD_BLINKING_OFF        0x00
#define LCD_BLINKING_ON         0x01

// Set Shift ------------------ 0b0001xxxx
#define LCD_SET_SHIFT           0x10

#define LCD_CURSOR_MOVE         0x00
#define LCD_DISPLAY_SHIFT       0x08
#define LCD_SHIFT_LEFT          0x00
#define LCD_SHIFT_RIGHT         0x04

// Set Function --------------- 0b001xxxxx
#define LCD_SET_FUNCTION        0x20

#define LCD_FUNCTION_4BIT       0x00
#define LCD_FUNCTION_8BIT       0x10
#define LCD_FUNCTION_1LINE      0x00
#define LCD_FUNCTION_2LINE      0x08
#define LCD_FUNCTION_5X7        0x00
#define LCD_FUNCTION_5X10       0x04

#define LCD_SOFT_RESET          0x30

// Set DD RAM Address --------- 0b1xxxxxxx  (Display Data RAM)
#define LCD_SET_DDADR           0x80

#endif

lcd.c

#include <avr/io.h>
#include "lcd.h"
#include <util/delay.h>



// Παραγωγή ενός παλμού για το Enable.
static void lcd_enable( void ){
    LCD_E_PORT |= (1<<LCD_EN);     // Enable σε λογικό 1.
    _delay_us(LCD_ENABLE_US);      // Καθυστέρηση.
    LCD_E_PORT &= ~(1<<LCD_EN);    // Enable σε λογικό 0.
}


// Αποστολή δεδομένων σε λειτουργία 4-bit.
static void lcd_out(uint8_t data){
    data &= 0xF0;                       // Μάσκα στα 4 άνω bit.

    LCD_PORT &= ~(0xF0>>(4-LCD_DB));    // Αφαίρεση μάσκας.
    LCD_PORT |= (data>>(4-LCD_DB));     // Αποστολή των bit.
    lcd_enable();
}


// Αρχικοποίηση του LCD.
void lcd_init( void ){


    LCD_E_DDR |= (1<<LCD_EN);   // To LCD_EN ως έξοδος.
    LCD_RS_DDR |= (1<<LCD_RS);  // To LCD_RS ως έξοδος.

    LCD_DDR |= 0b00001111;      // Τα DB4~DB7 ως έξοδοι.


    // Αναμονή για την εκκίνηση του LCD.
    // Σελίδα 46 της τεκμηρίωσης του HD44780.
    _delay_ms(LCD_BOOTUP_MS);

    // Αποστολή του 000011, και αναμονή.
    // Θα σταλεί 3 φορές.
    // Σελίδα 46 της τεκμηρίωσης του HD44780.
    lcd_out(LCD_SOFT_RESET);
    _delay_ms(LCD_SOFT_RESET_MS1);

    // Αποστολή παλμού στο EN για την εκτέλεση.
    // Δεύτερη εκτέλεση της παραπάνω εντολής
    // και καθυστέρηση > 100 usec.
    lcd_enable();
    _delay_ms(LCD_SOFT_RESET_MS2);

    // Αποστολή παλμού στο EN για την εκτέλεση.
    // Τρίτη εκτέλεση της παραπάνω εντολής
    // και καθυστέρηση > 100 usec.
    lcd_enable();
    _delay_ms(LCD_SOFT_RESET_MS3);

    // Ενεργοποίηση λειτουργίας 4-bit.
    lcd_out(LCD_SET_FUNCTION|LCD_FUNCTION_4BIT);

    _delay_ms(LCD_SET_4BITMODE_MS);

    // Λειτουργία 4-bit, 2 γραμμές, 5x7.
    lcd_command(LCD_SET_FUNCTION|LCD_FUNCTION_4BIT|LCD_FUNCTION_2LINE|LCD_FUNCTION_5X7);

    // LCD 1, απενεργοποίηση κέρσορα, απενεργοποίηση άναψε-σβήσε του _
    lcd_command(LCD_SET_DISPLAY|LCD_DISPLAY_ON|LCD_CURSOR_OFF|LCD_BLINKING_OFF);

    // Αύξηση του κέρσορα, απενεργοποίηση του scrol.
    lcd_command( LCD_SET_ENTRY|LCD_ENTRY_INCREASE|LCD_ENTRY_NOSHIFT);

    // Καθαρισμός της οθόνης.
    lcd_clear();
}


// Αποστολή data στα LCD.
void lcd_data(uint8_t data){

    LCD_RS_PORT |= (1<<LCD_RS);  // RS σε λογικό 1.

    lcd_out(data);          // Αποστολή των 4ων άνω bit.
    lcd_out(data<<4 );      // Αποστολή των επόμενων 4 bit.

    _delay_us(LCD_WRITEDATA_US); // Καθυστέρηση.
}


// Αποστολή εντολών στο LCD.
void lcd_command(uint8_t data){

    LCD_RS_PORT &= ~(1<<LCD_RS); // RS σε λογικό 0.

    lcd_out(data);      // Αποστολή των 4ων άνω bit.
    lcd_out(data<<4);   // Αποστολή των επόμενων 4 bit.

    _delay_us(LCD_COMMAND_US); // Καθυστέρηση.
}


// Εντολή καθαρισμού του LCD.
void lcd_clear(void){
    // Σελίδα 24 της τεκμηρίωσης του HD44780.
    lcd_command(LCD_CLEAR_DISPLAY );
    _delay_ms(LCD_CLEAR_DISPLAY_MS);
}


// Εντολή για επιστροφή του κέρσορα
// στην αρχική θέση.
void lcd_home(void){
    // Σελίδα 24 της τεκμηρίωσης του HD44780.
    lcd_command(LCD_CURSOR_HOME);
    _delay_ms(LCD_CURSOR_HOME_MS);
}


// Εντολή για συγκεκριμένη θέση του κέρσορα.
void lcd_setcursor( uint8_t x, uint8_t y ){

    uint8_t data;

    switch (y)
    {
        case 1:    // 1η γραμμή.
            data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
            break;

        case 2:    // 2η γραμμή.
            data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
            break;

        case 3:    // 3η γραμμή.
            data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
            break;

        case 4:    // 4η γραμμή.
            data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
            break;

        default:
            return;   // Εδώ αποφεύγουμε ακατάλληλη τιμή γραμμής.
    }

    lcd_command(data);
}


// Αποστολή αλφαριθμιτικού στο LCD.
void lcd_str(const char *data){

    while( *data != '\0' )
        lcd_data( *data++ );
}

Advertisements
This entry was posted in AVR, Electronics and tagged , , , , , . Bookmark the permalink.

2 Responses to AVR-GCC. HD44780 LCDs.

  1. Pingback: AVR-GCC. Αρχεία Makefile. | My humble Blog.

  2. Pingback: AVR-GCC. 7-Segment Displays. | My humble Blog.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s