Reading temperature sensor's range error.

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm interfacing a temperature sensor(LM34) to my AVR, and it's range as known from the data sheet is -50 F to +300 F.

but the value that is displayed on the LCD is from 0 F to 50 F and when i go beyond these values it stops on 0 if i'm trying to read minus and on 50 if i'm trying to read more than 50.

#include <util/delay.h>
#include <stdio.h>

#define ADCSRA                                       (*((volatile unsigned char *)0x26))
#define ADMUX                                        (*((volatile unsigned char *)0x27))
#define ADCH                                         (*((volatile unsigned char *)0x25))
// define port A
#define DDRA                                         (*((volatile unsigned char *)0x3A))
#define PORTA                                        (*((volatile unsigned char *)0x3B))
#define PINA                                         (*((volatile unsigned char *)0x39))
// define port B
#define DDRB                                         (*((volatile unsigned char *)0x37))
#define PORTB                                        (*((volatile unsigned char *)0x38))
#define PINB                                         (*((volatile unsigned char *)0x36))

#define LCD_RS 0      //LCD RS
#define LCD_RW 1      //LCD RW
#define LCD_EN 2      //LCD EN                             

void delay_us(unsigned int d)
{
	while(d) {
		_delay_us(1);
		d--;
	}
}

void lcdCommand(unsigned char cmnd)
{
	LCD_DPRT = cmnd;                //send cmnd to data port
	LCD_CPRT &= ~(1<<LCD_RS);       //RS = 0 for command
	LCD_CPRT &= ~(1<<LCD_RW);       //RW = 0 for write
	LCD_CPRT |= (1<<LCD_EN);        //EN = 1 for H-to-L pulse
	delay_us(1);                    //wait to make enable wide
	LCD_CPRT &= ~(1<<LCD_EN);       //EN = 0 for H-to-T pulse
	delay_us(100);                  //wait to make enable wide
}

void lcdData(unsigned char data)
{
	LCD_DPRT = data;                //send data to data port
	LCD_CPRT |= (1<<LCD_RS);        //RS = 1 for data
	LCD_CPRT &= ~(1<<LCD_RW);       //RW = 0 for write
	LCD_CPRT |= (1<<LCD_EN);        //EN = 1 for H-to-L pulse
	delay_us(1);                    //wait to make enable wide
	LCD_CPRT &= ~(1<<LCD_EN);       //EN = 0 for H-to-l pulse
	delay_us(100);                  //wait to make enable wide
}

void lcd_init()
{
	LCD_DDDR = 0xff;                //all pins in port C output
	LCD_CDDR = 0xff;                //all pins in port D output

	LCD_CPRT &= ~(1<<LCD_EN);       //LCD_EN = 0
	delay_us(2000);                 //wait for init
	lcdCommand(0x38);               //init. lcd 2 line, 5 x 7 matrix
	lcdCommand(0x0e);               //display on, cursor on
	lcdCommand(0x01);               //clear LCD
	delay_us(2000);                 //wait
	lcdCommand(0x06);               //shift cursor right
}

void lcd_gotoxy(unsigned char x, unsigned char y)
{
	unsigned char firstCharAdr[] = {0x80, 0xc0, 0x94, 0xd4};
	lcdCommand(firstCharAdr[y - 1] + x - 1);
	delay_us(100);
}

void lcd_print(char* str)
{
	unsigned char i  = 0;
	while (str[i] != 0)
	{
		lcdData(str[i]);
		i++;
	}
}

int main(void)
{

	char buffer[12];

	DDRA |= 0b00000111;             //pin 0,1,2 output & pin 3,4,5,6,7 input.
	DDRB |= 0xFF;                   // make port B output.
	ADCSRA |= 0x87;                 //make ADC enable and select ck/128.
	ADMUX |= 0xE6;                  //2.56 v vref, select ADC6 and make left justified.

	lcd_init();
	lcd_gotoxy(1, 1);
	lcd_print("temperature:");

	while(1)
	{
		ADCSRA |= (1 <<	0x06);                               //start conversion

		while (!(ADCSRA&0b00000101));
		PORTB = ADCH;

		if (ADCSRA&0b00000101)
		{
			sprintf(buffer, "%d", PORTB);
			lcd_gotoxy(1, 2);
			lcd_print(buffer);
		}
		return 0;
	}
}

 

 

* Moved to the correct forum. Moderator *

 

This topic has a solution.
Last Edited: Wed. Jun 14, 2017 - 12:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Then you do:

while (!(ADCSRA&0b00000101));

what on Earth is the purpose of that line? You just set bits 2 and 1 so surely even if this were just:

ADCSRA&0b00000100

then the result will always be 00000100 won't it? Then you apply ! so the +ve value (true) is turned to false so the while() loop exits immediately?!?

 

The "usual" sequence for making an ADC reading is:

ADCSRA |= (1 << ADSC);
while (ADCSRA & (1 << ADSC)); // bit stays high during conversion

Also what on earth is this nonsense about??....

// define port B
#define DDRB                                         (*((volatile unsigned char *)0x37))
#define PORTB                                        (*((volatile unsigned char *)0x38))
#define PINB                                         (*((volatile unsigned char *)0x36))

Why on earth aren't you using <avr/io.h> which has all this (and about 100+ other things) already defined for you?

 

Then you do:

	PORTB = ADCH;

and later:

sprintf(buffer, "%d", PORTB);

what on earth is that all about - why are you storing the ADCH reading to the PORT output register?

 

This all looks EXTREMELY confused indeed.

 

Oh and this:

void lcd_print(char* str)
{
	unsigned char i  = 0;
	while (str[i] != 0)
	{
		lcdData(str[i]);
		i++;
	}
}

why the array here (and then limit it to 127 characters), why not:

void lcd_print(char* str)
{
	while (*str)
	{
		lcdData(*str++);
	}
}

which is the "usual" way to do this?

Last Edited: Tue. Jun 13, 2017 - 06:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First of all, i'm using atmega32

Second, i'm still learning so i'm not good as you when it comes to write a C code so chill out.

Third, i modified all the lines in my code that you didn't like with your code,and (comes in fourth).

Fourth, you didn't answer my question which is why i can't read more than 50 and less than 0, and yes your code is better than mine but it didn't help me with my problem.

Fifth, i'm not using this library avr/io.h because i'm still learning so i want to do every thing by my self to know how to deal with ports. 

Last Edited: Tue. Jun 13, 2017 - 05:46 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The LM34 is an analog temp sensor (for those reading this and don't know) if you connect it's output directly to the analog input on the AVR and connect its power and gnd to VCC and gnd, it outputs a voltage that is 10mV / degree, so it can only output temps down to zero volts.   So negative temp are not possible with this simple circuit, because the ADC can not read negative voltages.

In order to read negative temps, you will need to bias up the output, or in other words add an offset to the output.  See diagram #17 in the datasheet.

 

I have used this temp sensor a lot over the years, it works pretty good, if you calibrate your setup at a single point (middle of range of interest) it should be with in spec of a couple of degrees.  

 

Good luck have fun learning.  Don't take criticism of your code to hard, the suggestions offered here will make you a better programmer.  

 

Jim