Contenido>Indice>Intro CursoC51

VARIABLES EN C51



Tipos de datos

Los tipos de datos admitidos por C51 son:

TIPO           TAMAÑO         RANGO DE VALORES
bit           = 1 bit         0 ó 1
char          = 8 bits        -128 a +127
unsigned char = 8 bits        0 a 255  
int           = 16 bits       -32768 a +32767
unsigned int  = 16 bits       0 a 65535
long          = 32 bits       -2147483648 a +2147483647
unsigned long = 32 bits       0 a 4294967295
float         = 32 bits       +/-1.175494E-38 a +/-3.402823E+38
puntero       = 24/16/8 bits  Dirección de una variable

Son declaraciones típicas las siguientes:
    unsigned char xdata tensión_batería ;
    int idata factor_de_corrección ;
    bit flag_1 ;

(Nota: las variables bit siempre residen en el área de memoria 'bdata' direccionable a nivel de bit del  8051 - véase capitulo 2 "Localización física de los espacios de memoria")

Para un procesador como el 8086, el tipo int es el más común, ya que al tratarse de un procesador de 16 bits, obtiene el máximo de eficiencia cuando trabaja con valores de 16 bits. Sin embargo, con el 8051, el tipo de dato a utilizar debe ser lógicamente el char. Por otro lado, ya que el 8051 no dispone de instrucciones para la aritmética con signo, es conveniente trabajar, siempre que ello sea posible, con tipos unsigned en lugar de con tipos signed. Si no se siguen estas reglas, los programas resultantes tendrán mayor tamaño y funcionarán con mayor lentitud.

El µC Siemens 80C537 dispone de un co-procesador matemático integrado, que le permite realizar instrucciones con números enteros y operaciones complejas como la división de un número de 32 bits, entre un número de 16 bits. El compilador Keil C51 dispone de una librería específica para el 80C537 que saca partido de las características especiales de este procesador.

Bits de funciones especiales

El programador en lenguaje ensamblador del 8051, encuentra que el lenguaje ANSI C no le ofrece facilidades para operar con los bits del área BDATA, y le obliga a trabajar con máscaras para comprobar el estado de los bits. Sin embargo, el compilador C51 permite ubicar variables en el área de RAM interna de acceso a nivel de bit y a nivel de byte, y manejar directamente desde C las instrucciones de manipulación de bits del 8051.

Veamos como ejemplo la comprobación del bit de signo de un char.

En primer lugar, se fuerza la residencia del char en el área "bdata":

    char bdata test ;

el bit de signo se define como sigue:

      sbit signo = test ^ 7   ;

Y se usa así:

void main(void) {
     test = -1 ;
     if(test & 0x80) { //Comprobación convencional con máscara&
        test = 1 ;      //tratamiento si número negativo
     }
     if(signo == 1)  { //Uso del bit de signo
        test = 1 ;      //tratamiento si número negativo
        }
      }

  Resultado en ensamblador:

RSEG  ?BA?T2
           test:   DS    1
signo EQU (test+0).7

; void main(void) {

main:
;      test = -1 ;
MOV  test,#0FFH
;      if(test & 0x80) {//Comprobación convencional con máscara&
MOV  A,test
JNB  ACC.7,?C0001
;         test = 1 ;     // tratamiento si número negativo
MOV  test,#01H
;      }
?C0001:
;      if(signo == 1)  { // Uso del bit de signo
JNB  signo,?C0003
;         test = 1 ;     // tratamiento si número negativo
MOV  test,#01H
;         }
;       }
?C0003:
RET  

La definición del bit de signo mediante la extensión sbit, hace que el compilador utilice la instrucción JNB, lo cual proporciona mayor rapidez que el uso de máscaras &.

 En en supuesto que se desee comprobar el signo de un valor int, se debe tener en cuenta que el el 8051 almacena el byte alto en la dirección de memoria más baja. Por ello, el bit 7 es el bit de mayor peso del byte alto, mientras que el bit 15 es el bit de mayor peso del byte bajo de la variable int.

Conversión entre tipos

Una de las principales fuentes de error en C, consiste en ignorar las implicaciones de los tipos de datos en los cálculos y comparaciones. En el siguiente ejemplo:

    unsigned char x, y, z ;
    
    x = 10 ;
    y = 5  ;
    
    z = x * y ;


El resultado es z = 50

Sin embargo:


    x = 10 ;
   y = 50 ;
    
   z = x * y ;

hace que z = 244. La solución verdadera 500 (0x1F4) no se logra, debido a que z no puede almacenarla. La solución consiste en hacer que z sea un unsigned int. Sin embargo, siempre es una buena idea hacer explícito el forzado de tipo (casting) de los operandos unsigned char a int así:

    unsigned char x, y, z ;

   z = (unsigned int) x * (unsigned int) y ;

Aunque C51 promueve automáticamente los char a int, lo mejor es no confiar en ello, ya que en un pequeño microcontrolador siempre hay que cuidar el tamaño exacto de los datos.

Una solución no-ANSI para la comprobación de valores

Una situación muy corriente se produce cuando se suman dos bytes y se limita el resultado máximo de la suma al valor 255. Ya se ha comentado que con el 8051, si se desea conseguir la máxima velocidad conviene evitar el uso de variables int. Por otro lado, si la suma de los dos bytes supera el valor 255, es necesario utilizar enteros.

Seguidamente se presentan dos ejemplos. En el primero se utiliza un enfoque ANSI, y puede verse el buen trabajo realizado por el compilador C51. En el segundo ejemplo, mucho más rápido se emplea una solución no ANSI: 

; #include <reg51.h>
; unsigned char x, y, z ;
; 
; /***Sumar dos bytes y comprobar resultado supera el valor 255***/
;  
; void main(void) {

RSEG  ?PR?main?T2
USING 0
main:
;     if(((unsigned int)x + (unsigned int)y) > 0xff)
MOV  A,x
ADD  A,y
MOV  R7,A
CLR  A
RLC  A
MOV  R6,A
SETB C
MOV  A,R7
SUBB A,#0FFH
MOV  A,R6
SUBB A,#00H
JC   ?C0002
;         z = 0xff ;   // versión ANSI C
MOV  z,#0FFH
;     }
?C0002:
RET

 

En este segundo ejemplo, se comprueba el valor del flag de acarreo CY, eliminando la necesidad de realizar operaciones con enteros, ya que si el resultado supera el valor 255, el bit CY toma valor 1. Por supuesto, se trata de una solución no conforme al estándar ANSI C.

; #include <reg51.h>
; 
; unsigned char x, y, z ;
; 
; /*** Sumar dos bytes y comprobar si el resultado supera el valor 255 ***/ 
; void main(void) {
main:
;     z = x + y;    
MOV  A,x
ADD  A,y
MOV  z,A
;     if (CY == 1)
JNB  CY,?C0002
;        z = 0xff ;   // Solución con el flag CY del 8051
MOV  z,#0FFH
;     }
?C0002:
RET

 

Si se suman dos enteros y se desea comparar si el resultado supera el valor 65535 (0xffff), la situación se complica ya que hay que utilizar valores long, que ocupan 32 bits. Aún en este caso, se puede comprobar el valor del bit CY después de realizar la suma de los bytes altos de los dos enteros. En sistemas de altas prestaciones con el 8051, la pérdida de portabilidad puede tolerarse. Desafortunadamente la portabilidad de los programas siempre compromete las prestaciones de los mismos.

 


   Contenido>Indice>Intro CursoC51