Sending string to lcd, PIC16F

2008-11-24
2013-03-12
  • santiago glez
    santiago glez
    2008-11-24

    I try to send an string to 44780 lcd, with pic16f876a; only writes the first character of the string, if i send character by character all ok, but looks that fails to do the pointer to string work, i tried with this variants:

    void lprintf( char *frase )
    {
        char *c;
          for (c=frase; *c; c++)
           {
            send_dato(*c);               //send byte to lcd
        }
    }

    void lprintf( char *frase )
    {
        while ( *frase )
        {

            send_dato( *frase ) ;                //send byte to lcd

            frase++ ; 
        }

    }

    void lprintf( const char *frase )
    {
        char c, n = 0;

        while( *frase )
        {
            c = frase[n];

            send_dato( c );                 //send byte to lcd
        }
    }

    to call the fuctcion i just do:

             lprintf("abcde")

    All compile ok and the pic+lcd run ok except it only prints only the firs character of the string.
    What i'm doing wrong?

    I see in the generted asm that there is a call to external function (if this can help):

    ; >>> gen.c:1839:call_libraryfunc
        CALL    __gptrget1

    Any help will be apreciated. Thank you.

     
    • I would guess that the PIC is sending the characters much too quickly. Check the 44780 data sheet to see how much delay it needs between characters.

       
    • santiago glez
      santiago glez
      2008-11-24

      Hello Oliver... Thanks for the fast reply...

      I forgot in previous post, sdcc -v:
      SDCC : mcs51/gbz80/z80/avr/ds390/pic16/pic14/TININative/xa51/ds400/hc08 2.7.0 #4818 (Jan 18 2008) (UNIX)

      I'm using "wait for not busy" for write byte to lcd, anyway i already try with several delays with and without "wait for not busy", and have same results.
      for example:

      lprintf("a"); lprintf("b"); lprintf("c"); lprintf("d");

      works ok.

      What i try is to make an lcd driver for pic16f, and wors ok for one character write  and for numbers write, but i would like to have an string write function.

      It's not finished yet but this is the code, if someone have any ideas they are wellcome:

      /*****************************************************************************
      ******************************************************************************
      ****                                                                      ****
      ****                 --- DRIVER LDC 4BITS para PIC16F ---                 ****
      ****                                                                      ****
      ******************************************************************************
      ******************************************************************************

              EN EL PROGRAMA PRINCIPAL DONDE VAYA A USAR LAS FUNCIONES LCD
      INSERTAR LAS SIGUIENTES LINEAS CON LAS DEFINICIONES DE PUERTO Y RELOJ USADOS:

      //---------------------------- PUERTO LCD --------------------------------
      //------------------------------------------------------------------------

      #define RS RC1            //PIN PARA RS.
      #define RW RC2            //PIN PARA RW.
      #define EN RC3            //PIN PARA ENABLE.
      #define DATOT TRISC        //TRIS DE DATOS, PINES 4, 5, 6, 7 DEL PUERTO.
      #define DATOP PORTC        //PORT DE DATOS, MISMO PUERTO.

      #define FREQ 8000        // 8000 KHz = 8 Mhz  , LA FRECUENCIA EN KHz.

      #include <lcd_sdcc_sgr.h>

      ********************************************************************************
      *******************************************************************************/

      //----------------------------- ACCIONES ---------------------------------
      //------------------------------------------------------------------------
      #define write  RW = 0; pausa(coms); DATOT &= 0x0F; pausa(coms)
      #define read   DATOT |= 0xF0; pausa(coms); RW = 1; pausa(coms)
      #define EN0 EN = 0; pausa(coms)
      #define EN1 EN = 1; pausa(coms)

      //--------------------------- COMANDOS LCD -------------------------------
      //------------------------------------------------------------------------
      #define clear                 0x01 // Clear Display
      #define home               0x02 // Cursor a Home
      #define normal            0x06 // Normal
      #define rev            0x04 // Normal-reverse
      #define scroll             0x07 // con scroll
      #define scroll_rev        0x05 // Reverse
      #define d8_bit            0x38 // 8 bit 2 lineas ( 5x7 font )
      #define d4_bit            0x28 // 4 bit 2 lineas ( 5x7 font )
      #define reset            0x30 // Reset
      #define dis_on                0x0C // Display on modo 2 lineas
      #define dis_off               0x08 // Display off
      #define linea1              0x80 // Linea 1 posicion 1
      #define linea2              0xC0 // Line 2 posicion 1
      #define cursor_on             0x0E // Cursor on
      #define cursor_off            0x0C // Cursor off
      #define blink_on           0x0F // Cursor blink
      #define cursor_der        0x14 // Mover cursor derecha
      #define cursor_izq         0x10 // Mover cursor izquierda
      #define display__der        0x1C // Scroll display derecha
      #define display__izq        0x18 // Scroll display izquierda

      //----------------------- CONFIGURAR VARIABLES ---------------------------
      //------------------------------------------------------------------------
      unsigned char d;
      unsigned int coms = FREQ / 4000;
      unsigned int pa = FREQ / 400;

      void pausa( char a )           
      {     a;                //tiempo = ( 4a + 1 )µs   a>=2, para 4MHz
          _asm                 // "a" ya está en w
          sublw 1    
          bucle:
          addlw 1
          btfss STATUS,0
          goto bucle
          _endasm;
      }

      void espera_ms( unsigned int ms )
      {
          ms = ms * coms;
          while (ms > 0 )
          {
              pausa(247);
              ms--;
          }
      }

      char lcd_read()
      {
          read;                //modo lectura #definido
         
          EN1;                //Enable = 1; pausa #definido
          d = DATOP & 0xF0;        //lee nibble alto
          EN0;                //Enable = 0; pausa #definido
         
          EN1;
          d |= DATOP >> 4;        //lee nibble bajo
          EN0;
         
          return d;
      }
         
      char lcd_busy()
      {
          RS = 0;
          lcd_read();
         
          d = d & 0x80;            //aisla bit busy
         
          if( d == 0x80 )         //comprueba si está ocupado
              return(1);
          else   
              return(0);
      }   

      void write_n( char dat )
      {
          write;                //modo escritura #definido
         
          DATOP &= 0x0F;
          DATOP |= dat & 0xF0;        //escribe nibble alto
          EN1;
          EN0;
         
          dat <<= 4;
         
          DATOP &= 0x0F;
          DATOP |= dat & 0xF0;        //escribe nibble bajo
          EN1;
          EN0;
          pausa(pa);
      }

      void send_dato( char dato )
      {
          //while( lcd_busy() == 1 );    //leer bit busy hasta que sea 0
          RS = 1;                //modo datos
          write_n( dato );
      }

      void send_comand( char comand )
      {
          RS = 0;                //modo comandos
          write_n( comand );
      }

      void lcd_clear()
      {
          send_comand( clear );
          send_comand( home );
      }

      void lcd_init( void )
      {
          DATOT = 0;            //todo a salidas
          DATOP = 0;            //todo a 0
          espera_ms(20);
          write_n( reset );        //secuancia de reset
          espera_ms(10);
          write_n( reset );
          pausa(50);
          write_n( reset );
          pausa(5);            //secuencia de inicio:
          send_comand( d4_bit );        //0x28 modo 4 bits 2 lineas
          send_comand( normal );        //0x06 entrada normal hacia adelante
          send_comand( dis_on );        //0x0c display on
          send_comand( linea1 );        //0x80 linea 1 posicion 1
      }

      void cal_as( char ca )
      {
          if (ca > 9)
              ca += 55;
          else
              ca += 48;
          send_dato(ca);
      }

      void cal_byte( char cb )
      {
          char n;
          n = ( cb >> 4 ) & 0x0f;
          cal_as(n);
          n = cb & 0x0f;
          cal_as(n);
      }

      void send_num( int num )
      {
          cal_byte( num >> 8 );
          cal_byte( num & 0xff );
      }

      void lprintf( char *frase )
      {
      while ( *frase ) 
      {

      send_dato( *frase ) ; 

      frase++ ; 
      }

       
      • Are you sure that the "wait for not busy" work?

         
    • santiago glez
      santiago glez
      2008-11-25

      i think the problem is when i try to use an array declared in main function in other function (lprintf).

      For example this code works ok:

      void main()
      {   
          unsigned char a[] = "hello";

          lcd_init();

          char n = 0;

          while( a[n] )
          {
              send_dato( a[n] );         //send byte to lcd
              n++;
          }
      while(1);
      }
      -----------------------------------------------------------------------------

      but this doesn't work correctly, it just write first character of array:

      void lprintf( unsigned char *frase )
      {
          char n = 0;

          while( frase[n] )
          {
              send_dato( frase[n] );        //send byte to lcd
              n++;
          }
      }

      void main()
      {   
          unsigned char a[] = "hola";

          lcd_init();

          lprintf(a)

      while(1);
      }
      ------------------------------------------------------------------------------

      and if i try to declare a[] as global (outside main) i have this error:

      glue.c:936: emitInitVal: Assertion `!"Initialized char-arrays are not yet supported, assign at runtime instead."' failed.

      Is there any chance to do this any other way?

      thanks... and over all thanks to people who is porting sdcc to pic mcus!!

      Greatings.

       
    • santiago glez
      santiago glez
      2008-11-26

      Hi Oliver.. may be you didn'n see my last post... i don't know why it's in the 3º position.. i talked about declaring a global char array...
      I think all functions work ok, for example this code works ok:

      void main() 

      unsigned char a[] = "hello";

      lcd_init();

      char n = 0;

      while( a[n] )
      {
      send_dato( a[n] ); //send byte to lcd
      n++;
      }
      while(1);
      }

      thanks...