Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] Problem with displaying adc value in lcd

Status
Not open for further replies.

manojkl

Newbie level 5
Joined
Aug 16, 2015
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
143
[Moved] Problem with the Proteus

I wrote a code for reading adc value from POT and displaying it in lcd
but proteus showing it as
Simulation not running in real time due to excessive cpu load
code is
Code:
// LCD module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections
 char message[]="ADC Value=";
 char *temp="00.00";
unsigned int value;
void main() 
{
  ADCON0=0X00;
   ADCON1=0X00;
   CMCON=0X07;
   TRISA=0XFF;
   TRISD=0X00;
  lcd_init();
  lcd_cmd(_LCD_CLEAR);
  lcd_cmd(_LCD_CURSOR_OFF);
  lcd_out(1,1,message);
  do
  {
   value=ADC_read(0);
   temp[0]=value/1000+48;
   temp[1]=(value/100)%10+48;
   temp[3]=(value/10)%10+48;
   temp[4]=value%10+48;
   lcd_out(1,12,temp);
   delay_ms(100);
   }
  while(1);
 }
 

Attachments

  • adc.c.zip
    45.1 KB · Views: 101

Re: [Moved] Problem with the Proteus

LCD Connections are wrong. This is the code according to the LCD connections. You have used PORTD for LCD. In code you were using PORTB for LCD.

ADCON1 setting was not correct.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// LCD module connections
sbit LCD_RS at RD2_bit;
sbit LCD_EN at RD3_bit;
sbit LCD_D4 at RD4_bit;
sbit LCD_D5 at RD5_bit;
sbit LCD_D6 at RD6_bit;
sbit LCD_D7 at RD7_bit;
 
sbit LCD_RS_Direction at TRISD2_bit;
sbit LCD_EN_Direction at TRISD3_bit;
sbit LCD_D4_Direction at TRISD4_bit;
sbit LCD_D5_Direction at TRISD5_bit;
sbit LCD_D6_Direction at TRISD6_bit;
sbit LCD_D7_Direction at TRISD7_bit;
// End LCD module connections
 
char message[] = "ADC Value";
char str[17];
unsigned int value;
 
void main() {
 
   CMCON = 0x07;
   ADCON1 = 0x8E;
   
   TRISA = 0x01;
   TRISB = 0x00;
   TRISC = 0x00;
   TRISD = 0x00;
   
   PORTA = 0x00;
   PORTB = 0x00;
   PORTC = 0x00;
   PORTD = 0x00;
   
   LCD_Init();
   LCD_Cmd(_LCD_CURSOR_OFF);
   LCD_Cmd(_LCD_CLEAR);
   LCD_Out(1,1,message);
   
   do {
       value = ADC_read(0);
       IntToStr(value, str);
       LCD_Out(2,1,str);
       Delay_ms(100);
   } while(1);
}

 
I am taking adc value from a temperature sensor and displaying it on a lcd screen.
the problem is that it takes the analog value and display double the actual value!!
if temperature is 30°c it shows value as 60.why is tht!
Code:
// LCD module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections
 char message[]="Temp is=";
 char str[20];
unsigned int value;
void main() 
{
  ADCON0=0X00;
   ADCON1=0X80;
   CMCON=0X07;
   TRISA=0XFF;
   TRISD=0X00;
   ADC_init();
  lcd_init();
  lcd_cmd(_LCD_CLEAR);
  lcd_cmd(_LCD_CURSOR_OFF);
  lcd_out(1,1,message);
  do
  {
   value=ADC_read(0);
   IntTostr(value,str);
   lcd_out(1,11,str);
   delay_ms(100);
   }
  while(1);
 }
 

What temperature sensor are you using ? LM35 ? If yes, are you using Vref+ not equal to 5V ? If not, then for 5V adc input you get 1023 raw adc value. If LM35 is used then it gives max 1.5V for 150 degree C. So, for 1.5 it is 150 therefore for 5V it is 500. So, you have to use

Code:
value = ADC_Read(0) * 500 / 1023;

value should be unsigned long type or use double type for value with below code.

Code:
value = ADC_Read(0) * 500.0 / 1023.0;
 
Code:
value = ADC_Read(0) * 500 / 1023;
Doesn't work according to C type conversion rules. You need to convert a multiplicand to long before the multiplication. value can be 16 bit integer.
Code:
value = (unsigned long)ADC_Read(0) * 500 / 1023;
 
are you using Vref+ not equal to 5V ? If not, then for 5V adc input you get 1023 raw adc value

An implementation that could save core processing is divide by 1024 (2^10) instead of 1023.
The added math's error (~0.1%) would be even smaller than the intrinsic accuracy of the sensor.
 
Hi,

An implementation that could save core processing is divide by 1024 (2^10) instead of 1023.
The added math's error (~0.1%) would be even smaller than the intrinsic accuracy of the sensor.

I've never seen a formula in the datasheet of an ADC or DAC where 1023 is used. 1024 most probably is the correct value.

I agree the error is negligible.

Klaus
 
Why 1024 has to be used ? See if the LM35 gives 1.5V then it is 150 degree C. So for 5V it is 500. So if we use

Code:
value = 1023 * 500 / 1023;
we get 500 and if adc input is 1.5V then we get

Code:
value = 306.9 * 500.0 / 1023.0;

= 150.

306.9 * 500 / 1024.0 = 149.854
 

The PIC datasheet clarifies the point:

The ideal transfer function of the A/D converter is as follows: the first transition occurs when the analog input voltage (VAIN) is 1 LSb (or Analog VREF / 1024)

The datasheet shows an offset of 0.5 LSB with the ideal transfer characteristic, but it doesn't change the gain.
 
Hi,

it is independent of LM35.
It is the decoding scheme of the ADC.

And we talking about a "one LSB detail", so it is not very important. It is a more "theoretical" discussion. For 10 bit converter it may be not important but for 8 bit converters it is getting more important.

You ask why 1024 has to be used? --> because the datasheet says.

Usually with 10 bit ADCs with 5.000V reference. (Only a few ADCs split a half LSB for upper and lower value)
one LSB represents 5.000V / 1024 = 4.883mV
so 0 LSB is everything below 4.883mV. (it could be 0V, but it also could be -0.1V or +0.003V)
1 LSB is everything between 4.883mV and 9.766mV
...
1022 LSB is everything between 4.990V and 4.995V
1023 LSB is everything above 4.995V. it could be 4.996V or 5.000V or 5.100V
The exact value for 5.000V is 1024 LSB, but this is out of ADC range of 0...1023

But I se the problem with displaying 500 with an ADCvalue of 1023 LSBs. Therefore you use the 1023 method. And it is OK to do so.
...
I am designing reliable measurement tools for the industry. And here i take care of the problem.
If I want to measure 0...5V, then i expand my ADC input range on both ends a little bit (let´s say 0.2V) . For sure i need some offset and gain correction.
But the benefit is I can reliably decide "underflow", valid 0..5V and "overflow".
How much headrom i use, depend on ADC and analog circuitry offset and gain error range.

For further discussion we should open a new thread.

Klaus
 
  • Like
Reactions: d123

    d123

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top