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
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