ayuda problema con datos flotantes

quisiera que me ayudaran a resolver un problema que tengo con datos flotantes.

sucede que hice un programa en C utilice microC for PIC.....
para un contador electronico con tarifa y subtotales y total.
bueno en fin, el caso es que si pongo una tarifa con punto decimal a la hora de multiplicar la tarifa (con punto decimal o sin punto decimal) me arroja resultados aproximados en decimales en el subtotal y total.

por ejemplo:

si mi tarifa es 5.00 y el numero de pulsos que se han contado es 20 me aparecen en los subtotales 100
pero aqui viene el problema al pasar a 21 en numero de pulsos contados y multiplicarlo por la misma tarifa me arroja en el subtotal la cantidad de 104.99999 siendo que deberia ser 5X21=105

Eso es en cifras cerradas

y pues ni hablar en las cifras con punto decimal igual los datos arrojados no encajan con la logica matematica =P

y pues necesito que sean las multiplicaciones exactas

aqui les muestro el codigo.

de antemano gracias

Código:
   // programa: CONTADOR electronico Y TARIFADOR con  pic18F4550
   // entrada de señal del sensor PORTB.0
  // Lcd configuracion de los pines de salida que utilizara el modulo lcd

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;
   // configuracion de la direccion de los pines de salida
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;
// fin de configuracion de los pines del lcd
// como vemos se a utilizado el puerto D PARA LA SALIDA DE DATOS HACIA EL LCD

    //  char resultado[11];    // variable tipo string para la convercion de dato a cadena string


      char i   ;            // variable char rango de un byte 0...255
      char TECLA;           //
      char digitos;
      char digito_1;
      char digito_2;
      char digito_3;
      char digito_4;
      char digito_5;
      char digito_6;
      // variable para la convercion a cadena
      char PRECIO_LCD[15];  //
      char pulsos_lcd[12];  //
      char cantidad_lcd[5];  //
      int cantidad ;
      char presiono ;
      char digitos_r ;
      char clave1;
      char clave2;
      char clave3;
      char clave4;

      char clave1d;
      char clave2d;
      char clave3d;
      char clave4d;
      char aciertos;
      char mensaje_1;
        // variables de tipo flotante de 4 bytes para calculos con decimal
      float tarifa ;
      float precio;
      float parte_decimal;
      float parte_entera;
      float pulsos  ;
      float total_f;
      long cantidad_final ;
      char sumar;
      char cambiar;


void guardar_datos(){ //subrutina que graba el numero que se programo en el contador en
      EEPROM_Write(0x00,DIGITO_1) ;  //la memoria eeprom del pic18f452a
      DELAY_MS(10);
      EEPROM_Write(0x01,DIGITO_2)  ;
      DELAY_MS(10);
      EEPROM_Write(0x02,DIGITO_3)  ;
      DELAY_MS(10);
      EEPROM_Write(0x03,DIGITO_4)   ;


//
}

 void VISUALIZA_clave(){   // subrutina que visualiza el digito que se presiono y lo visualiza

     switch (digitos) {

      case 1 :
      clave1d= TECLA  ;
      Lcd_Chr(2, 20,'*') ;
      break ;
      case 2:
      clave2d= TECLA ;
      Lcd_Chr(2, 19, '*') ;

      break ;
      case 3:
      clave3d= TECLA ;
      Lcd_Chr(2, 18,'*' );

      break ;
      case 4:
      clave4d= TECLA ;
      Lcd_Chr(2, 17, '*') ;

      break ;

      default:
      break ;
}

//
}
     void v_tarifa(){         // esta subrutina visualiza los digitos de la tarifa
      Lcd_Chr(2, 1,'T');
      Lcd_Chr(2, 2,':');

      Lcd_Chr(2, 4, DIGITO_1+48);
      Lcd_Chr(2, 5, DIGITO_2+48);
      Lcd_Chr(2, 6, '.');
      Lcd_Chr(2, 7, DIGITO_3+48);
      Lcd_Chr(2, 8, DIGITO_4+48);

}
 void VISUALIZA_tarifa(){   // subrutina que visualiza el digito que se presiono y lo visualiza

     switch (digitos) {

      case 1 :
      digito_1= TECLA  ;
      Lcd_Chr(2, 16,digito_1+48) ;
      break ;
      case 2:
      digito_2= TECLA ;

      Lcd_Chr(2, 17, digito_2+48);
      break ;
      case 3:
      digito_3= TECLA ;
      Lcd_Chr(2, 19, digito_3+48);
      break ;
      case 4:
      digito_4= TECLA ;
      Lcd_Chr(2, 20, digito_4+48) ;
      break ;

      default:
      break ;
}

//
}


   void VISUALIZA_clave_nueva(){   // subrutina que visualiza la clave nueva

     switch (digitos) {

      case 1 :
      clave1= TECLA  ;
      Lcd_Chr(2, 17,clave1+48) ;
      break ;
      case 2:
      clave2= TECLA ;

      Lcd_Chr(2, 18, clave2+48);
      break ;
      case 3:
      clave3= TECLA ;
      Lcd_Chr(2, 19, clave3+48);
      break ;
      case 4:
      clave4= TECLA ;
      Lcd_Chr(2, 20, clave4+48) ;
      break ;

      default:
      break ;
}

//
}



void sumar_contador(){     // subrutina que suma las cantidades despues de borrar los datos de la 3 y 4 linea

   cantidad_final=cantidad_final+pulsos;
   cantidad=cantidad_final ;
   total_f=total_f+precio;
    FloatToStr(total_f, PRECIO_LCD);  // txt is "-374.2"
    WordToStr(cantidad, cantidad_lcd);
    Lcd_OUT(4, 5, precio_lcd);
    Lcd_OUT(4, 16, cantidad_lcd);
    pulsos=0 ;
    precio=0;

//
}



void convercion_parte_entera(){   // sumatoria de la parte entera por descomposicion polinomica
    parte_entera= (DIGITO_1*1000+DIGITO_2*100 +DIGITO_3*10+DIGITO_4);
}

void leer_tarifa_eeprom(){         // lectura los digitos que fueron guardados en la eeprom
     DIGITO_1=EEPROM_Read(0x00);
     delay_ms(10);
     DIGITO_2=EEPROM_Read(0x01) ;
     delay_ms(10);
     DIGITO_3=EEPROM_Read(0x02) ;
     delay_ms(10);
     DIGITO_4=EEPROM_Read(0x03) ;
     delay_ms(10);
//
}

void leer_clave_eeprom(){       // lectura los digitos que fueron guardados la clave en la eeprom
     clave1=EEPROM_Read(0x08);
     delay_ms(10);
     clave2=EEPROM_Read(0x09) ;
     delay_ms(10);
     clave3=EEPROM_Read(0x0A) ;
     delay_ms(10);
     clave4=EEPROM_Read(0x0B) ;
     delay_ms(10);
//
}

  void escribir_clave_eeprom(){  // lectura los digitos de la clave que fueron guardados en la eeprom
     EEPROM_Write(0x08,clave1);
     delay_ms(10);
     EEPROM_Write(0x09,clave2);
     delay_ms(10);
     EEPROM_Write(0x0A,clave3);
     delay_ms(10);
     EEPROM_Write(0x0B,clave4);
     delay_ms(10);
//
}

void comprobar_clave(){
 aciertos=0 ;
 if(clave1==clave1d){    // comprurba la primera clave
   aciertos ++;
}

if(clave2==clave2d){    // comprurba la segunda clave
   aciertos ++;
}

if(clave3==clave3d){    // comprurba la tercera clave
   aciertos ++;
}

if(clave4==clave4d){    // comprurba la cuarta clave
   aciertos ++;
}


}

void convercion(){        // convercion de datos para el display lcd
    precio=(parte_entera*pulsos)/100  ;
    FloatToStr(PRECIO, PRECIO_LCD);  //
    LongToStr(pulsos, pulsos_lcd);


}


void borrar_digitos(){  // borra todos los digitos del teclado
      digito_1=0;
      digito_2=0;
      digito_3=0;
      digito_4=0;
      digito_5=0;
      digito_6=0;
      digitos=0;
}
void imprimer_cf(){            // impresion de caracter para el contador cf
      Lcd_Chr(2, 13,'C');
      Lcd_Chr(2, 14,':');
      Lcd_Chr(4, 12,' ');
      Lcd_Chr(4, 13,'C');
      Lcd_Chr(4, 14,'F');
      Lcd_Chr(4, 15,':');
//
}


 void LEER_TECLA() {      // subrutina que lee el teclado
  TECLA=16;
  presiono=0 ;
  PORTD= 0B00001110  ;     // FILA 1
  if (Button(&PORTD, 4, 10, 0)) {               // COLUMNA 1
     Tecla=1 ;
while (PORTD.F4==0){
}
   goto salir;
}

   if (Button(&PORTD, 5, 10, 0)) {               // COLUMNA 2
     Tecla=2 ;
while (PORTD.F5==0){
}
   goto salir;
}

   if (Button(&PORTD, 6, 10, 0)) {               // COLUMNA 3
     Tecla=3 ;
while (PORTD.F6==0){
}
   goto salir;
}

  if (Button(&PORTD, 7, 10, 0)) {               // COLUMNA 4
     Tecla=15 ;
while (PORTD.F7==0){
}
   goto salir;
}


PORTD= 0B00001101  ;     // FILA 2
  if (Button(&PORTD, 4, 10, 0)) {               // COLUMNA 1
     Tecla=4 ;
while (PORTD.F4==0){
}
   goto salir;
}

   if (Button(&PORTD, 5, 10, 0)) {               // COLUMNA 2
     Tecla=5 ;
while (PORTD.F5==0){
}
   goto salir;
}

   if (Button(&PORTD, 6, 10, 0)) {               // COLUMNA 3
     Tecla=6 ;
while (PORTD.F6==0){
}
   goto salir;
}

  if (Button(&PORTD, 7, 10, 0)) {               // COLUMNA 4
     Tecla=14 ;
while (PORTD.F7==0){
}
   goto salir;
}


PORTD= 0B00001011  ;     // FILA 3
  if (Button(&PORTD, 4, 10, 0)) {               // COLUMNA 1
     Tecla=7 ;
while (PORTD.F4==0){
}
   goto salir;
}

   if (Button(&PORTD, 5, 10, 0)) {               // COLUMNA 2
     Tecla=8 ;
while (PORTD.F5==0){
}
   goto salir;
}

   if (Button(&PORTD, 6, 10, 0)) {               // COLUMNA 3
     Tecla=9 ;
while (PORTD.F6==0){
}
   goto salir;
}

  if (Button(&PORTD, 7, 10, 0)) {               // COLUMNA 4
     Tecla=13 ;
while (PORTD.F7==0){
}
   goto salir;
}

PORTD= 0B00000111  ;     // FILA 4
  if (Button(&PORTD, 4, 10, 0)) {               // COLUMNA 1
     Tecla=10 ;
while (PORTD.F4==0){
}
   goto salir;
}

   if (Button(&PORTD, 5, 10, 0)) {               // COLUMNA 2
     Tecla=0 ;
while (PORTD.F5==0){
}
   goto salir;
}

   if (Button(&PORTD, 6, 10, 0)) {               // COLUMNA 3
     Tecla=11 ;
while (PORTD.F6==0){
}
   goto salir;
}

  if (Button(&PORTD, 7, 10, 0)) {               // COLUMNA 4
     Tecla=12 ;
while (PORTD.F7==0){
}
   goto salir;
}
  goto final;


salir: ;
  presiono=255;
final:  ;


}      // fin de la subrutina lee_teclado






void main() {       // inicio del programa principal


       PORTA=0   ;   // apagamos todos los puertos a 0v
       PORTB=0  ;
       PORTC=0   ;
       PORTD=0   ;
       PORTE=0   ;

      ADCON1 = 14 ;    // desabilitamos las entradas analogicas
      cmcon=7;                // configuramos todos los puertos como salida exepto   el PORTB.0  que es configurado como entrada
      TRISA = 0B00000000 ;
      TRISB = 0B00000001  ;
      TRISC = 0B00000000  ;
      TRISD = 0B11110000  ;    // configuracion para el teclado
      TRISE = 0B00000000  ;


      digito_1=0;     // iniciamos poniendo a cero todas las variables
      digito_2=0;
      digito_3=0;
      digito_4=0;
      digito_5=0;
      digito_6=0;
      digitos=0;
      pulsos=0  ;
      precio=0   ;
      mensaje_1=0;
      leer_tarifa_eeprom();

      clave1=EEPROM_Read(0x08); // lectura los digitos de la clave que fueron guardados en la eeprom
     delay_ms(10);
     clave2=EEPROM_Read(0x09) ;
     delay_ms(10);
     clave3=EEPROM_Read(0x0A) ;
     delay_ms(10);
     clave4=EEPROM_Read(0x0B) ;
     delay_ms(10);
      cantidad_final =0 ;
      total_f=0;
      sumar=0;
        Lcd_Init();      // inicia el modul lcd
inicio: ;
      Lcd_Cmd(_LCD_CLEAR) ;    // borramos el display lcd
      Lcd_Cmd(_LCD_CURSOR_OFF);  // borramos el cursor
                                 // mensaje inicial de lcd
      Lcd_OUT(1, 1, "LEYENDA:                ");
      Lcd_OUT(2, 1,"T:          C:     0");
      Lcd_OUT(3, 1,"TP:                0");
      Lcd_OUT(4, 1,"TF:       0 CF:    0");
      V_TARIFA();
      Lcd_Chr(2, 13,'C');
      Lcd_Chr(2, 14,':');
      Lcd_Chr(2, 20,'0');
     V_TARIFA();   // visualiza la tarifa que fue guardada en la eeprom

 while(1){
      LEER_TECLA();   // lee el teclado hasta confirmar orden

   if (tecla==10){       // si TECLA =10 va a introducir clave para cambiar de tarifa
      CAMBIAR= 0 ;
      goto  introducir_clave ;
}

   if (tecla==12){       // si TECLA =12 va a introducir clave para cambiar la clave eeprom
    CAMBIAR=255 ;
   goto introducir_clave  ;
}

   if (tecla==13){         //   si TECLA =13 inicia el modo de contaje tarifador
   goto CONTAR_PULSOS  ;
}
//

  }


cambiar_tarifa:  ;     // bloque de programa que cambia la trifa principal
     leer_tarifa_eeprom();

     Lcd_Cmd(_LCD_CLEAR) ;
     Lcd_Cmd(_LCD_CURSOR_OFF);
      Lcd_OUT(1, 1,"CAMBIAR TARIFA:");
      Lcd_OUT(2, 16,"00.00");
      Lcd_OUT(4, 1,"CONFIRMAR:A SALIR: B");
      v_tarifa() ;


 while (1){

   LEER_TECLA();

   if (tecla==10){
        guardar_datos();
      v_tarifa();

}
   if (tecla==11){
              asm {
      reset;
}
//
}
   if (Tecla < 10){

    digitos++  ;

    if (digitos >4){
      digito_1=0;
      digito_2=0;
      digito_3=0;
      digito_4=0;
      digitos=1;
    Lcd_OUT(2, 16, "00.00");
}

    VISUALIZA_tarifa();  // visualiza la nueva tarifa

//
}

}
contar_pulsos:      // modo de contar pulsoy y tarifador normal
     mensaje_1=0;
      Lcd_Cmd(_LCD_CLEAR) ;    // borramos el display lcd
      Lcd_Cmd(_LCD_CURSOR_OFF);  // borramos el cursor
      Lcd_OUT(1, 1, "LEYENDA:");
      Lcd_OUT(2, 1,"T:          C:     0");
      Lcd_OUT(3, 1,"TP:                0");
      Lcd_OUT(4, 1,"TF:       0 CF:    0");
      V_TARIFA();
      Lcd_Chr(2, 13,'C');
      Lcd_Chr(2, 14,':');
      Lcd_Chr(2, 20,'0');
      convercion_parte_entera() ;

   if (sumar==255){
        sumar_contador();
        imprimer_cf();
//
}
      pulsos=0  ;
 while (1){
      LEER_TECLA();
      if (tecla==14){ // si TECLA = 14 activa el flag de sumar
     sumar=255;
     goto contar_pulsos;

}

  if(PORTB.B0==1){       // si portb.0= 1
      pulsos=pulsos+1  ;         // incrementamos contador

          if(pulsos > 9999){  // si el contador es mayor a 9999 lo ponemos a cero
          pulsos=0   ;
}
       convercion();
    Lcd_OUT(2, 10, pulsos_lcd);
    Lcd_OUT(3, 14, precio_lcd);
        imprimer_cf();


 while(PORTB.B0==1){   // espera a que cambie de señal para continuar
//
}
//
}


}

introducir_clave: ;   // bloque de prgrama que se encarga de cambiar la clave o tarifa
     digitos=0;
     Lcd_Cmd(_LCD_CLEAR) ;    // borramos el display lcd
      Lcd_out(1, 1,"introdusca clave:");
      Lcd_out(4, 1,"            Salir: B");
  while(1){
      LEER_TECLA();

   if (tecla==11){      // si TECLA=11 resetea todo el microcontrolador
            asm {
      reset;
}

}



    if (Tecla < 10){    // si TECLA es menor que 10 visualiza la clave

    digitos++  ;
    VISUALIZA_clave();
    if (digitos ==4){
       comprobar_clave() ;  // subrutina que comprueba la clave
       clave1d=0;
       clave2d=0;
       clave3d=0;
       clave4d=0;
     if (aciertos ==4){        // si aciertos = 4 cambia la tarifa o la clave
       if (cambiar==0){
      goto cambiar_tarifa;
}
else{
     goto cambiar_clave;
}
       
       
}
     digitos=0;
   Lcd_OUT(2, 16, "ERROR");     // si de digito la clave erronea imprime el mensaj eeror
   DELAY_MS(1000) ;
   Lcd_OUT(2, 16, "     ");
}
//

//
}

  }


cambiar_clave: ;   // bloque de programa que cambia la clave de la tecla
     digitos=0;
     Lcd_Cmd(_LCD_CLEAR) ;    // borramos el display lcd
      Lcd_out(1, 1,"clave nueva:");
      Lcd_out(2, 17,"0000");
      Lcd_OUT(4, 1,"CONFIRMAR:A SALIR: B");
  while(1){
     LEER_TECLA();
      if (tecla==11){     // si TECLA=11 resetea el microcontrolador
            asm {
      reset;
}
      
     //goto  inicio ;
}

  if (tecla==10){
     EEPROM_Write(0x08,clave1); // lectura los digitos que fueron guardados en la eeprom
     delay_ms(10);
     EEPROM_Write(0x09,clave2);
     delay_ms(10);
     EEPROM_Write(0x0A,clave3);
     delay_ms(10);
     EEPROM_Write(0x0B,clave4);
     delay_ms(10);
     Lcd_Chr(1, 17, clave1+48);   // visaliza la clave en la prmera fila del lcd
     Lcd_Chr(1, 18, clave2+48);
     Lcd_Chr(1, 19, clave3+48);
     Lcd_Chr(1, 20, clave4+48);
     Lcd_out(2, 17,"0000");


    // goto  inicio ;
}


  if (Tecla < 10){      // si TECLA es menor que 10 imprime el digito como clave nueva
    digitos++  ;

    if (digitos >4){
      digito_1=0;
      digito_2=0;
      digito_3=0;
      digito_4=0;
      digitos=1;
    Lcd_OUT(2, 17, "0000");
}

    VISUALIZA_clave_nueva();  // subruina que visualiza la clave nueva

//
}

//
}


//}
}// fin de programa principal
 
Atrás
Arriba