Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Displaying ADC value in LCD using PIC

Status
Not open for further replies.

avoidance

New Member
Hi all,

I am in a situation where I need to read ADC value and display it in LCD. Im using PIC18F4620. I have interfaced the LCD with the PIC and it can display normal strings very well. But I have been caught in a difficult situation when I try to read an analog value and display it in my LCD. This is my simple code:

// LCD module connections
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;
// End LCD module connections



int temp;


void main() {
TRISB = 0; //PORTB as output
TRISA = 0xFF; //PORTA as input
ADCON1 = 0x7A; // Configure all ports with analog function as digital except RA2
CMCON |= 7; // Disable comparators
Lcd_Init(); //Initialize LCD

while (1){
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
temp = 5000*ADC_Read(2)/1023;


Lcd_Out(1, 1, temp);
Delay_ms(500);
}
}

There are few problems here. I am not sure what value will the variable 'temp' have. When I use the function LCD_Out, I get a warning that reads: "Implicit conversion of int to ptr" and the LCD would show a string of funny symbols. When I use LCD_Chr, it doesnt give any warning, but I only get to see a single numeric character on the display. Furthermore, I am not sure if I should convert temp from hex to decimal or binary to decimal since I am not sure the nature of the read value. Please help me on this, thanks in advance. Your suggestions/opinions are much much anticipated.
 
This would do better if posted the "MicroControllers" forum.
 
In C programming, functions that requre pointers don't work with other data types. That's what is meant by being strongly "typed." What does the interface for Lcd_Out look like?

As a quicky, you might try this:

Lcd_Out(1, 1, &temp);

If your function accepts integer pointers, it might work. If it only accepts string pointers, then you will need to convert your value to an appropriate string.
 
Last edited:
In C programming, functions that requre pointers don't work with other data types. That's what is meant by being strongly "typed." What does the interface for Lcd_Out look like?

As a quicky, you might try this:

Lcd_Out(1, 1, &temp);

If your function accepts integer pointers, it might work. If it only accepts string pointers, then you will need to convert your value to an appropriate string.

I am using a typical 2x16 LCD interface to my microcontroller. I am using mikroC compiler, and it gets really confusing on how to handle strings here. Lcd_out is a function that is already provided in MikroC's LCD library. Adding '&temp' doesnt change anything. I guess I have to somehow convert it into string.

It seems like you are using mikroC. You should convert your temp value to character string first. Check out this:
Experiments with PIC16F628A: Experiment No. 4 : Reading Temperature Values from DS1820 using 1-Wire Protocol

-Raj
Experiments with PIC16F628A

Yes I am using MikroC. I was trying to convert it into string but I had no luck, but thanks to the link that you shared there, I now have some idea. I will try it out and post the results here again later. Thanks alot, that's a reallly HUGE help.
 
I am using a typical 2x16 LCD interface to my microcontroller. I am using mikroC compiler, and it gets really confusing on how to handle strings here. Lcd_out is a function that is already provided in MikroC's LCD library. Adding '&temp' doesnt change anything. I guess I have to somehow convert it into string.

QUOTE]

I think the link by rajbex is your solution. You have to do a string conversion before sending the data to the LDC. I would just use the code just as it's written, and include it in your module. Hopefully, you want to display celcius, as that's what the code converts to. For farenheit, you'll need to modify the code, I think.
 
Hi again, I have successfully modified my code, and thankfully I am seeing a better display on my LCD now. I am just wondering, how do I scale it? And, what is the maximum value of voltage than an ADC of a PIC can detect, is it 5V? I am seeing numbers like 255, while a multimeter measurement shows values which is slightly above 5V (5.32V). And what does Vref do?

So I am wondering if i can still detect voltage values which are greater than 5V, and how do I scale it so that my display would show 5V instead of 255?
 
The maximum analog voltage you can give to any ADC pin is 5V. So whatever analog signal you are trying to measure, make sure that the i/p volt to the PIC pin should not exceed beyond 5V. If you want to measure voltage more than 5V, you should use resistor network. The values of resistances required depends on the range of input voltage. You said you can see number 255 for input voltage 5.32V. For all values above 5V, you will get the same number which is the saturated value. If you are seeing 255, it means you are reading only 8-bits of A/D conversion. You can read all 10-bits for better resolution.

What does Vref do?
Suppose in your experiment, if you are sure that your input analog signal will always between 3-5V, then you can fix the Vref pin to exact 3V, and use the entire 10-bit range to measure the voltage between 3-5V. That means you will get reading 0 for i/p 3V, and 1023 for i/p 5V or more. This enhances the accuracy of analog measurements.

- Raj
Experiments with PIC16F628A
 
Hi Raj, love your blog. I've been in EE for decades, but don't know too much about Pic's. I've bookmarked you and am going to try some of your experiments.

Sorry for the O/T
 
Hi again, i need some suggestion. I am working on a project that is powered by a rechargeable 9V battery. And I need to display the battery level indicator through the LCD. How can I achieve this? For development purposes, I have been supplying constant 5V to the board. I am thinking of voltage regulator in the final stage, but will it be able to show me if the voltage has gone down since it won't read anything more than 5V? Another option is to measure the voltage after the regulator, which will be 5V. But if the power from the battery decreases, will it still be able to power my PIC (since the power would have gone below 5V)? And do you have experiment example using resistance network? Where can I find more about this?

I do have another question. Yesterday, I tried measuring some triple A battery. Multimeter shows that it was of 1.58V. But when I measured using my ADC, it still showed 255 (5V). How is this possible? And when nothing is connected, it would show 0 sometimes and 230 or 242 at other times. What could have been wrong?
 
Can you post your exact circuit and code?

- Raj
Experiments with PIC16F628A


Hi raj, thanks for your attention. The following is my up to date code:


// LCD module connections
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;
// End LCD module connections



void main() {
long scale;
int temp;
char print;
char txt[7];

TRISB = 0; //PORTB as output
TRISA = 0xFF; //PORTA as input
ADCON1 = 0x0E; // Set AN0 channel pin as analog
CMCON |= 7; // Disable comparators
Lcd_Init(); //Initialize LCD



while (1){
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
temp = ADC_Read(0);
scale = 5000*temp;
scale=scale/1024;
temp=scale;

print = temp/1000;
Lcd_Chr(1, 1, print+48); //print 1st digit (print=5, 5+48 = 53. in ascii, 53 is character 5
Lcd_Chr_CP('.');
print = (temp/100)%10;
Lcd_Chr_CP(print+48); //print 2nd digit
print= (temp/10)%10;
Lcd_Chr_CP(print+48); //print 3rd digit
print=temp%10;
Lcd_Chr_CP(print+48); //print 4th digit
Lcd_Chr_CP('V');
IntToStr(temp, txt);
Lcd_Out(2,1,txt); //display ADC value
Delay_ms(1000);
}
}

How can I post my circuit here? I don't have any schematics. My circuit has LCD interfaced to port B, and the LCD works fine. For ADC purposes, I directly connect AN0 to VDD using a jumper. There is nuthin else unusual in my simple circuit. Any suggestion what Im doing wrong? Thanks again for your attention.
 
Update: changing IntToStr(temp, txt); into IntToStr(ADC_Read(0), txt); does show me correct ADC result. But the converted voltage remains wrong. That means, my ADC is correct, but something is terribly wrong with the conversion or the printing. I have tried various methods and yet all yields the same results.
 
// LCD module connections
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;
// End LCD module connections



void main() {
unsigned int temp, hold, sum;
char txt[7], print[7];


TRISB = 0; //PORTB as output
TRISA = 0xFF; //PORTA as input
ADCON1 = 0x0E; // Set AN0 channel pin as analog
CMCON |= 7; // Disable comparators
Lcd_Init(); //Initialize LCD



while (1){
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
hold = ADC_Read(0);
IntToStr(hold, txt);
sum = ((txt[2]-48)*1000)+((txt[3]-48)*100)+((txt[4]-48)*10)+(txt[5]-48);
temp = 5000*sum/1024;




LCD_Chr(1,1,temp/1000+48);
LCD_Chr(1,2,46);
LCD_Chr(1,3,(temp/100)%10+48);
LCD_Chr(1,4,(temp/10)%10+48);
LCD_Chr(1,5,temp%10+48);
LCD_Chr(1,6,86);
Lcd_Out(2,1,txt);
delay_ms(500);

/*Lcd_Chr(1, 1, print+48); //print 1st digit (print=5, 5+48 = 53. in ascii, 53 is character 5
Lcd_Chr_CP('.');
print = (temp/100)%10;
Lcd_Chr_CP(print+48); //print 2nd digit
print= (temp/10)%10;
Lcd_Chr_CP(print+48); //print 3rd digit
print=temp%10;
Lcd_Chr_CP(print+48); //print 4th digit
Lcd_Chr_CP('V');
IntToStr(ADC_Read(0), txt);
Lcd_Out(2,1,txt); //display ADC value
Delay_ms(1000);*/
}
}

Latest Code
 
Summary of my problem:

-Objective: To read ADC value and display in voltage ranged 0V to 5V.

-when ADC_Read(0) is converted to string through IntToString and printed, it yields the correct result (1023 for 5V, 316 for 1.5V and so on)

-when ADC_Read(0) value is scaled as 0V-5V voltage, it will show 0.003V in LCD although the ADC_read(0) shows 1023.

-replacing ADC_Read(0) with integer 1023 in the code results in a proper printing for scaled result: 4.995V in LCD. This shows that the scaling formula and printing code is correct.

-In the latest attempt, since IntToString could print the proper value of ADC_Read, the string txt (outcome of IntToString) is used to reconstruct the integer that corresponds to ADC_Read value (represented by variable sum). Theoretically, the integer 'sum' could never go wrong since it is printed correctly in string 'txt'. In debugging mode, ADC_Read was replaced by an integer, and variable 'sum' will produce the same number with the integer which is in ADC_Read's place. When ADC_Read is used, again it shows 0.003V.

-In short, my ADC_Read(0) contains the correct value by I have problem scaling it to 0-5V values.

This is puzzling. Obviously im doing something wrong. Someone please point me at the right direction. :roll:
 
Why do you convert the ADC reading to a string BEFORE mathamatical operations? I would think you want to do all the manipulations and THEN convert the final result.
 
Last edited:
It was part of the troubleshooting code, it was not intended to be placed there. Mathematical operation of the ADC reading was giving false result all the while, so like I said, in a desperate attempt, i tried to read back values from converted string to avoid reading directly form ADC_Read. If nuthin is working out I guess its worth a try to go all out. Besides, the converted string plays no part in the scaling. It is just there to indicate whether or not my ADC is giving the correct value, as such, placing is before or after makes no different (refer to my second posted code).

Anyhow, Ive managed to solve the puzzle. The problem has been in displaying results in LCD_Out. If LCD out has some huge number in it, it will display false result. For example, LCD_Chr(1,1,(5000*hold/1024)/1000+48); will not display correctly, whereas LCD_Chr(1,1,(5*hold/1024)+48) would have no problem (both of them are similar). So the problem was in type conversion. This is my updated code:

// LCD module connections
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;
// End LCD module connections



void main() {
unsigned int hold;
char txt[7];


TRISB = 0; //PORTB as output
TRISA = 0xFF; //PORTA as input
ADCON1 = 0x0E; // Set AN0 channel pin as analog
CMCON |= 7; // Disable comparators
Lcd_Init(); //Initialize LCD



while (1){
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
hold = ADC_Read(0);
IntToStr(hold, txt);

LCD_Chr(1,1,5*hold/1024+48);
LCD_Chr(1,2,46);
LCD_Chr(1,3,(50*hold/1024)%10+48);
LCD_Chr(1,4,(20*hold/41)%10+48); //20/41 =~ 500/1024
LCD_Chr(1,5,86);
Lcd_Out(2,1,txt);
delay_ms(500);

}
}

As you can, the result has been reduced from 4 significant figures to 3 significant figures. Because the scaling formula for the omitted figure would be something like LCD_Chr(1,5,5000*hold/1024+48);. SO in worst case scenario, 5000*1024 will be 5120000 which is out of range, thus the LCD wont have correct output. (based on my observation, correct me if im doing anything wrong). And yes, I tried to do the mathematical operation separately with a LONG variable to store the large numbers and then when the numbers have been divided into a smaller on, i tried to store it back in INT type variable. But when I try to display this converted variable, it would be faulty as well.

So for now, im gonna stick to this theory (avoid LCD Library to have anything to do with large numbers) until someone can explain me the technical explanation behind this. Thanks to everyone for helping me out. I truly appreciate it.
 
Your code should be...
Code:
// LCD module connections
sbit LCD_RS at RB0_bit;
sbit LCD_EN at RB1_bit;
sbit LCD_D4 at RB2_bit;
sbit LCD_D5 at RB3_bit;
sbit LCD_D6 at RB4_bit;
sbit LCD_D7 at RB5_bit;

sbit LCD_RS_Direction at TRISB0_bit;
sbit LCD_EN_Direction at TRISB1_bit;
sbit LCD_D4_Direction at TRISB2_bit;
sbit LCD_D5_Direction at TRISB3_bit;
sbit LCD_D6_Direction at TRISB4_bit;
sbit LCD_D7_Direction at TRISB5_bit;
// End LCD module connections



float temp;
char strDisplay;

void main() {
TRISB = 0; //PORTB as output
TRISA = 0xFF; //PORTA as input
ADCON1 = 0x7A; // Configure all ports with analog function as digital except RA2
CMCON |= 7; // Disable comparators
Lcd_Init(); //Initialize LCD

while (1){
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
temp = 5000*ADC_Read(2)/1023;

FloatToStr(temp, strDisplay);
Lcd_Out(1, 1, strDisplay);
Delay_ms(500);
}
}
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top