Autor Tema: funcion multiplicar en xc8 no me funciona ?  (Leído 2173 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado nahueldiaz1992

  • PIC12
  • **
  • Mensajes: 75
funcion multiplicar en xc8 no me funciona ?
« en: 16 de Febrero de 2016, 09:39:52 »
Buenas , tengo un problema a la hora de poder realizar una multiplicacion en xc8 y la no puedo ver cual es el problema , ya que compila bien , pero cuando realizo el debug del programa , no se modifica mi variable de la forma deseada .

result = (ADRESL * 1275)>>8 ;

dando como resultado=> result = 0x00 ; siendo que con el stimulus logro que el adc del micro me de ADRESL = 0xFF ; y ADRESH = 0x02 ;

incluso cuando realizo la siguiente operacion

result = ADRESL * 1275 ;

result = 0x00 ; asi que no entiendo cual es el problema , estoy trabajando con el pic16f88 .

Me gustaria saber en que me equivoque o que es lo que hago mal .. para poder realizar operaciones matematicas .El programa esta sin terminar y es para mostrar por 4 displays 7 segmetos los valores de temperatura o cualquier dato que se presente a medir .

Código: [Seleccionar]
/*
 * File:   vumetro2.c
 * Author: nahueldiaz
 *
 * Created on 27 de enero de 2016, 21:20
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <plib.h>
#include <plib/adc.h>
#include <math.h>




#define _XTAL_FREQ 2000000

// CONFIG1
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB0      // CCP1 Pin Selection bit (CCP1 function on RB0)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// CONFIG2
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal External Switchover mode enable

unsigned char high,low;
unsigned char result;
unsigned char cnt,msb,lsb ;

void interrupt alta(void){ //interrupcion de alta
   
    INTCONbits.GIE = 0; //deshabilita las int. para nocausar varias int a la vez
   
    if (PIR1bits.ADIF == 1){ // si salto flag de ADC entonces..
       
            high = ADRESH; // rescatar valores de ADC
            low  = ADRESL;
            PORTB = low;
           
            __delay_ms(10);
           
            ADRESH = 0x00;
            ADRESL = 0x00;
           
         
        PIR1bits.ADIF = 0;
    }
    INTCONbits.GIE = 1;
}

unsigned char display (unsigned char no){ //display 7 segmentos
    unsigned char patern;
    unsigned char segment[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
    patern = segment[no];
    return (patern);
}

void main (){
   
        OSCCON = 0x50 ;// clock 2MHz
        __delay_ms (10);
   
        TRISA = 0X02;
        TRISB = 0X00;
        PORTA = 0X00;
        PORTB = 0X00;
       
        ANSEL  = 0b00000010; // ADC en RA1
        ADCON0 = 0b10001001; // clock 2 mhz dividido 64 = 31250
        ADCON1 = 0b11000000; // 32us de tiempo de adquisicion
       
        INTCON = 0b01000000; // interrupciones habilitadas ADC
        PIR1bits.ADIF = 0;
        PIE1bits.ADIE = 1;
        INTCONbits.GIE = 1;
       
        __delay_ms (30);
       
        ADCON0 = 0b10001101 ;
       
        while (1){
           
            __delay_ms(10);
           
            result = ADRESL * 1275;
           
            ADCON0 = 0b10001101;
           
        }
       
        // el siguiente bloque se coloca si se quiere realizar manualmente la consulta del adc
       
        //while (1){
        //if (ADCON0 == 0b10001001) { // si completo la conversion , entra en el ciclo y toma los valores del ADC
            //high = ADRESH;
            //low  = ADRESL;
            //PORTB = low;
        //}
         //__delay_ms (30);
   
       
        //ADCON0 = 0b10001101;
       
               
       
        }//}

Desconectado luismh

  • PIC16
  • ***
  • Mensajes: 149
Re:funcion multiplicar en xc8 no me funciona ?
« Respuesta #1 en: 16 de Febrero de 2016, 09:54:14 »
Creo que la variable "result" está mal definida... Es de tipo char y solo tiene 8 bits de extensión... Al multiplicarla por 1275 se desborda totalmente.

Podrías probar definiendo esta variable con:

unsigned long int result

Saludos.

Desconectado nahueldiaz1992

  • PIC12
  • **
  • Mensajes: 75
Re:funcion multiplicar en xc8 no me funciona ?
« Respuesta #2 en: 16 de Febrero de 2016, 10:12:09 »
Creo que la variable "result" está mal definida... Es de tipo char y solo tiene 8 bits de extensión... Al multiplicarla por 1275 se desborda totalmente.

Podrías probar definiendo esta variable con:

unsigned long int result

Saludos.

 Buenas , acabode realizar la prueba y no , no da , es cierto que desborda , fue mi descuido pero sin embargo no funciona.
Lo que queria realizar es la conversion de binario a decimal para poder mostrarlo en los displays

Desconectado luismh

  • PIC16
  • ***
  • Mensajes: 149
Re:funcion multiplicar en xc8 no me funciona ?
« Respuesta #3 en: 16 de Febrero de 2016, 10:26:06 »
En tu rutina de interrupción pones a cero el registro ADRESL...

ADRESL = 0x00;

Luego, cuando vuelves al main hace la multiplicación

result = ADRESL * 1275;

Como ADRESL  es cero, la multiplicación te da cero...

Podrías probar usando la variable low que declaraste y en la que guardas el valor de ADRESL:

result = low * 1275

Espero que sea de ayuda.
Saludos.


Desconectado nahueldiaz1992

  • PIC12
  • **
  • Mensajes: 75
Re:funcion multiplicar en xc8 no me funciona ?
« Respuesta #4 en: 16 de Febrero de 2016, 11:41:18 »
Tampoco funciona asi ... lo he probado y sigue dando cero

Desconectado luismh

  • PIC16
  • ***
  • Mensajes: 149
Re:funcion multiplicar en xc8 no me funciona ?
« Respuesta #5 en: 16 de Febrero de 2016, 12:28:45 »
Que señal hay en el pin RA1?

Sabés usar el debugger de mplab? Podrías poner un breakpoint en la rutina de interrupción y ver si el programa pasa por ahí en algún momento. Si no pasa por ahí, probablemente está mal configurado el módulo ADC y/o las interrupciones.

Otra cosa: en la rutina de interrupción no es necesario deshabilitar las interrupciones globales, el micro lo hace solo cuando entra en interrupción de alta prioridad. Otra: no se recomienda utilizar delays en interrupciones, la idea es atender la interrupción lo mas rápido posible y volver al main.

Además noté que configuraste el registro ADCON1 para que el resultado de la conversión esté justificado a la izquierda.. Esto significa que la mayoría de bits de ADRESL sea cero, mientras que la parte significativa estará en ADRESH... Podrías intentar leer ADRESH en lugar de ADRESL o en su defecto poner en 1 el bit 7 del registro ADCON1 para justificar a la derecha.



Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:funcion multiplicar en xc8 no me funciona ?
« Respuesta #6 en: 16 de Febrero de 2016, 14:11:08 »
Primero sacar lo de la interrupcion poniendo ADRESL y ADRESH a 0. Ya que es son 2 cosas que pueden hacer que te de 0. Eso y que leas efectivamente 0 del ADC. (Al final hay mas sobre esto)

Y ahora vamos con el tema de la multiplicacion.

Código: C
  1. result = ((unsigned short long int)ADRESL * 1275)>>8 ;

O si utilizas stdint, ( personalmente no me gusta la opcion anterior )

Código: C
  1. result = ((uint24_t)ADRESL * 1275)>>8 ;


Esto hace que ADRESL  sea tomado como una variable de 24bits y cuando se multiplica el resultado entre por completo. luego el shift y se guarda.
De no haberlo realizado de esa forma ADRESL se promociona al tipo de 1275, es decir un int ( 16 bits ). Y se produce la multiplicacion en 16bits


Por ejemplo, con ADRESL = 250, y result siendo de 32bits sin signo para que pueda tener ese valor

Código: C
  1. result = (ADRESL * 1275);

Lo obtenido es : result = 0xFFFF.E418
Como la multipliacion en 16bits ( sin signo ) supera los 16bits se trunca a 16 quedando 0xE418, lo cual es con signo, al pasarlo a uno de 32 bits se promociona de nuevo pero se promociona a lo mas proximo y que pueda representar el valor, lo cual es: 24/32 bits con signo y se extiende el signo por eso las 0xFFFF, si repetimos el mismo trabajo con esta formula:

Código: C
  1. result = ((uint24_t)ADRESL * 1275);

El resultado es distinto, por que esta ves el mas grande es el de uint24_t, como resultado tenes que result tiene un valor de = 0x0003.E418.
Ahora si incorporamos todo.

Código: C
  1. result = ((uint24_t)ADRESL * 1275)>>8;

Queda en 0x03E4 , que es el valor buscado.



Optimizacion

- Y ahora llega el momento de la optimizacion... Es necesario hacer ese calculo ? 1275 / 256 = 4.98
¿Crees que le estarias errando por mucho al hacerlo directamente asi?:

Código: C
  1. result = ((uint16_t)ADRESL * 5);
  2. resultado = ((uint16_t)variable << 2) + variable;

Obviamente el maximo error se va a dar cuando ADRESL tenga un valor igual a 255.

Con tu formula : 0x4F6   - 350 ciclos en PIC sin multiplicador
Con 5 en la formula: 0x4FB  ( Maximo error 5 ) - 219 ciclos
Con shift de 2 + ADRESL : 0x4FB (Mismo error que con 5)  - 17 ciclos  ( Lo que hago es multiplicar por 4 y sumarle 1, en resume igual que multiplicar por 5 )



Error en tomar el valor ?

- Y por otra parte .. por que estas tomando ADRESL cuando tu ADC es de 10 bits ? , si quisieras realmente reducir tu numero a un valor de 8 bits, deberias usar justificado izquierda y tomar ADRESH.



Error en activar el ADC ?

- Estaria bueno que dijeras el PIC que posees, por que normalmente el bit de GO ( que activa la conversion ) esta en el bit 1 el cual nunca activas:

 ADCON0 = 0b10001101;

Igual podrias hacer:

Código: C
  1. ADCON0bits.GO = 1;                         // Activo conversion
  2. while(ADCON0bits.GO == 1);             // Espero que termine.

Por lo que puede ser que no estes activando la conversion del ADC y por lo tanto siempre leas 0. Que es una de las 2 causas que dije al comienzo de por que puede dar 0.
« Última modificación: 16 de Febrero de 2016, 14:35:33 por KILLERJC »

Desconectado nahueldiaz1992

  • PIC12
  • **
  • Mensajes: 75
Re:funcion multiplicar en xc8 no me funciona ?
« Respuesta #7 en: 17 de Febrero de 2016, 21:44:50 »
Primero sacar lo de la interrupcion poniendo ADRESL y ADRESH a 0. Ya que es son 2 cosas que pueden hacer que te de 0. Eso y que leas efectivamente 0 del ADC. (Al final hay mas sobre esto)

Y ahora vamos con el tema de la multiplicacion.

Código: C
  1. result = ((unsigned short long int)ADRESL * 1275)>>8 ;

O si utilizas stdint, ( personalmente no me gusta la opcion anterior )

Código: C
  1. result = ((uint24_t)ADRESL * 1275)>>8 ;


Esto hace que ADRESL  sea tomado como una variable de 24bits y cuando se multiplica el resultado entre por completo. luego el shift y se guarda.
De no haberlo realizado de esa forma ADRESL se promociona al tipo de 1275, es decir un int ( 16 bits ). Y se produce la multiplicacion en 16bits


Por ejemplo, con ADRESL = 250, y result siendo de 32bits sin signo para que pueda tener ese valor

Código: C
  1. result = (ADRESL * 1275);

Lo obtenido es : result = 0xFFFF.E418
Como la multipliacion en 16bits ( sin signo ) supera los 16bits se trunca a 16 quedando 0xE418, lo cual es con signo, al pasarlo a uno de 32 bits se promociona de nuevo pero se promociona a lo mas proximo y que pueda representar el valor, lo cual es: 24/32 bits con signo y se extiende el signo por eso las 0xFFFF, si repetimos el mismo trabajo con esta formula:

Código: C
  1. result = ((uint24_t)ADRESL * 1275);

El resultado es distinto, por que esta ves el mas grande es el de uint24_t, como resultado tenes que result tiene un valor de = 0x0003.E418.
Ahora si incorporamos todo.

Código: C
  1. result = ((uint24_t)ADRESL * 1275)>>8;

Queda en 0x03E4 , que es el valor buscado.



Optimizacion

- Y ahora llega el momento de la optimizacion... Es necesario hacer ese calculo ? 1275 / 256 = 4.98
¿Crees que le estarias errando por mucho al hacerlo directamente asi?:

Código: C
  1. result = ((uint16_t)ADRESL * 5);
  2. resultado = ((uint16_t)variable << 2) + variable;

Obviamente el maximo error se va a dar cuando ADRESL tenga un valor igual a 255.

Con tu formula : 0x4F6   - 350 ciclos en PIC sin multiplicador
Con 5 en la formula: 0x4FB  ( Maximo error 5 ) - 219 ciclos
Con shift de 2 + ADRESL : 0x4FB (Mismo error que con 5)  - 17 ciclos  ( Lo que hago es multiplicar por 4 y sumarle 1, en resume igual que multiplicar por 5 )



Error en tomar el valor ?

- Y por otra parte .. por que estas tomando ADRESL cuando tu ADC es de 10 bits ? , si quisieras realmente reducir tu numero a un valor de 8 bits, deberias usar justificado izquierda y tomar ADRESH.



Error en activar el ADC ?

- Estaria bueno que dijeras el PIC que posees, por que normalmente el bit de GO ( que activa la conversion ) esta en el bit 1 el cual nunca activas:

 ADCON0 = 0b10001101;

Igual podrias hacer:

Código: C
  1. ADCON0bits.GO = 1;                         // Activo conversion
  2. while(ADCON0bits.GO == 1);             // Espero que termine.

Por lo que puede ser que no estes activando la conversion del ADC y por lo tanto siempre leas 0. Que es una de las 2 causas que dije al comienzo de por que puede dar 0.


Muchisimas Gracias KILLERJC !!!! nunca vi que nadie respondiese tan bien a alguna duda ! enserio Muchas Gracias !

Respecto al pic que uso es el PIC16F88 , el ADC lo activo , el tema es que como no me gusta utilizar la declaracion de bit por bit , directamente configuro el byte entero con el datasheet a mi lado .pero si , el ADC esta activo ya que al simularlo y estimularlo funciona  y tambien funciona cuando lo simulo en el proteus .

Revisare y modificare el programa , luego comento los resultados  . Gracias !


 

anything