View previous topic :: View next topic |
Author |
Message |
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
problem with ADC |
Posted: Sat Dec 08, 2012 5:26 am |
|
|
I'm using pic18F2520 and internal oscillator 4MHz.
i have connected a pot to analog channel 4 and displaying the values in LCD. But it's not working. Please help Code: | #include "18F2520.h"
#include "f2520_regs.h"
#fuses INTRC_IO // Internal clock
#use delay(clock=4000000) // 4MHZ
#byte CMCON = 0xFB4
#byte OSCCON = 0xFD3
#define RS PIN_A2 // LCD RS pin connected to uC PIN_A2
#define EN PIN_A1 // LCD EN pin connected to uC PIN_A1
void lcd_init();
void lcd_cmd(unsigned char);
void lcd_data(unsigned char);
unsigned char low_byte,high_byte,value;
unsigned int16 full_value;
void main()
{
lcd_init(); // lcd initialization
CMCON = 0x07;
TRISA = 0b00100000; // RA5 -input, rest as output
ADCON0 = 0b00010000; // analog channel 4
ADCON1 = 0b00001010; // ref volt. VSS and VDD. AN4 to AN0 as analog
ADCON2 = 0b10111101; // Right justified, 20 TAD, 1/16Tosc
ADON = 1;
while(1)
{
delay_us(50);
GO = 1; // to start conversion
while(GO==1); // wait for bit to be cleared
low_byte = ADRESL;
high_byte = ADRESH;
full_value = ((high_byte<<8)|low_byte);
lcd_cmd(0x80);
printf(lcd_data,"%4lu",full_value);
delay_ms(100);
}
}
void lcd_init()
{
lcd_cmd(0x30); // Configure the LCD in 8-bit mode, 1 line and 5x7 font
lcd_cmd(0x0c); // display on and cursor off
lcd_cmd(0x01); // clear display screen
lcd_cmd(0x06); // increment cursor
lcd_cmd(0x80); // set cursor to 1st line
}
void lcd_cmd(unsigned char c)
{
output_b(c);
output_low(RS);
output_high(EN);
delay_ms(15);
output_low(EN);
}
void lcd_data(unsigned char z)
{
output_b(z);
output_high(RS);
output_high(EN);
delay_ms(15);
output_low(EN);
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Sat Dec 08, 2012 6:33 am |
|
|
comments...
1) Have you confirmed your PIC works by creating the '1Hz LED' test program and running it?
2) It looks like you're trying to 'port over' another compiler's code and that's just plain silly. CCS has taken the time and effort to create 'functions' that allow you to setup the ADC and everything else. Trying to wade through the code you supply is tiresome as ONE simple CCS line eliminates a lot of guesses on out part.Code like TRISA=....,ADCON=...,etc are all unecessary in CCS C.
3) You should in the 'examples' folder and read the fine examples of how CCS shows you how to read the ADC and displayit using an LCD module.
100% of the code you need for your project is already supplied by CCS !
hth
jay |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat Dec 08, 2012 8:07 am |
|
|
I second temtronic.
You also need a delay in main before initialising the LCD.
It allows time for everything to settle.
I usually wait for 1s.
Test things one at a time:-
1) Get 1Hz LED flasher going, to confirm PIC is OK.
2) Get LCD to work, (with CCS provided code)
3) Then add ADC.
Mike
EDIT
This is now a recurring theme.
You asked about LCDs twice in October.
You appear to have taken on little of the advice given then.
You were told (amongst a load of other things) that the initialisation command 0x30 has to be sent THREE times.
This clearly does not happen in your code.
You're insisting on making life difficult for yourself by not using the CCS examples. |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Sun Dec 09, 2012 12:17 am |
|
|
Yup i already worked on adc using ccs inbuilt functions. It works great, I agree. But blindly adding the line, doesn't make sense for me. I don't know what's happening inside the line. So i read the datasheet and found whats happening inside when adc function is called. To confirm that i understand it in right way,so I'm writing the code using registers. To my knowledge the code i wrote should work, But i don't know where i did the mistake. Please help if you can!!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19508
|
|
Posted: Sun Dec 09, 2012 2:21 am |
|
|
The remaining obvious problem is with the byte assembly.
full_value = ((high_byte<<8)|low_byte);
In C, arithmetic is done using the types of the variables involved on the right of the equation. The 'highest' type in each operation is identified, and this is used for the operation. 'Highest' here comes from the table:
byte char, int8 etc.
signed int8
int16 etc.
signed int16
float
etc..
The full table is in K&R.
Now, both your variables in the equation, are 'char'. What happens if you rotate an 8bit character left eight times?......
Solutions:
1)
full_value = (((int16)high_byte<<8)|low_byte);
This tell the compiler to treat 'high_byte' as an int16 for the rotation.
2)
full_value = make16(high_byte,low_byte);
This is much more efficient, and just moves the bytes directly to the required target locations.
3) Use a union (this is the more general C way of doing this)
There is a general comment here. On most bigger chips like those in the PC, the 'default' smallest size is an int16, and these will often propagate all smaller types to this size when performing operations. So on a PC, multiplying two int8 values together gets automatically expanded to an int16, and the same applies to the rotation. This is however just 'luck', and should not be relied on.....
Best Wishes |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Sun Dec 09, 2012 8:32 am |
|
|
Thanks Ttelmah, mike and temtronic I have solved the problem.
The problem occured in this line,
Code: |
unsigned int8 low_byte,high_byte; |
changed as
Code: | unsigned int16 low_byte,high_byte;
|
It works fine now |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Dec 09, 2012 11:14 am |
|
|
Wow, you sure know how _not_ to make friends.
For your problem 3 solutions were given. Instead of using one of these you had to find yourself a (less efficient) fourth solution.
Then in the other thread a suggestion for LCD initialization was given. You haven't implemented so and neither explained why you have chosen to ignore the suggestion.
Similar behaviour is seen in you ignoring the CCS functions and writing to the registers directly. It is admirable you want to understand the low level technology, but it is plain stupid stubbornness not to use the high level commands. The CCS commands are easy to read, easy to understand and portable to another processor by only changing the included header file. Your code has none of these advantages. When I'm interested in the register configurations I have a look at the generated assembly code, but I don't want to see them in my normal code.
I like helping people solve their programming problems but with your attitude I rather spend my time on other people. |
|
|
|