# ¿Como mostrar variables Float en una LCd? con -WinAVR-



## StrySG (Feb 23, 2010)

Tengo un pequeño problema no he podido imprimir en un LCD alfanumerica una variable del tipo float seguramente el problema esta en la funcion de control de la lcd que utilizo en win AVR es la siguiente

```
#include<stdio.h>
#include<avr/io.h>
#include<util/delay.h>
void delay_ms(int n){
while(n--){
_delay_ms(1);
}
}
#define RS 2
#define EN 3
void EN_pulse(void){
	PORTD|=(1<<EN);
	_delay_us(1);
	PORTD&=~(1<<EN);
	
} 
void lcd_general(char dato,char tipo){
	PORTD=dato&0xf0;
	if(tipo)PORTD|=(1<<RS);
	EN_pulse();
	PORTD=(dato<<4);
	if(tipo)PORTD|=(1<<RS);
	EN_pulse();
	_delay_us(40);
}
#define lcd_char(l) lcd_general(l,1)
#define lcd_cmd(c) lcd_general(c,0)

void lcd_clear(void){
	lcd_cmd(1);
	delay_ms(2);
}

void lcd_init(void){
	PORTD=0;
	DDRD|=0xfc;
	delay_ms(5);
	
	PORTD=0x30;
	EN_pulse();
	delay_ms(5);

	PORTD=0x30;
	EN_pulse();
	delay_ms(5);
	
	PORTD=0x30;
	EN_pulse();
	delay_ms(5);

	PORTD=0x20;
	EN_pulse();
	delay_ms(5);
	
	lcd_cmd(0x28);
	lcd_cmd(0x0E);
	lcd_cmd(0x06);
	lcd_clear();
	
}
//********************MANEJO DEL STDIO.H****************************

int lcd_putchar(char c,FILE *stream){  //file se agrega en stdio.h
if((c==10)||(c==13)) //habilita \n para nueva linea
	lcd_cmd(0xc0);    //comando para salto de linea
	else
	lcd_char(c); // escribe el texto 
	return 0;    //retorna de donde vino con valor 0

}
FILE lcd=FDEV_SETUP_STREAM(lcd_putchar,NULL,_FDEV_SETUP_WRITE); //declaraciones de stdio.h

void print_init(void){
	lcd_init();
	stdout=&lcd; // habilita printf con ayuda de stdio.h el comando de stdio.h es enmascarado con 
    // el contenido de la lcd 	
}
```

como no se mucho del manejo de la libreria stdio.h no tengo ni idea de como hacer que se imprima una variable "float" en la lcd alfanumerica, por la funcion que manejo manda datos a la lcd del tipo "char"...

Si hay alguien que maneje WIN AVR y una funcion o algun otro metodo para imprimir variables del tipo "float" estaria muy agradecido con que comparta el código o cualquier ayuda posible...


----------



## Beamspot (Feb 24, 2010)

Por aquello de que las librerías del prinf con floats ocupan varios KB de flash, yo nunca he usado dichas librerías con el WinAVR, y siempre me he currado mis propias presentaciones en LCD a bajo nivel para ahorrar KB (no se porque siempre me quedo corto de memoria).

En otro sistema (que no tiene nada que ver con AVRs), lo que hago es un sprintf que en lugar de mandar nada a la pantalla, lo que hace es 'imprimir' en un buffer de memoria. Cosa útil, ya que a mi (por mis manías particulares) me gusta tener el control del LCD y mandar retazos de bytes o buffers de memoria, en lugar de 'redirigir' librerías y demás. De esta manera puedo enviar un buffer de memoria o una cadena de datos directamente de la memoria Flash, o copiar los datos de una memoria (generalmente uso Flash) externa. O redirigirlo todo al puerto serie.

Siento no poder ser de más ayuda.


----------



## StrySG (Feb 24, 2010)

No creo que haya mucho problema en cuanto a espacio de memoria cuando usas un ATMEGA16 o ATMEGA 32 asi que si es una libreria grande no importa, pero quisiera saber como puede imprimir en la lcd una variable del tipo float,

Alguien me dijo que era cuestion de tambien manipular bien el Makefile que creas al hacer tu proyecto no se si es verdad...

Si alguien puede ayudar con algun código o cualquier pista de utilidad se lo agradeceria.


----------



## cosmefulanito04 (Feb 24, 2010)

Usa un fprintf y transforma esa variable flotante en un string. El costo de eso, son 1 o 2 kb de memoria de codigo por el uso de esa funcion.

Otra alternativa sera hacer esto, ej:

pepe=1,3402 (Supone que queres mostrar este dato)


```
...
unsigned char digito[5]={'0','0','0','0','0'};
...

void transformar(unsigned float pepe)
{
  usnigned int auxiliar=0;
  auxiliar=(int) pepe*10000;  (auxiliar=13402; y elimino la coma casteando)
  digito[4]=auxiliar%10+0x30;  // El digito de menor peso "2", el 0x30 sera el 0 en nº ascii.
  auxiliar=(int) auxiliar/10; // auxiliar=1340
  digito[3]=auxiliar%10+0x30;  // El 2 digito de menor peso "0"
  auxiliar=(int)auxiliar/10; // auxiliar=134
  digito[2]=auxiliar%10+0x30; // El 3er digito de menor peso "4"
  auxiliar=(int)auxiliar/10; // auxiliar=13
  digito[1]=auxiliar%10+0x30; // El 4to digito de menor peso "3"
  digito[0]=(int)auxiliar/10+0x30; // El ultimo digito, el mas significativo "1"
}
...
```

El codigo lo podes pulir con un while/for, ya que es facil ver que el proceso es siempre el mismo, hasta el ultimo digito. Por ultimo, tenes que tener en cuenta donde poner la coma cuando presentes el numero en el LCD.

Lo malo de este ultimo codigo, es que requiere varias operaciones para obtener los digitos (operacion complejas como la division y el resto), con lo cual deberas tener en cuenta las perdidas de tiempo que la conversion pueda generarte en un programa.


----------



## Beamspot (Feb 24, 2010)

Yo uso un código similar al último descrito, pero la 'pega' es que necesitas saber dónde está la coma, es decir, el 10000 que multiplica a pepe en la línea sale de algún lado.  Las rutinas de printf con floats, si no voy equivocado están entre 4 y 8 KB (eso sí, con tooodos los detallitos y filigranas posibles), más que nada porque incluyen algo de matemáticas en coma flotante, que ocupan bastante espacio también. Aún así, coge este dato con pinzas. Yo tuve que hacer filigranas para que me cupiese el último programa que hice en un ATmega128, aunque había más de 20KB de textos varios y en varios idiomas.


----------



## cosmefulanito04 (Feb 24, 2010)

Si en eso tenes razon, pero podria hacer esta manganeta:

Suponiendo que uno sabe que mas de tantos digitos enteros no puede pasar la variable, por ejemplo tu numero posible sera:

XXX,XXXXX 

pepe=102,10234


```
...
unsigned char decimales[5]={'0','0','0','0','0'}, enteros[3]={'0','0','0'}; 
...

void transformar_decimal(unsigned float ); // Misma funcion que puse arribla

void transformar_entero(unsgned float pepe)
{
  unsigned int aux=(int) pepe; // aux=102;
  ..//  Repito el proceso que mencione antes.
}
```

Nuevamente, el codigo se podria retocar usando while/for, y empleando una misma funcion tanto para decimales como enteros utilizando un flag para diferenciarlos.


----------



## Beamspot (Feb 25, 2010)

Si el número de dígitos está más o menos controlado, entonces la cosa se puede simplificar. Personalmente evito totalmente en lo que puedo las mates en coma flotante, y acabo haciendo toda la parte en coma fija a mano. La matemática entera es mucho más rápida, eficiente, ocupa menos código, simplifica mucho el programa final, evita problemas, y facilita luego el posterior uso y manipulación para presentar en pantalla y/o almacenar.

Así que la propuesta de cosmefulanito04 es el camino que personalmente he tomado en varias situaciones en las que he tenido que usar decimales. Parece más engorroso y una tontería acabar haciendo las cosas a 'pico y pala' en lugar de usar librerías, pero cuando los programas empiezan a complicarse, o uno se coge un micro muy sobredimensionado o acaba teniendo problemas.


----------



## StrySG (Feb 25, 2010)

Gracias son interesantes formas de manejar las variables int, en caso de que me quedara corto de espacio, no tendría mas opcion que aplicarlas...

Pero chequeando un poco en el Makefile, al crearlo no me habia percatado de que hay una opcion en la que se puede habilitar la libreria que maneja las comas flotantes, (printf options)  (floatpoint), tuve que crear un nuevo Makefile.

Afortunadamente la funcion de manejo de la LCD que esta al principio tambien la acepta.

He coseguido mostar la variable tipo 'float' con su coma flotante sin mayores problemas, el codigo aumento su tamaño pero no muy significativamente, supongo que es esa una de las ventajas de los AVR.

Gracias por la ayuda acabo de solucionar el problema .


----------



## R-Mario (Sep 6, 2010)

Oye una pregunta alguien sabe como funciona la libreria EEPROM y ADC del WinAVR es decir como se usan las funciones


----------



## Beamspot (Sep 7, 2010)

Dada la sencillez de funcionamiento de estos dos periféricos (a no ser que uses los Xmega), no entiendo porque necesitas librerías, si las rutinas como mucho te ocuparán una veintena de líneas en C. Puedes explicar mejor tu problema?


----------



## R-Mario (Sep 7, 2010)

Ha pues se supone que las librerias estan hechas para ahorrar tiempo en programacion y no preocuparte mucho por donde estan ubicado esto y como funcionan aquello entonces yo solo por curiosidad tenia la duda de como funcionan estas dos librerias en el WinAVR, de hecho lo he implementado como tu dices pero queria ver como hacerlo con estas librerias, bueno a ver si alguien sabe


----------



## Beamspot (Sep 7, 2010)

No se que tal estan Uds en cuanto a programación de aplicaciones, pero en mi caso, de la parte de drivers de HW y librerías de periféricos, en una semana tengo escrito lo que tengo para el AVR. Sin embargo, para el grueso de la aplicación, generalmente necesito meses.

Así pues, las librerías me ahorran, como mucho, un dia o dos de trabajo, que luego, a la hora de depurar, igual acaban por fastidiármelo igualmente. Ergo no uso librerias para hacer funciones que sólo ocupan unas pocas decenas de líneas.

Es más, hace poco empecé a hacer ciertas pruebas y tonterías con librerías, para al final tener que escribírmelas todas de nuevo debido a que las que venían hechas no servían para mis propósitos.


----------



## R-Mario (Sep 7, 2010)

Ok entiendo, pero nuevamente yo lo decia por mera curiosidad de querer usarlas, aunque no hay que negar que si ayudan mucho digo algo tan sencillo con _delay_ms() es muy buena te evitas estar calculando ciclos en base a la velocidad y demas pero bueno cada quien como le guste, yo por otro lado sigo esperando a ver si alguien conoce como funcionan las librerias ADC y EEPROM he hecho unas pruebas pero no doy y luego la explicacion de WinAVR no es muy buena deja mucho que desear


----------



## R-Mario (Sep 11, 2010)

Oigan alguien sabe como convierto un numero flotante en una cadena de caracteres


----------



## Beamspot (Sep 13, 2010)

Aparte de las librerías de print y sus variantes (sprintf, etc), la única manera que conozco es hacerse uno mismo las mismas.

Hasta donde yo se, dichas librerías, si no las usas para nada más, te gastarán entre 4 y 8 KB de memoria de programa sólo por el hecho de imprimir comas flotantes.

En la parte matemática, me curré buena parte de las rutinas de DSP y conversión que hice para hacerlo todo en coma fija, y luego lo 'convertía' a texto con mis propias rutinas (que al fin y al cabo, todo era coma fija, así que lo único que hacía, era poner la coma en un sitio concreto). La reducción en memoria de programa, memoria RAM y sobre todo, el aumento de velocidad de cálculo era realmente jugosa. Y además, muy instructiva. Todo en menos de los 8K de la librería completa.


----------



## R-Mario (Sep 13, 2010)

Pues me encontre un ejemplo mas o mejos asi: aver si alguien me puede decir como se podria modificar para hacerlo que funcione con numeros float porque este solo funciona con enteros
void itoa(int n; char s[])
{
int i, sign;
if((sign = n) < 0)    ;Para verificar si es entero positivo
n = -n;
i=0;  

do{     ;porque al menos debe tener un digito
s[i++] = n%10 + '0';      ;No lo entendi, se que saca el residuo y de esa manera lo va convirtiendo pero para que le suma el '0'
}while((n /= 10) > 0);

if(sign < 0)
s[i++] = '-';    ;Por si el numero era negativo
s_ = '/0';  ;Le agrega el fin de cadena
reverse(s);   ;Se supone que es una funcion que invierte las posiciones de los caracteres

A ver si alguien me lo puede explicar bien y si es posible implementarlo para su uso con floats_


----------



## StrySG (Sep 13, 2010)

Te recomiendo que para el uso de la EEPROM en WINAVR no utilices sus librerías por que te ocuparan mas campo de lo necesario, para el uso de la EEPROM si revisas las *hoja de datos *del dispositivo, por ejemplo un ATMEGA32, en la seccion de EEPROM memory, esta un pequeño código en lenguaje C que permite escribir y leer la EEPROM, luego creas  2 sub-programas, copias el codigo que esta en la hoja de datos  y al llamarlos desde tu programa principal realicen el manejo de la EEPROM...

Para el ADC también es preferible que tu mismo te crees sub-programas o macros a partir de las hojas de datos, pero si por alguna razon no puedes hacerlo busca en  http://www.avrfreaks.net/index.php?name=PNphpBB2&file=index , en este foro hay funciones o subrutinas en lenguaje C para manejo de los recursos de AVRs.



> No lo entendi, se que saca el residuo y de esa manera lo va convirtiendo pero para que le suma el '0'



Al sumar '0' le esta añadiendo el codigo ASCCI del 0, asi si el resultado fuese 2 le suma '0' que equivale a 30h y quedara 32h que es el equivalente en ASCCI al numero 2 e imprime el numero 2 en la pantalla.


----------



## R-Mario (Sep 13, 2010)

Haaa ya vi para que lo del '0' es como cuando quieres convertir numeros binario a bcd y le sumas 30H para que te de el numero ascci si cierto perdon es que cuando vi el '0' no me imagine que se referia a eso jajaja que tonto, bueno todos lo dias se aprende algo nuevo o no!!!!

Respecto a las rutinas pues ya las hice con puro C sin usar librerias bueno nada mas la IO.h pero eso si ya es por mera flojera.

Yo queria aprender a usar las librerias por pura curiosidad y ver que tanto crece el programa, gracias pro tu respuesta StrySG


----------



## R-Mario (Sep 28, 2010)

Cierto lo de la eeprom es mas muy sencillo con el mismo ejemplo que ponene en las datasheets, bueno volviendo al tema entonces en resumen alguien tiene una buena rutina para convertir numeros flotantes en caracteres


----------



## miborbolla (Abr 15, 2011)

Hola se que estan comentando sobre WINAVR, yo uso codevisionAVR y aqui dejo un pequeño ejemplo de como usar sprintf para dejar en una variable string, el resultado que se desea, Aqui el codigo: 


#include <lcd.h>
#include <stdio.h>
int x; // variable X usada en el for
char strbuff[40]; //Variable string donde se deposita el resultado de sprintf
void main(void)
{
lcd_init(40); //inicializo LCD en mi caso es de 40 caracteres de Ancho X 2 lineas
lcd_gotoxy(0,0);
lcd_putsf("muestra X en Decimal, Ascii y Hexadecimal"); //muestra titulo en LCD
while (1)
      {
      for (x=0;x<=254;x++){
      sprintf(strbuff,"Dec=%d Ascii=%c Hex=%x ",x,x,x); //el despliegue de sprintf queda despositado en la variable strbuff.
      lcd_gotoxy(0,1);    //posiciona el "cursor" al principio de la segunda linea
      lcd_puts(strbuff);  // despliega el contenido de strbuff en el LCD
      delay_ms(200);    // retardo de tiempo    

      }
      }
}


Supongo que por ser lenguaje "C" debe funcionar muy similar o se puede adaptar este codigo, a mi me a ahorrado mucho tiempo de programacion y puedo desplegar todo lo que quiera.

Saludos.


----------

