domingo, 16 de octubre de 2016

No se muestran correctamente los mensajes en el LCD o puerto serie


Desafortunadamente MikroC (PIC16Fxxxx) al momento de introducir textos para mostrarlos en LCD ej: lcd_out(1,1,”texto1”); o puerto serie ej: uart1_write_text(“texto1”);  la constante “texto1” se almacena en la ram del uC y solamente muestra correctamente aquellos que el compilador aloja en los bancos 0 y 1 de modo que si se tienen varios mensajes y estos son situados en los bancos 2 y 3 no se muestran correctamente.
Ejemplo 1.
sbit LCD_RS at RB2_bit;   sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;   sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;sbit LCD_D7 at RB7_bit;
sbit LCD_RS_Direction at TRISB2_bit;   sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;   sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;   sbit LCD_D7_Direction at TRISB7_bit;
void main()
{
   uart1_init(19200);   //velocidad del puerto serie 19200bps
   lcd_init();
   while(1)
   {
      lcd_out(1,1,"1234546789ABCDEF");
      lcd_out(2,1,"FEDCBA9876543210");
      uart1_write_text("1234567890abcdefghijk\r\n");
      uart1_write_text("1234567890abcdefghijk\r\n");
      uart1_write_text("1234567890abcdefghijk\r\n");
      uart1_write_text("1234567890abcdefghijk\r\n");
      uart1_write_text("1234567890abcdefghijk\r\n");
   }
}
En proteus tenemos.

Se puede observar que el segundo mensaje del lcd (“FEDCBA9876543210”) no es mostrado correctamente y es porque se encuentra situado en el banco 3 de la memoria ram.
Ejemplo 2.
sbit LCD_RS at RB2_bit; sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit; sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit; sbit LCD_D7 at RB7_bit;
sbit LCD_RS_Direction at TRISB2_bit; sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit; sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit; sbit LCD_D7_Direction at TRISB7_bit;
void main()
{
   uart1_init(19200);   //velocidad del puerto serie 19200bps
   lcd_init();
   while(1)
   {
      lcd_out(1,1,"1234546789ABCDEF");
      lcd_out(2,1,"FEDCBA9876543210");
      uart1_write_text("1234567890abcdefghijk\r\n");
      uart1_write_text("1234567890abcdefghijk\r\n");
      uart1_write_text("1234567890abcdefghijk\r\n");
      uart1_write_text("1234567890abcdefghijk\r\n");
      uart1_write_text("1234567890abcdefghijk\r\n");
      uart1_write_text("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n");
      uart1_write_text("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n");
      uart1_write_text("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n");
      uart1_write_text("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n");
      uart1_write_text("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n");
      uart1_write_text("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n");
   }
}
Aquí se observa que el compilador no informa que el microcontrolador no tiene suficiente memoria ram.
Esta situación nos limita bastante si queremos hacer un programa que contenga varios mensajes, pero a grandes problemas, grandes soluciones.
En este caso la solución está en crear una función que obliga al compilador a que nuestros mensajes sean situados en la rom y que se pasen a la ram solo cuando queramos mostrarlos.
Ejemplo 3.
char *const_ram(const char *msg)
{
   static char msg_ram[30];//reserva 30 bytes en la ram para mostrar los mensajes
   unsigned short n;
   for(n=0;*msg!=0;msg_ram[n++]=*msg++);
   return msg_ram;
}
void main()
{
   uart1_init(19200);   //velocidad del puerto serie 19200bps
   lcd_init();
   while(1)
   {
      lcd_out(1,1,const_ram("1234546789ABCDEF"));
      lcd_out(2,1,const_ram("FEDCBA9876543210"));
      uart1_write_text(const_ram("1234567890abcdefghijk\r\n"));
      uart1_write_text(const_ram("1234567890abcdefghijk\r\n"));
      uart1_write_text(const_ram("1234567890abcdefghijk\r\n"));
      uart1_write_text(const_ram("1234567890abcdefghijk\r\n"));
      uart1_write_text(const_ram("1234567890abcdefghijk\r\n"));
      uart1_write_text(const_ram("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"));
      uart1_write_text(const_ram("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"));
      uart1_write_text(const_ram("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"));
      uart1_write_text(const_ram("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"));
      uart1_write_text(const_ram("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"));
      uart1_write_text(const_ram("ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"));
   }
}
Gracias a la función const_ram() y a los punteros logáramos que los mensajes se muestren correctamente sin un excesivo uso de memoria ram.

Variables automáticas y estáticas (MikroC)


Variables automáticas, son aquellas variables que mantienen su valor durante la ejecución del código de la función en la que han sido creadas, cuando termina la función los valores de estas variables se pierden. Estas variables son creadas por defecto sin la necesidad de usar la palabra reservada auto. Ejemplo.

unsigned short variable;

Variables estáticas, son aquellas variables que mantienes su valor durante y después de que se ejecute el código de la función en la que fueron creadas, esto significa que después de que la función termina esta variable sigue conservando su valor. Para declararla es necesario usar la palabra reservada static. Cuando se crea una variable de tipo estática esta empieza con el valor cero por defecto. Ejemplo.

static unsigned short variable;

Ejemplo 1.

unsigned short motor_paso()

{

   const char motor_p_simple[]={1,2,4,8};   //constante local

   static unsigned short paso;                                     //variable local estática

   return motor_p_simple[(paso++)&0x03];

}

void leer_temperatura()

{

   unsigned short temperatura;          //variable local automática

   char display_txt[4];                        //variable vector local automática

   temperatura=(5.0/1024.0)*(100.0)*adc_read(0);//ajuste de escala para el lm35

   if(temperatura>99){temperatura=99;}

   bytetostr(temperatura,display_txt);

   portb=((display_txt[2]&(0x0f))<<4)|(display_txt[1]&0x0f);

}

void main()

{

   portd=0;portb=0;

   trisd=0;trisb=0;

   while(1)

   {

      leer_temperatura();

      portd=motor_paso();

      delay_ms(100);

   }

}

Ámbito de las variables (MikroC).


Hablemos un poco del ámbito de las variables.

Variables globales son aquellas a las que se puede acceder desde cualquier parte del programa y desde cualquier subrutina, función o interrupción, estas variables están presentes durante toda la ejecución del programa.
Variables locales son aquellas a las que se pueden acceder solamente en la subrutina, función o interrupción en donde se las creo, estas variables son creadas al inicio de la rutina y destruidas al terminarla.
 Elegir correctamente el ámbito de las variables ayuda a optimizar el manejo de la memoria ram del uC.
Las variables locales al existir solamente en la rutina donde fueron creadas dan la posibilidad de reusar el espacio de ram que usan en distintas rutinas mientras que las variables globales siempre están presentes y el espacio que ocupan en la ram no se libera hasta que termine el programa.
Ejemplo 1.
void main()
{
   unsigned short contador;   //variable local
   portd=0;
   trisd=0;                   //puerto D como salida
   while(1)
   {
      for(contador=0;contador<10;contador++)
      {
         portd=contador;
         delay_ms(500);
      }
   }
}
 
Ejemplo 2.
unsigned short n=0;                           //variable global
void contador_display()
{
   unsigned short estado_entrada;      //variable local
   estado_entrada=portb.rc0;
   if(estado_entrada==0)
   {
      if(n>9){n=0;}
      portd=n;
   }
}
void main()
{
   unsigned short i=1;                         //variable local
   option_reg.not_rbpu=0;                 //pull-up del puerto b habilitado
   portc=0;
   portd=0;
   trisc=0;                                           //puerto C como salida
   trisd=0;                                           //puerto D como salida
   while(1)
   {
      contador_display();
      n++;
      portc=i;
      if((i=i*2)==0)
      {
         i=1;
      }
      delay_ms(500);
   }
}


lunes, 10 de octubre de 2016

Generando archivos *.cof en MikroC Pro PIC

Iniciando este blog con publicaciones hechas antes en el grupo de Facebook: De Electrónica para electrónicos.
Esta serie de artículos recogen las eventualidades con la que me encontré mientras hacia proyectos con microcontroladores PIC utilizando el compilador MickroC.

1.      Consejo: Generar el archivo de depuración *.cof.
Quizá muchos sepan cómo depurar código mediante el archivo *.cof que genera MikroC Pro PIC pero no esta demás mostrar cómo se usa.
Una vez abierto MikroC Pro PIC ir a la pestaña Tools y seleccionar la opción options

Luego en la pestaña Output seleccionar la opción Generate COFF file luego presionar los botones Apply y OK.
Una vez hecho y después de compilar se generara el archivo *.hex y el *.cof, este último archivo también puede ser cargado a PROTEUS para efectuar depuración de código en la simulación.

Cargado el archivo *cof a PROTEUS.


Ya se puede efectuar la simulación y cuando se presiona el botón de pause ya podremos ver el código para ejecutarlo paso a paso.

... Eso es todo un saludo y hasta la próxima que estemos viendo algo sobre el ámbito de las variables.