Comportamiento extraño de desbordamiento de variable de tipo de carácter

2

Estoy intentando diseñar un decodificador de codificación ON-OFF para un proyecto de lector RFID en el que he estado trabajando. A continuación se muestra el código que se ejecuta en un PIC16F887 @ 20MHZ. El compilador es Mikroelektronika mikroC PRO para PIC.

Lo que estaba tratando de hacer es alternar PORTC.1 cada 200 uS. El código se ejecuta como se desea, pero solo durante unos 5,8 ms, como medí con el osciloscopio. Después de eso, PORTC.1 no cambia.

Supongo que de alguna manera está relacionado con el desbordamiento de las variables fiftymicros y data_time . Si aumentamos la variable fiftymicros cada 50 usec; en realidad, esto es lo que hace el programa, se desbordará después de 255 * 50 microsegundos, lo que equivale a 12.75 mseg.

Siempre que cambie el tipo de las variables fiftymicros y data_time a entero, el problema disminuye.

¿Podría ayudarme a entender cuál es la razón detrás de este comportamiento?

volatile unsigned char fiftymicros=0;
volatile unsigned char fiftymicroscounter=0;
volatile unsigned char data_time=0;
volatile unsigned int milis=0;
volatile unsigned int milis_ctr=0;

void calculate_data_time()
{
     static volatile unsigned char ctr=0;
     static volatile unsigned char ind=0;
     if(fiftymicros-data_time>3)
     {
       data_time=fiftymicros;
       PORTC.F1=~PORTC.F1;
     }
}

void interrupt()
{
     if(INTCON.T0IF)
     {
      TMR0=198;
      INTCON.T0IF=0;
      fiftymicros++;
      if(++fiftymicroscounter==20) { fiftymicroscounter=0; milis++; }
     }
    if(INTCON.RBIF)
     {
      //data_time=fiftymicros;
      INTCON.RBIF=0;
     }
}

void main()
{
     ANSEL =0;
     ANSELH=0;
     TRISA=0; PORTA=0;
     TRISB=0x01; PORTB=0;
     TRISC=0; PORTC=0;
     TRISD=0; PORTD=0;
     TRISE=0; PORTE=0;
     OPTION_REG.INTEDG=1;
     OPTION_REG.T0CS=0;
     OPTION_REG.PSA=0;
     OPTION_REG.PS0=1;
     OPTION_REG.PS1=0;
     OPTION_REG.PS2=0;
     INTCON.TMR0IE=1;
     INTCON.RBIE=1;
     INTCON.GIE=1;
     UART1_Init(9600);
     Delay_ms(100);
     milis_ctr=milis;
     while(1)
     {
      calculate_data_time();
     }
}
    

2 respuestas

1

Si el compilador es compatible con ANSI C, los dos caracteres sin signo se promoverán a números enteros según las conversiones aritméticas habituales especificadas en el estándar ANSI C. Si data_time es mayor que cincuentamicros debido a cincuentamicros desbordados, entonces el resultado de fiftymicros - data_time será un número negativo.

Con el código original, si fiftymicros = 0 y data_time = 251, el resultado de fiftymicros - data_time será -251

Puedes obligar al compilador a hacer lo que quieras cambiando el código a esto:

if ((unsigned char)(fiftymicros - data_time) > 3)
{
    ...
}

Con este código, si fiftymicros = 0 y data_time = 251, el resultado de (carácter sin signo) (fiftymicros - data_time) será 5.

    
respondido por el Louis Davis
2

Creo que todo se reduce a:

 if(fiftymicros-data_time>3)
 {
   data_time=fiftymicros;
   PORTC.F1=~PORTC.F1;
 }

No sé cómo ese compilador maneja el >3 , pero puede estar realizando una comparación firmada. Entonces, aquí está el escenario: Supongamos que fiftymicros acaba de incrementarse a 255, y data_time es 251 (estos números podrían ser un poco más pequeños y el resultado sería el mismo). El if sería verdadero, por lo que data_time se establecería en 255. Luego, interrupt() incrementos fiftymicros , lo que hace que se desplace a 0 (porque fiftymicros es un personaje sin signo). Ahora, todos los cálculos futuros fiftymicros-data_time darán como resultado un número negativo (firmado), que siempre será menor que 3.

Una solución simple sería:

 if(fiftymicros>3)
 {
   fiftymicros=0;
   PORTC.F1=~PORTC.F1;
 }

Si aún desea data_time por otros motivos, agregue data_time+=fiftymicros; antes de fiftymicros=0; .

    
respondido por el Klox

Lea otras preguntas en las etiquetas