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.

[SOLVED] PIC18F97J60 ADC interface, observe forum rules

Status
Not open for further replies.

samizard

Junior Member level 2
Joined
Oct 27, 2017
Messages
23
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
198
Hello guys, as I am new to pic-controllers there's a problem that I am facing right now.
Currently I'm using Olimex Pic-Maxi-Web development board, it consist of pic18f97j60 controller.
In my current project I want to display analog values from potentiometer on lcd using pic18f97j60.
But I'm facing problem with adc conversion. The board consist of potentiometer connected to RA2 Port/AN2 channel. Following is the program that I made from some examples...->


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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <p18f97j60.h>
#include <stdio.h>
 
#define XTAL_FREQ 25000000
 
#define ldata PORTE
#define rs PORTHbits.RH2
#define rw PORTHbits.RH1
#define en PORTHbits.RH0
 
#define pot PORTAbits.RA2;
 
int x,y,j;
char buff[] = "";
 
void MSDelay(unsigned int itime){
    unsigned int i,j;
    for(i=0;i<itime;i++)
        for(j=0;j<135;j++);
}
 
void lcdcmd(unsigned char value){
    ldata = value;
    rs = 0;
    rw = 0;
    en = 1;
    MSDelay(1);
    en = 0;
}
 
void lcddata(unsigned char value){
    ldata = value;
    rs = 1;
    rw = 0;
    en = 1;
    MSDelay(1);
    en = 0;
}
 
void lcdinit(void){
    lcdcmd(0x01); //clear lcd screen
    MSDelay(20);
    lcdcmd(0x38); //lcd 2 lines, 5x7 matrix
 
    MSDelay(20);
    lcdcmd(0x0E); //display on, cursor on
 
    MSDelay(20);
    lcdcmd(0x01); //clear screen
 
    MSDelay(20);
    lcdcmd(0x06); //shift cursor right 
 
    MSDelay(20);
    lcdcmd(0x80); //line 1, position 0
}
 
void main(){
    TRISA = 1; //port A for pot
    TRISE = 0; //port E for lcd data
    TRISH = 0; //port H for lcd control lines
    TRISJ = 0; //port J for led
    PORTJ = 0;
    
    en = 0; //enable pin 0
      
    lcdinit(); //lcd initialization
    
    ADCON0 = 0b00001001; //ADC bits
    ADCON1 = 0b00101100; //..
    ADCON2 = 0b00000010; //..
    ADCON0bits.ADON = 1;
    
    PORTJbits.RJ0 = 1; //port J0 led on
    
    while(1){
        PORTJbits.RJ0 = 0;
        PORTJbits.RJ2 = 0; //port J2 led off
        PORTJbits.RJ1 = 1; //port J1 led on
        ADCON0bits.GO = 1; //start ADC conversion
        lcddata('G'); //display G on lcd
        MSDelay(25);
        
        while(ADCON0bits.DONE == 1); //ADC conversion finish
        lcdcmd(0x01);
        MSDelay(10);
        x = ADRESH;
        x += (ADRESL<<8);
      
        itoa(x,buff); //convert int value from x to char and store in buff
  
        for(j=0;j<10;j++){
            lcddata(buff[j]); //displaying buff
        }
    }
}

lcd is showing some number and then garbage values but how will I know if the ADC is working properly...
Please help me with my problem.
 
Last edited by a moderator:

Hi,

you need to read the microcontroller datasheet ADC section.

Basically, for a stable conversion you need:
* stable signal input
* stable reference voltage
* correct ADC timing.

***
Supply voltage(s) should be clean, too.

*****
lcd is showing some number and then garbage values
For you it may look like garbage, but for us the display content could be a good information to find the error.

Klaus
 

Again PORTx registers for PIC18F. Use LATx registers for LCD connections and digital output pins.
 

hello,

char buff[] = ""; // Empty string reservation
=>
Code:
char buff[7];

.......
   [URL="https://www.opengroup.org/onlinepubs/009695399/functions/itoa.html"][COLOR=#000066]itoa[/COLOR][/URL][COLOR=#009900]([/COLOR]x[COLOR=#339933],[/COLOR]buff[COLOR=#009900])[/COLOR][COLOR=#339933];[/COLOR] [COLOR=#666666][I]//convert int value from x to char and store in buff[/I][/COLOR]    k=strlen(buff);
      [COLOR=#B1B100]for[/COLOR][COLOR=#009900]([/COLOR]j[COLOR=#339933]=[/COLOR][COLOR=#0000DD]0[/COLOR][COLOR=#339933];[/COLOR]j[COLOR=#339933]<k;[/COLOR]j[COLOR=#339933]++[/COLOR][COLOR=#009900])
[/COLOR][COLOR=#009900]     {[/COLOR]
            lcddata[COLOR=#009900]([/COLOR]buff[COLOR=#009900][[/COLOR]j[COLOR=#009900]][/COLOR][COLOR=#009900])[/COLOR][COLOR=#339933];[/COLOR] [COLOR=#666666][I]//displaying buff[/I][/COLOR]
        [COLOR=#009900]}
[/COLOR]
 

Please do not try to write your own delay functions as most C compilers will look at code such as yours and convert the whole lot to a single 'nop' (if that!). It looks like you are using the C18 compiler and there are are delay functions provided with that (see the 'delays.h' include file).
It is good that you are providing the XTAL_FREQ pre-processor value but that is ONLY used by the compiler-provided 'delay' functions. You don't show us the config settings so we have no idea if you have set up the oscillator correctly to actually provide that clock rate.
Susan
 

Hello guys, sorry for late reply.
I am using C18 compiler.
Below are config settings I used.


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
// CONFIG1L
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on SWDTEN bit))
#pragma config STVR = OFF       // Stack Overflow/Underflow Reset Enable bit (Reset on stack overflow/underflow disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
 
Code:
// CONFIG1H
#pragma config CP0 = OFF        // Code Protection bit (Program memory is not code-protected)
 
// CONFIG2L
#pragma config FOSC = ECPLL     // Oscillator Selection bits (EC oscillator, PLL enabled and under software control, CLKO function on OSC2)
#pragma config FOSC2 = ON       // Default/Reset System Clock Select bit (Clock selected by FOSC1:FOSC0 as system clock is enabled when OSCCON<1:0> = 00)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor enabled)
#pragma config IESO = ON        // Two-Speed Start-up (Internal/External Oscillator Switchover) Control bit (Two-Speed Start-up enabled)
 
// CONFIG2H
#pragma config WDTPS = 32768    // Watchdog Timer Postscaler Select bits (1:32768)
 
// CONFIG3L
#pragma config EASHFT = ON      // External Address Bus Shift Enable bit (Address shifting enabled; address on external bus is offset to start at 000000h)
#pragma config MODE = MM        // External Memory Bus (Microcontroller mode, external bus disabled)
#pragma config BW = 16          // Data Bus Width Select bit (16-Bit Data Width mode)
#pragma config WAIT = OFF       // External Bus Wait Enable bit (Wait states for operations on external memory bus disabled)
 
// CONFIG3H
#pragma config CCP2MX = ON      // ECCP2 MUX bit (ECCP2/P2A is multiplexed with RC1)
#pragma config ECCPMX = ON      // ECCP MUX bit (ECCP1 outputs (P1B/P1C) are multiplexed with RE6 and RE5; ECCP3 outputs (P3B/P3C) are multiplexed with RE4 and RE3)
#pragma config ETHLED = ON      // Ethernet LED Enable bit (RA0/RA1 are multiplexed with LEDA/LEDB when Ethernet module is enabled and function as I/O when Ethernet is disabled)



I have to use the delay function that is defined from beforehand like #include <delays.h>, right?

The garbage value lcd is showing is something like this :- 16######7#
 
Last edited by a moderator:

What is the character string that it should be showing in that example?
To get things working with the LCD it might be an idea to take everything else out but the LCD code and get it to display a known string. One that is working you can add back in the iota part, again with a known starting value, so you know that it is working correctly. Then add back in the ADC parts.
Susan
 

As paulfjujo indicated in post #4, the problem lies with the following statement:

Code:
char buff[] = "";

Which is essentially a pointer to NULL.

The C language does not permit automatic dynamic allocation of memory, memory must be reserved by initial variable/array declaration:

Code:
char buff[[COLOR="#FF0000"]25[/COLOR]];

Or dynamically allocated by the use of malloc() or calloc() routines:

Code:
char * buff = (char *) malloc(25*sizeof(char));

As your code exists now, the following line:

Code:
itoa(x,buff); //convert int value from x to char and store in buff

Overwrites the NULL and several bytes of memory with undetermined results, with the integer to ASCII conversion.


BigDog
 

Hello guys,
Firstly changed PORTx to LATx of lcd pin definition, as for post #7, I tried the lcd program to by displaying some text and integers on it and the program is running fine, so no problem with lcd display and then I added ADC program to it.

I made some changes to my previous program like,
added stdlib.h for itoa(),
added string.h for strlen(),
changed ADCON values as follows,
ADCON0 = 0b00001001; //ADCAL=0;u=0;CHS3210=0010;GO=0;ADON=1;
ADCON1 = 0b00001100; //u=0;u=0;VCFG1=0;VCFG0=0;PCFG3210=1100;
ADCON2 = 0b00111110; //ADFM=0;u=0;ACQT210=111;ADSC2=110;

stored values as, x = ADRESH and y = ADRESL

I found this line of code in a book for combining ADRESH and ADRESL like,
x >>= 2; //shift right
x &=0x3F; //mask upper 3 bits

y <<= 6; //shift left 6 times
y &= 0xC0; //mask lower 6 bits

z = x|y; //combine x and y in z

Now after converting the value of 'z' to string, lcd displays potentiometer output between range of 0-63.

So the problem is now I want to know how to extract the values from ADRESH and ADRESL, convert them to decimal and store in one variable.
 

hello,

Assume you get measure on Analog CH2
modifiy ADFM=1 to get a Right justified result !

Code:
char buff[25];   //minima size must be 7 for itoa, but this buffer could be used for other purpose
unsigned int x;

        ADCON2 = 0b10111110; //ADFM=1;u=0;ACQT210=111;ADSC2=110;


       ADCON0bits.GO = 1; //start ADC conversion
        lcddata('G'); //display G on lcd
        Delay_ms(25);
        while(ADCON0bits.DONE == 1); //ADC conversion finish   
       lcdcmd(0x01);
        Delay_ms(10);  
        x = ADRESH <<8;  // MSB
        x =x + ADRESL;   // LSB
      
        itoa(x,buff); //convert int value from x to char and store in buff
        k=strlen(buff);
        for(j=0;j<k;j++)
        {
            lcddata(buff[j]); //displaying buff
        }
 
Last edited:

Thanks everyone now I am able to get analog input displayed on lcd.
Now I have to read 6 analog inputs, so for that all I have to do is change the ADCON bits according to the channel being used, repeat steps for ADRESH and ADRESL registers to combine and display, right??

[
 
Last edited by a moderator:

... for that all I have to do is change the ADCON bits according to the channel being used, repeat steps for ADRESH and ADRESL registers to combine and display, right?
[

Yes ,
keep a litle delay after changing the chanel and before setting the GO bit.

Code:
//ADCON0 = 0b00001001; //ADCAL=0;u=0;CHS3210=0010;GO=0;ADON=1;
ADCON0=( Chanel <<2)+1;
Delay_ms(20);
ADCON0bits.GO = 1; //start ADC conversion
 

Is it necessary to give delay..????? Cause I don't want any delay when different analog values are displayed.
 

Hi,

Is it necessary to give delay..????? Cause I don't want any delay when different analog values are displayed.
Simple answer: The datasheet wil tell you.

Some ADCs need a delay, others not.

Klaus
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top