Help in A/D

Thread Starter

moahrs

Joined Dec 5, 2011
8
Hi all,

I have the program below, i have trying to use the AD in 18F2550. I searched many samples and tips, but not work.

My idea is read position in a touch screen. The circuit (hardware) is ok, tested. The voltage is changing correctly, but the 18F2550 dont convert to digital.

How work:
- CPU (Z80) generate INT to INT2 in 18f2550, and send the byte 0x01 which indicates to read the touch;
- 18f2550 go to read touch. First I configure all necessary, OUT_TFFT indicate what was read (x- or y-), in this case, 18f2550 only leave the loop if read anything in x- first;
- When AD finish, it generate a interrupt low priority, and verify if any was read, if "0x00", it generate a delay and start new conversion (in interruption yet).
- If was read a valid number (padlido <> 0x00), the system go to next positon (y-) and do same operations;
- When was read a valid number in x- and y-, he compare if is equal to previous ppox and ppoxy, if is, start all process again, until read a valid number;
- if valid number is read an diferente from previous, he generate a interrupt in cpu Z80, and wait cpu returna to get the positons.

My problem is that the 18f2550 is not reading any valor correct, he is only reading the same valor, 0x00, and not leave from process.

Ty for help.

below, my code:
Rich (BB code):
#include <pic18f2550.h>

static __code char __at(__CONFIG1H) conf1H = _OSC_INTOSC__USB_HS_1H;
//static __code char __at(__CONFIG1L) conf1L = _PLLDIV_DIVIDE_BY_5__20MHZ_INPUT__1L & _CPUDIV__OSC1_OSC2_SRC___1__96MHZ_PLL_SRC___2__1L;
static __code char __at(__CONFIG2H) conf2H = _WDT_DISABLED_CONTROLLED_2H;
static __code char __at(__CONFIG3H) conf3H = _MCLRE_MCLR_OFF_RE3_ON_3H;
static __code char __at(__CONFIG4L) conf4 = _LVP_OFF_4L & _ENHCPU_OFF_4L; // & _BACKBUG_OFF_4L & _STVR_OFF_4L;

#define OUT_TFFT LATAbits.LATA2
#define OUT_CTRLWAIT LATAbits.LATA4
#define OUT_INTZ80 LATAbits.LATA5

#define OUT_CPU0 LATCbits.LATC0
#define OUT_CPU1 LATCbits.LATC1
#define OUT_CPU2 LATCbits.LATC2
#define OUT_CPU3 LATBbits.LATB3
#define OUT_CPU4 LATBbits.LATB4
#define OUT_CPU5 LATBbits.LATB5
#define OUT_CPU6 LATBbits.LATB6
#define OUT_CPU7 LATBbits.LATB7

#define IN_CPU0 PORTCbits.RC0
#define IN_CPU1 PORTCbits.RC1
#define IN_CPU2 PORTCbits.RC2
#define IN_CPU3 PORTBbits.RB3
#define IN_CPU4 PORTBbits.RB4
#define IN_CPU5 PORTBbits.RB5
#define IN_CPU6 PORTBbits.RB6
#define IN_CPU7 PORTBbits.RB7

#define IN_PC5 PORTEbits.RE3    
#define IN_PC6 PORTAbits.RA3
//#define IN_CS2 PORTBbits.RB2

// PC6 | PC5 | Result
//  0  |  0  | Ok
//  0  |  1  | WR Data Z80 -> PIC
//  1  |  0  | RD Data PIC -> Z80
//  1  |  1  | RD CTRL PIC -> Z80

//#define debug 1

volatile unsigned char pbyte;
volatile unsigned char pbytectrl;
volatile unsigned char pposx;
volatile unsigned char pposy;
volatile unsigned char padlido;
volatile unsigned char pbyteler[64];
volatile unsigned char ploop;

void EnviaByte();
unsigned char RecebeByte();
void ProcessaAD();
void ProcessaUSB();
void LerTouch();
void ComunicarUSB();
void ComunicarSerial();

void main()
{
    // CONFIGURAR PORTAS
    OSCCON = 0x70;
    ADCON1 = 0x0D;    // RA0=AN0, RA1=AN1, TODAS AS DEMAIS ANx = DIGITAIS
    PORTA = 0x30;
    PORTB = 0x00;
    PORTC = 0x00;
    TRISA = 0x0B;    // RA7-X, RA6-X, RA5-INTZ80, RA4-CTRWAIT, RA3-PC6, RA2-X+/Y+, RA1-AN1, RA0-AN0
    TRISB = 0xFC;    // RB7 A RB3 - D7 A D3, RB2-INT2/CS2, RB1-SCL, RB0-SCA
    TRISC = 0x97;    // RC7-RX, RC6-TX, RC5-D+, DC4-D-, RC3-X, RC2 A RC0 - D2 A D0, RE3-PC5

    RCON = RCON | 0x80;
    PIR1 = 0x00;
    PIR2 = 0x00;
    PIE1 = 0x00;
    PIE2 = 0x00;
    IPR1 = 0x00;
    IPR2 = 0x00;
    INTCON = 0xC0;    // 0xC0
    INTCON2 = 0xE0;   // 0xE0
    INTCON3 = 0x90;   // 0x90

    ADCON2bits.ADFM = 0x01;    // right justied
    ADCON2bits.ACQT2 = 0x00;
    ADCON2bits.ACQT1 = 0x00;
    ADCON2bits.ACQT0 = 0x00; // 0 TAD
    ADCON2bits.ADCS2 = 0x01;
    ADCON2bits.ADCS1 = 0x01;
    ADCON2bits.ADCS0 = 0x01; // FRC
    ADCON0bits.ADON = 0x01;  // ADC ON

    pbyte = 0x00;
    pbytectrl = 0x00;
    OUT_TFFT = 0;

    INTCON3bits.INT2IE = 0x01;
    PIE1bits.ADIE = 0x01;

    while(1)
    {
        switch (pbyte)
        {
            case 0x01:
                LerTouch();
                break;
            case 0x02:
                ComunicarUSB();
                break;
            case 0x03:
                ComunicarSerial();
                break;
        }
    }
}

void isr_reset(void) __interrupt 0
{
    INTCON3bits.INT2IE = 0x00;
    PIE1bits.ADIE = 0x00;
    INTCON3bits.INT2IF = 0x00;
    PIR1bits.ADIF = 0x00;
    PIR2bits.USBIF = 0x00;

    main();
}

void isr_int2(void) __interrupt 1
{
    // DESLIGA INTERRUPCAO PARA EVITAR NOVAS SOLICITACOES
    OUT_INTZ80 = 0x01;
    INTCON3bits.INT2IE = 0x00;
    PIE1bits.ADIE = 0x00;
    
    if (INTCON3bits.INT2IF == 0x01)    // INTERRUPCAO SOLICITADA PELO Z80
    {
        // DESLIGA FLAG DE INT2
        INTCON3bits.INT2IF = 0x00;

#ifndef debug
        if (IN_PC6 == 0 && IN_PC5 == 1)              // WR DADOS
            pbyte = RecebeByte();
        if (IN_PC6 == 1 && IN_PC5 == 0)              // RD DADOS
            EnviaByte;
        if (IN_PC6 == 1 && IN_PC5 == 1)              // RD CTRL
            EnviaByte;
#endif
    }

    // LIGA INTERRUPCAO
    INTCON3bits.INT2IE = 0x01;
    PIE1bits.ADIE = 0x01;
}

void isr_AD_USB(void) __interrupt 2
{
    // DESLIGA INTERRUPCOES PARA EVITAR NOVAS SOLICITACOES
    PIE1bits.ADIE = 0x00;

    if (PIR1bits.ADIF == 0x01) // INTERRUPCAO SOLICITADA PELO CANAL DE A/D
    {
        PIR1bits.ADIF = 0x00;
        ProcessaAD();
    }
    else if (PIR2bits.USBIF == 0x01) // INTERRUPCAO SOLICITADA PELO CANAL USB
    {
        PIR2bits.USBIF = 0x00;
        ProcessaUSB();
    }

    // LIGA INTERRUPCOES
    PIE1bits.ADIE = 0x01;
}

void EnviaByte()
{
    unsigned char oldTRISB, oldTRISC, vbyte;

    // SALVA VALORES ATUAIS DO STATUS DAS PORTAS
    oldTRISB = TRISB;
    oldTRISC = TRISC;

    // DEFINE NOVOS VALORES
    TRISB = 0x04;
    TRISC = 0x90;
    vbyte = 0x00;

    if (IN_PC6 == 1 && IN_PC5 == 0)        // RD DADOS
        vbyte = pbyteler[ploop];
    else if (IN_PC6 == 1 && IN_PC5 == 1)        // RD CTRL
        vbyte = pbytectrl;

    if (pbytectrl != 0x00)
    {
        ploop++;
        if (ploop >= (pbytectrl & 0x3F))
            pbytectrl = 0x00;
    }

    // ENVIA BYTE PELA PORTA
    OUT_CPU0 = vbyte & 0x01;
    vbyte = vbyte >> 1;
    OUT_CPU1 = vbyte & 0x01;
    vbyte = vbyte >> 1;
    OUT_CPU2 = vbyte & 0x01;
    vbyte = vbyte >> 1;
    OUT_CPU3 = vbyte & 0x01;
    vbyte = vbyte >> 1;
    OUT_CPU4 = vbyte & 0x01;
    vbyte = vbyte >> 1;
    OUT_CPU5 = vbyte & 0x01;
    vbyte = vbyte >> 1;
    OUT_CPU6 = vbyte & 0x01;
    vbyte = vbyte >> 1;
    OUT_CPU7 = vbyte & 0x01;

    // RETIRA Z80 DO WAIT
    OUT_CTRLWAIT = 0x00;

    // AGUARDA ATE A CPU SAIR DA LEITURA
    while (IN_PC6 != 0x00 || IN_PC5 != 0x00);

    // RECOLOCA SINAL WAIT PARA PROXIMO ACESSO Z80
    OUT_CTRLWAIT = 0x01;

    // VOLTA VALORES ATUAIS DAS PORTAS
    PORTB = 0x00;
    PORTC = 0x00;
    TRISB = oldTRISB;
    TRISC = oldTRISC;
}

unsigned char RecebeByte()
{
    unsigned char oldTRISB, oldTRISC;
    unsigned int vbyte, vbyte1;

    // SALVA VALORES ATUAIS DO STATUS DAS PORTAS
    oldTRISB = TRISB;
    oldTRISC = TRISC;

    // DEFINE NOVOS VALORES
    TRISB = 0xFC;
    TRISC = 0x97;

    // RECEBER VALOR PELAS 2 PORTAS
    vbyte = PORTB & 0xF8;
    vbyte1 = PORTC & 0x07;
    vbyte = vbyte + vbyte1;

    // RETIRA Z80 DO WAIT
    OUT_CTRLWAIT = 0x00;

    // AGUARDA ATE A CPU SAIR DA GRAVAÇÃO
    while (IN_PC6 != 0x00 || IN_PC5 != 0x00);

    // RECOLOCA SINAL WAIT PARA PROXIMO ACESSO Z80
    OUT_CTRLWAIT = 0x01;

    // VOLTA VALORES ATUAIS DAS PORTAS
    PORTB = 0x00;
    PORTC = 0x00;
    TRISB = oldTRISB;
    TRISC = oldTRISC;

    return vbyte;
}

void ProcessaAD()
{
    unsigned int cc;

    padlido = ADRESL;
    padlido += (ADRESH << 6);

    if (padlido == 0x00)
    {
        for (cc = 0; cc <= 0x1FF; cc++);

        ADCON0bits.GO = 0x01;
    }
}

void ProcessaUSB()
{
    pbytectrl = 0x20;    // Indica USB (0b10) e 1 byte de informacao (0b000000) (valor + 1)
}

void LerTouch()
{
    unsigned char vloop;
    unsigned char pposantx, pposanty;
    unsigned int cc;

    pbyte = 0x00;
    vloop = 0x01;
    pposantx = 0x00;
    pposanty = 0x00;
    pposantx = pposx;
    pposanty = pposy;

    OUT_TFFT = 0x01;
    ADCON0bits.CHS0 = 0x00;
    ADCON0bits.CHS1 = 0x00;
    ADCON0bits.CHS2 = 0x00;
    ADCON0bits.CHS3 = 0x00;

    // Primeiro Espera Um Touch no LCD pelo Canal X+
    while (vloop == 0x01)
    {
        // Inicia Conversao
        padlido = 0x00;
        PIR1bits.ADIF = 0x00;
        for (cc = 0; cc <= 0x0FF; cc++);
        ADCON0bits.GO = 0x01;
        
        // Aguarda a Interrupção do AD com o Valor
        while (padlido == 0x00);

        if (OUT_TFFT == 0x01)
        {
            pposx = padlido;

            // MUDA PARA O CANAL Y+
            OUT_TFFT = 0x00;
            ADCON0bits.CHS0 = 0x01;
        }
        else
        {
            pposy = padlido;

            if (pposx != pposantx || pposy != pposanty)
                vloop = 0x00;
        }
    }

    // Finaliza, envia bytes pro Z80
    pbyteler[0] = pposx;
    pbyteler[1] = pposy;
    ploop = 0x00;
    pbytectrl = 0x41;    // Indica AD (0b01) e 2 bytes de informacao (0b000001) (valor + 1)

    OUT_INTZ80 = 0x00;
}

void ComunicarUSB()
{
    pbyte = 0x00;
}

void ComunicarSerial()
{
    pbyte = 0x00;
}
 
Last edited by a moderator:

DerStrom8

Joined Feb 20, 2011
2,390
Which compiler is this? Hi-Tech?

Anyway, I recently learned how to use the ADC on the 18F1330 and I have a few questions for you. First, I'm not sure about this, but I think

ADCON2bits.ACQT0 = 0x00; // 0 TAD

is saying you're not giving the ADC any time to acquire a value. Setting it to, say, 20 TAD might work better. Second, I don't see where you wait for the ADC to finish the conversion--you just skip ahead to the next piece of code. You need to have a line that says something like while(BusyADC()); or something like that. I think there's actually a bit for that, so you might be able to use that rather than the library function BusyADC. And lastly, I don't see where you read the ADC. Again, you can use the ReadADC() library function or find the bit that says to read the value.
If there's something I missed, please point it out to me. I hope you can figure it out soon!
Regards,
Der Strom
 

Thread Starter

moahrs

Joined Dec 5, 2011
8
Which compiler is this? Hi-Tech?

Anyway, I recently learned how to use the ADC on the 18F1330 and I have a few questions for you. First, I'm not sure about this, but I think

ADCON2bits.ACQT0 = 0x00; // 0 TAD

is saying you're not giving the ADC any time to acquire a value. Setting it to, say, 20 TAD might work better. Second, I don't see where you wait for the ADC to finish the conversion--you just skip ahead to the next piece of code. You need to have a line that says something like while(BusyADC()); or something like that. I think there's actually a bit for that, so you might be able to use that rather than the library function BusyADC. And lastly, I don't see where you read the ADC. Again, you can use the ReadADC() library function or find the bit that says to read the value.
If there's something I missed, please point it out to me. I hope you can figure it out soon!
Regards,
Der Strom
First of all, thank you for explanations.

I Using SDCC. I can't use HI_TECH and MPLAB, and how my patience is very short, and dont work anytime, i decided to use SDCC and work very well..

I was put 20 TAD, but the same, don't work. I decided use the control of TAD with for(cc=0;cc<=0x00FF;cc++). I wait finish the conversion with while(padlido==0x00), and finish with interrupt.
 

Thread Starter

moahrs

Joined Dec 5, 2011
8
May I ask why you can't use MPLAB and Hi-Tech?
See, i try compile em MPASM, same program compile in anyone ASM compiler, but in MPASM not.

I Try HI-TECH C, I had setup, how write in site and instructions, but the MPLAB dont find it... Only says that dont cant use HI-TECH because cant find it... but the directory is OK...

I think that its me the problem, but how I use SDCC at long time ago for Z80, 8051 and other, I decided to use in PIC18. Until now, its working OK... "Only this problem with AD"...

But if you think that I need try, "again", install HI-TECH and use him, i can try, and tomorow post here the result.

More one time, ty...
 

t06afre

Joined May 11, 2009
5,934
On my computers I have no problem with MPLAB not finding HI-Tech C. Have you read the quickstart.pdf in the docs folder. The path is something like this
C:\Program Files\HI-TECH Software\PICC-18\PRO\9.64\docs
 

Thread Starter

moahrs

Joined Dec 5, 2011
8
On my computers I have no problem with MPLAB not finding HI-Tech C. Have you read the quickstart.pdf in the docs folder. The path is something like this
C:\Program Files\HI-TECH Software\PICC-18\PRO\9.64\docs
Hum... I understand. I will try again. But, in the my code, have anyone problem that need I to fix ?

I will thinking in change interrupt for loop seeing if ADCON0.GO is in "0".

What u think ?
 

DerStrom8

Joined Feb 20, 2011
2,390
Do you go through the project wizard in MPLAB? It makes things a LOT easier. When you open it up, go to Project-->Project Wizard. It will walk you through the proper setup process, including finding the correct location for Hi-Tech. Another idea, if you are using an 18F processor, is C18 lite, which is the compiler I use. You can download it for free from the Microchip website.
 

ErnieM

Joined Apr 24, 2011
8,377
I agree with always starting from the Project Wizard.

To just inform MPLAB where a tool is (such as a compiler) you can use "Set Language Tool Locations..." under the Project menu.
 

thatoneguy

Joined Feb 19, 2009
6,359
This part:

Rich (BB code):
void ProcessaAD() 
{     
unsigned int cc;     
 padlido = ADRESL;     
padlido += (ADRESH << 6);     
 if (padlido == 0x00)     
{         
for (cc = 0; cc <= 0x1FF; cc++);          
ADCON0bits.GO = 0x01;     
} 
}
After ADCON0bits.GO=0x01;

In addition to giving more time for the ADC to complete (20 TAD is good)

Add a line:
While (ADCON0bits.go);

I'm unsure why you have it in a for loop, since you are continually restarting the AD conversion each time?

That will keep the function from returning from the subroutine before the AD conversion is complete.

Maybe put the move from ADRES to after the while(ADCON0.go) as well, so the function will return a result.
 
;here is my code tha tworks.
ADCON1=0Xd;
ADCON0=1;
ADCON2=0XB6;
ADCON0bits.GO_DONE=1; //START A2D first time
reloop:
if (ADCON0bits.GO_DONE==1)
goto reloop;

//result to data
data=ADRESL+256*ADRESH;
 
Top