Convertir valor ADC para mostrarlo en LCD-AVR GCC

Tengo un problema con el ADC, estoy usando un AVR ATmega48p

Tengo un programa que me muestra el valor del ADC, de 0000 hasta 1024 ya que mi ADC tiene una resolucion de 10 bits. Mi voltaje de referencia es de 5 V. Y se puede mostrar en una LCD de 2x16.
Por lo que he leido hasta ahorita, debo multiplicar el valor del ADC con la resolucion, paara mostrar el voltaje, esto es Vres=5/1024=4.88mV, y eso por el valor ADC.

El problemas que que quiero mostrar este dato en el LCD y debido a que la respuesta tiene decimales, no se como hacer la conversión para mostrarlo.
que se muestre de la siguiente manera V= x.xx V

es por que la variable es "int"? por lo que entiendo solo acepta numeros enteros.
inicio en esto de la programacion avr gcc

Anexo mi programa

Código:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "lcd.h"

int adc_value;
uint16_t readADC(uint8_t channel);

void init_adc(void)
{
    DDRC &= ~(1 << 4);
	ADMUX=0b00100100;
	ADCSRA=_BV(ADEN)|_BV(ADEN)|_BV(ADIE)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADSC);
	sei();
}

void to_ascii(void)
{
	uint16_t resultado;
	resultado=readADC(4);

	LCDWriteIntXY(10,0,resultado,4);

	_delay_loop_2(0);
}

int main(void)
{
    InitLCD(LS_BLINK|LS_ULINE);
	init_adc();
	LCDWriteString("Dato:");
	while (1)
	{
	to_ascii();
	}
}

uint16_t readADC(uint8_t channel)
{
	
	uint16_t result;
	uint8_t i;
	
	ADCSRA = (1 << ADEN) | (1 << ADPS2);	//ADC aktiv, Prescaler 16
	ADMUX = channel;						//ADC0 kein mutiplexing
	ADMUX |= (1 << REFS0);					// AVcc als Versorgungspannung
	ADCSRA |= (1 << ADSC);					//ADC starten mit Dummyreadout

	while(ADCSRA & (1 << ADSC));
		
		result = 0;

	for(i = 0; i < 5; i++) 
	{
		ADCSRA |= (1 << ADSC);
	
			while(ADCSRA & (1 << ADSC));
		
    		  result += ADCW / 5;
     		 _delay_us(1);
	}

	ADCSRA &= ~(1 << ADEN)					;//ADC aus
	return result;
}
 

Adjuntos

  • P1260351.JPG
    P1260351.JPG
    232.9 KB · Visitas: 26
Última edición por un moderador:
El tipo int es Integer o entero, no admite decimales.

Hay dos posibilidades para mostrar un número con decimales en un LCD, una es trabajar con el tipo float y usar la función dtostrf (está en stdlib.h) o bien usar aritmética de punto fijo.

Suerte.
 
Con 4KB de flash en tu micro, no te recomiendo trabajar con numeros float, lo que tienes que hace es esto.

Tomas el valor de ADC y lo multiplicas por 488 luego te va salir un numero entero, luego ese numero lo conviertes a BCD con divisiones sucesivas y cuando muestres estos digitos en la LCD recuerdas poner el punto decimal donde debe ir.

Mira suponte que el ADC tiene un valor de 512 entonces

512 * 488 = 249856 luego lo conviertes a digitos BCD separados y los envias a la LCD solo recuerda poner un punto despues del 2 asi te quedaria 2.49856 que se aproxima mucho a 2.5 volts que es lo que deberia aparecer.

Prueba usar 48828 y veras que se va ir aproximando mas, el problema entonces sera el tamaño del resultado, para ello puedes usar variables tipo unsigned long que son variables de 32 bits
 
HOLA Resistance20:
tengo esta rutinita para hacer un voltimetro con atmega48, solo que esta en codevision avr no se si te interese

lcd_gotoxy(5,0);
lcd_putsf("''VOLTIMETRO''");
while (1)
{
x=read_adc(0);
v=(x*500)/255;
c=v/1000;
r=v%1000;
d=r/100;
r=r%100;
u=r/10;
lcd_gotoxy(4,3);
lcd_putchar(c+0x30);
lcd_putsf(".");
lcd_putchar(d+0x30);
lcd_putchar(u+0x30);
lcd_putsf("V");
};
}

y estas son las variables usadas

unsigned long int x,u,d,c,cen,v,r;
 
Yo hice un programa con la fórmula, pero no sé si está del todo bien.
Es la siguiente:

Código:
while (1)
      {
      // Place your code here
      //medicion RPM  
      X = 5.0 * adc_1 * 720;    
      RPM = (X / 1023)-1800;  //RPM = ((720 * X) - 1800);           
      lcd_clear();
      lcd_gotoxy(0,0);   
      sprintf (lcd,"****medicion****")
      lcd_puts(lcd);
      delay_ms(100); 
      
      //medicion PSI   
      adc_1=read_adc(0);
      adc_2=read_adc(1); 
      X = 5.0 * adc_2*10;   
      PSI = (X/1023) - 0;                   
      lcd_gotoxy(0,1);  
      sprintf (lcd,"PSI:%i/RPM:%i",adc_2,adc_1);                                      
      lcd_puts(lcd);                    
      delay_ms(100);
 
lo probaste y no funciona? que dudas tenes?

lo único que veo, pero no se si esta mal o no, solo que yo para leer varios canales del adc lo hago de otra forma

Código:
set_adc_channel(0);
adc_0=read_adc();
set_adc_channel(1);
adc_1=read_adc();

y también veo que usas el valor adc_1 antes de haberlo leido
 
Atrás
Arriba