Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Ricerca personalizzata

Comandare l' HD44780U con il PIC32

Raccolta di codici sorgenti

Moderatore: Foto UtentePaolino

6
voti

[1] Comandare l' HD44780U con il PIC32

Messaggioda Foto UtenteTardoFreak » 13 lug 2010, 17:25

Visto che questa sezione dovrebbe essere anche una raccolta di software posto il sorgente in C delle funzioni che ho scritto e provato per gestire il famoso controller di displays alfanumerici.
Il software funziona ma e' stato buttato giu' di getto ed ha bisogno di una bella cura di bellezza, infatti mancano tutti i prototipi che, di solito metto quando ho la certezza che tutto funzioni. :mrgreen:
Comunque spero di far cosa gradita, anche solo come curiosita', nel metterlo qui di seguito.
Codice: Seleziona tutto
#include "mpu_config.h"
#include "app_defs.h"
#include <plib.h>
#include <p32xxxx.h>

#define SYS_FREQ    (80000000)
#define SYS_FREQ_KHZ   (80000)

// defines per l' assegnazione dei pin di uscita per il comando del modulo LCD
#define LCD_EN     LATEbits.LATE4
#define LCD_EN_DIR TRISEbits.TRISE4

#define LCD_RS     LATEbits.LATE5
#define LCD_RS_DIR TRISEbits.TRISE5

#define LCD_D4     LATEbits.LATE0
#define LCD_D4_DIR TRISEbits.TRISE0

#define LCD_D5     LATEbits.LATE1
#define LCD_D5_DIR TRISEbits.TRISE1

#define LCD_D6     LATEbits.LATE2
#define LCD_D6_DIR TRISEbits.TRISE2

#define LCD_D7     LATEbits.LATE3
#define LCD_D7_DIR TRISEbits.TRISE3

short lcd_curs_pos_x;      // posizione x attuale del cursore
short lcd_curs_pos_y;      // posizione y attuale del cursore
short lcd_size_x;          // numero di caratteri per riga
short lcd_size_y;          // numero di righe del display
short lcd_hardware_lines;  // numero di linee hardware gestite dal controllore
char lcd_screen[80];       // array che contiene l'immagine del display
int lcd_chr_delay;         // ritardo in millisecondi per l' invio di stringhe


/*****************************************************************************/
/* delay_ms                                                                  */
/*     This functions provides a software millisecond delay. It uses the     */
/*     core timer.                                                           */
/*****************************************************************************/
void delay_ms(unsigned int msec)
{
  unsigned int tWait, tStart;
      
  tWait=(SYS_FREQ/2000)*msec;
  tStart=ReadCoreTimer();
  while((ReadCoreTimer()-tStart)<tWait);      // wait for the time to pass
}

/*****************************************************************************/
/* delay_us                                                                  */
/*     This functions provides a software microsecond delay. It uses the     */
/*     core timer.                                                           */
/*****************************************************************************/
void delay_us(unsigned int usec)
{
  unsigned int tWait, tStart;
      
  tWait=(SYS_FREQ_KHZ/2000)*usec;
  tStart=ReadCoreTimer();
  while((ReadCoreTimer()-tStart)<tWait);      // wait for the time to pass
}

/*****************************************************************************/
/*  lcd_send digit, lcd_send_byte                                            */
/*      Funzioni interne per l' invio di un digit e di un byte               */
/*****************************************************************************/
void lcd_send_digit(unsigned char n)
{
  delay_us(1);  // dovrebbe essere di 10ns 
  n &= 0x0f;
  LCD_EN = 1;
 
  // mette il digit un bit alla volta nei pin D4-D7
 
  if (n & 1) LCD_D4 = 1; else LCD_D4 = 0;
  if (n & 2) LCD_D5 = 1; else LCD_D5 = 0;
  if (n & 4) LCD_D6 = 1; else LCD_D6 = 0;
  if (n & 8) LCD_D7 = 1; else LCD_D7 = 0;
 
  delay_us(1);  // dovrebbe essere di 80 ns.
  LCD_EN = 0;
}

void lcd_send_byte(unsigned char n)
{
  lcd_send_digit(n>>4);
  lcd_send_digit(n);
}

/*****************************************************************************/
/*  lcd_send_cmd                                                             */
/*      Invia un byte al controllore come comando. Il comando verra' esguito */
/*****************************************************************************/
void lcd_send_cmd(unsigned char n)
{
  LCD_RS = 0;  // essendo un comando la linea RS va a 0
  delay_us(1); 
  lcd_send_byte(n);
 
  // Ritarda per attendere la completa esecuzione del comando
  // questi ritardi sono piu' lunghi di quelli indicati nel datasheet.
  // dovrebbero essere di 1520 e 37 us.
  if (!(n & 0xfc)) delay_us(1600); else delay_us(40);
}

/*****************************************************************************/
/*  lcd_send_data                                                            */
/*      Invia un byte al controllore come dato. Il dato verra' memorizzato   */
/*      nella memoria grafica                                                */
/*****************************************************************************/
void lcd_send_data(unsigned char n)
{
  LCD_RS = 1;  // essendo un dato la linea RS va a 1
  delay_us(1);   
  lcd_send_byte(n);
 
  // Ritarda per attendere la completa esecuzione del comando
  // anche questo ritardo dovrebbe essere di 37us
  delay_us(40);
}

/*****************************************************************************/
/*  lcd_init                                                                 */
/*      Inizializza il display. sx ed sy sono le dimensioni del display      */
/*      nl e' il numero di linee hardware di cui e' composto il display      */
/*****************************************************************************/
void lcd_init(short sx, short sy, short nl)
{
 
  // inizializza le linee di uscita
  LCD_EN_DIR = 0;
  LCD_EN = 0;
 
  LCD_RS_DIR = 0;
  LCD_RS = 0;
 
  LCD_D4_DIR = 0;
  LCD_D4 = 0;
 
  LCD_D5_DIR = 0;
  LCD_D5 = 0;
 
  LCD_D6_DIR = 0;
  LCD_D6 = 0;
 
  LCD_D7_DIR = 0;
  LCD_D7 = 0; 
 
  delay_ms(15);        // aspetta 15ms per stabilizzazione Vcc
 
  // esegue la sequenza di reset, quella che si usa in caso di alimentazione
  // che non garantisce un buon reset interno.
 
  LATEbits.LATE5 = 0;  // mette RS a 0
  lcd_send_digit(0x03);
  delay_ms(5);         // sul datasheet e' indicato 4,1 ms
 
  lcd_send_digit(0x03);
  delay_us(120);       // il datasheet indica > 100 us.
 
  lcd_send_digit(0x03);
  delay_us(120);
 
  lcd_send_digit(0x02);
  delay_us(120);
 
  lcd_send_cmd(0x28); //0x20 per una linea
  lcd_send_cmd(0x08);
  lcd_send_cmd(0x01);
  lcd_send_cmd(0x06);
  lcd_send_cmd(0x28); //0x20 per una linea
  lcd_send_cmd(0x0d); // lcd acceso e cursore lampeggiante senza cursore a linea
 
  // aggiorna le variabili
  lcd_curs_pos_x = lcd_curs_pos_y = 0;
  lcd_size_x = sx;
  lcd_size_y = sy;
  lcd_hardware_lines = nl;
  lcd_chr_delay = 0;
}

/*****************************************************************************/
/*  lcd_clear                                                                */
/*      invia il comando di cancellazione del display e riporta a 0 tutti i  */
/*      caratteri del buffer immagine dell schermo                           */
/*****************************************************************************/
void lcd_clear(void)
{
  short i;
 
  lcd_send_cmd(0x01);
  lcd_curs_pos_x = 0;
  lcd_curs_pos_y = 0;
  for (i=0; i<80; i++) lcd_screen[i] = 0x10;
}

#define lcd_cursor_off() lcd_send_cmd(0x0c);
#define lcd_cursor_on() lcd_send_cmd(0x0d);

/*****************************************************************************/
/*  lcd_gotoxy                                                               */
/*      Posiziona il cursone alle coordinate indicate. L' angolo superiore   */
/*      sinistro ha come coordinate 0,0                                      */
/*****************************************************************************/
void lcd_gotoxy(short x, short y)
{
  unsigned char ind;
 
  if (lcd_hardware_lines == 2)
  switch(y)
  {
    case 0: ind = x;
      break;
    case 1: ind = x + 0x40;
      break;
    case 2: ind = x + lcd_size_x;
      break;
    case 3: ind = x + lcd_size_x + 0x40;
      break;
  }
  else
  {
    ind = x + y * lcd_size_x;
  }
  ind |= 0x80;
  lcd_send_cmd(ind);
  lcd_curs_pos_x = x;
  lcd_curs_pos_y = y;
}

/*****************************************************************************/
/*  lcd_curs_nextch                                                          */
/*      Aggiorna la posizione del cursore sul display dopo che e' stato      */
/*      to un carattere. Gestisce il ritorno a capo                          */
/*****************************************************************************/
void lcd_curs_nextch(void)
{
  short x,y,i;
 
  lcd_curs_pos_x++;
  if ((lcd_curs_pos_x == lcd_size_x) && (lcd_curs_pos_y == (lcd_size_y -1)))
  {
    // fa lo scroll dello schermo
    for ( i=0 ; i<((lcd_size_y-1)*lcd_size_x); i++)
    {
      lcd_screen[i] = lcd_screen[i+lcd_size_x];  //  memorizza i caratteri nel buffer
    }
    lcd_send_cmd(0x01);
    i = 0;
    for (y=0;y<(lcd_size_y-1);y++)
      for (x=0;x<lcd_size_x;x++)
      {
        lcd_gotoxy(x,y);
        lcd_send_data(lcd_screen[i]);
        i++;
      }
   
   
    lcd_gotoxy(0,lcd_size_y-1);
  }
  else // non deve fare lo scroll
  {
    if (!(lcd_curs_pos_x % lcd_size_x) && lcd_curs_pos_x)
    {
      lcd_curs_pos_y++;
      if (lcd_curs_pos_y == lcd_size_y) lcd_gotoxy(0,0); else lcd_gotoxy(0,lcd_curs_pos_y);
    }
  }
}

/*****************************************************************************/
/*  lcd_screen_update                                                        */
/*      Funzione di aggiornamento dell' immagine dello schermo               */
/*****************************************************************************/
void lcd_screen_update(char c)
{
  lcd_screen[lcd_curs_pos_x + lcd_curs_pos_y * lcd_size_x] = c;
}

/*****************************************************************************/
/*  lcd_write_char                                                           */
/*      Scrive un carattere, aggiorna l' immagine dello schermo e non        */
/*      introduce nessun ritardo di visualizzazione                          */
/*****************************************************************************/
void lcd_write_char(char c)
{
  lcd_send_data(c);
  lcd_screen_update(c);
  lcd_curs_nextch();
}

/*****************************************************************************/
/*  lcd_write_text                                                           */
/*      Scrive la stringa a partire dalla posizione attuale del cursore      */
/*****************************************************************************/
void lcd_write_text(char *s)
{
  while(*s)
  {
    lcd_send_data(*s);
    lcd_screen_update(*s);
    s++;
    if (lcd_chr_delay) delay_ms(lcd_chr_delay);
    lcd_curs_nextch();   
  }
}

/*****************************************************************************/
/*  main                                                                     */
/*****************************************************************************/
int main(void)
{
  int i;
 
  // KEY CONCEPT - Configure the device for maximum performance, but do not change the PBDIV clock divisor.
   // Given the options, this function will change the program Flash wait states,
   // RAM wait state and enable prefetch cache, but will not change the PBDIV.
  // The PBDIV value is already set via the pragma FPBDIV option above.
  SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
 
  lcd_init(20,4,2);
  lcd_chr_delay = 50;
 
  lcd_clear();
  lcd_cursor_off();
  lcd_gotoxy(0,0);
  lcd_write_text("prova di LCD per valutare il ritorno a capo automatico e scroll.");
  lcd_write_text("DURANTE IL MAIUSCOLO DEVE EFFETTUARE LO SCROLLING");
  lcd_clear();
  lcd_gotoxy(0,3);
  lcd_write_text("Ulteriore prova per verificare lo scrolling");

  while(1)
  {
  }
 
  return (0);
}
Nel data sheet si trova tutto. Anche gli errori.
"La follia sta nel fare sempre la stessa cosa aspettandosi risultati diversi".
"Parla soltanto quando sei sicuro che quello che dirai è più bello del silenzio".
PIERIN-PIC18
Avatar utente
Foto UtenteTardoFreak
71,3k 8 12 13
G.Master EY
G.Master EY
 
Messaggi: 15601
Iscritto il: 16 dic 2009, 10:10
Località: Torino - 3° pianeta del Sistema Solare

0
voti

[2] Re: Comandare l' HD44780U con il PIC32

Messaggioda Foto UtentePaolino » 16 lug 2010, 10:44

Cosa graditissima. Aggiungo che il driver non è difficile da portare su altre piattaforme, soprattutto per chi conosce il C.
Grazie!

Ciao.

Paolo
"Houston, Tranquillity Base here. The Eagle has landed." - Neil A.Armstrong

-------------------------------------------------------------

PIC Experience - http://www.picexperience.it
Avatar utente
Foto UtentePaolino
31,4k 8 12 13
G.Master EY
G.Master EY
 
Messaggi: 4129
Iscritto il: 20 gen 2006, 10:42
Località: Vigevano (PV)

1
voti

[3] Re: Comandare l' HD44780U con il PIC32

Messaggioda Foto UtenteTardoFreak » 16 lug 2010, 11:02

Sull' onda dell' entusiasmo, come si puo' vedere dal listato, ho implementato anche la funzione di scroll (con il buffer in ram) e la possibilita' di rallentare la visualizzazione delle stringhe per dare l' idea del terminale. 8)
Vabbe', mi andava di giocare un po'. :mrgreen: :mrgreen: :mrgreen:
Nel data sheet si trova tutto. Anche gli errori.
"La follia sta nel fare sempre la stessa cosa aspettandosi risultati diversi".
"Parla soltanto quando sei sicuro che quello che dirai è più bello del silenzio".
PIERIN-PIC18
Avatar utente
Foto UtenteTardoFreak
71,3k 8 12 13
G.Master EY
G.Master EY
 
Messaggi: 15601
Iscritto il: 16 dic 2009, 10:10
Località: Torino - 3° pianeta del Sistema Solare


Torna a Firmware e programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 5 ospiti