News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Pic18F46Q43 A/D trouble

Started by Jamie, Mar 25, 2024, 05:18 AM

Previous topic - Next topic

Jamie

Good Evening all,

I have the following program that has me stumped with the A/D input on AN0
In the following program if I supply and input to ADIn 1 the program does what i expect but
no matter what I try if I supply an input to ADIn 0 the program doesnt respond.

However If The input to ADIn 0 is present at power up or reset it works just the once then not at all

Any assistance would be appreciated

Jamie

Device 18F46Q43                ' 64k
Declare Xtal = 64
'Declare Create_Coff = True                                  ' Create a COF file for simulation in Proteus
'Declare All_Digital = true
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Serial comm setup for communication with a PC AT 9600 bps
'
    Declare Hserial1_Baud = 9600        ' SETTING UP THE UART'S NEEDS TO BE DONE THIS WAY ON THE 18F46Q43
    Declare HRSOut1_Pin = PORTC.6      ' THIS IS UART1 ULCD
    Declare HRSIn1_Pin = PORTC.7
    Declare Hserial1_Clear = On        ' Enable Error clearing on received characters      ' Clear the buffer before receiving
                                        ' ********* BOTH OF THESE ARE THE CORRECT WAY TO CONFIGURE SERIAL ON THE 18F46Q43
                                        ' ********* BOTH OF THESE ARE THE CORRECT WAY TO CONFIGURE SERIAL ON THE 18F46Q43
    Declare Hserial2_Baud = 9600        ' SETTING UP THE UART'S NEEDS TO BE DONE THIS WAY ON THE 18F46Q43
    Declare HRSOut2_Pin = PORTD.6      ' THIS IS UART2 RS485 OR XBEE
    Declare HRSIn2_Pin = PORTD.7
    Declare Hserial2_Clear = On        ' Enable Error clearing on received characters      ' Clear the buffer before receiving

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Declare Adin_Res    12                  ' Set the resolution to 12 (18f4523)
Declare Adin_Tad    FRC                ' Choose the RC osc for ADC samples
Declare Adin_Stime    500                  ' Allow 100us for charge time

ANSELA = %00000011 ' Set analogue input on PORTA.0, PORTA.1

ADCON0 = %10010100
ADCON1 = %00000000                      ' Set AN0,AN1,AN2,AN3 analog and the rest digital with vdd and vss as vref (18F4523) remove with 877a
ADCON2 = %00000000                      ' AD Right judtified, 20 TAD, FRC for the (18F4523) Only remove this line with 16f877a
'ADCON3 = %00000000

'ADCLK = %00001111
'ADREF = %00000000

TRISA = %00000011

Output PORTB
Output PORTE.0
Output PORTE.1
Output PORTE.2

Output PORTA.2
Output PORTE.0
Output PORTE.1
Output PORTE.2
Input PORTA.0
Input PORTA.1

Symbol DQ = PORTC.0          ' DS1822 data line (Sensor 1)
Symbol RLY_Bank1 = PORTE.0
Symbol RLY_Bank2 = PORTE.1
Symbol RLY_Bank3 = PORTA.2
Symbol Latch_Clear = PORTE.2

'Symbol Input_1 = PORTA.0
'Symbol Input_2 = PORTA.1

Dim Input_1 As  Float
Dim Input_2 As  Float
Dim BVolts  As  Float
Dim RXCommand  As  Byte
Dim XbeeCommand As  Byte
Dim ADSteps12      As  Float      ' 12 bit A/D volts per step 0.001221 Volts / Step
Dim ADC_Result      As  Word        ' General temporary variable for calculating A/D voltage
Dim Ave            As  Float
Dim X          As  Word
Dim COUNTUP        As Byte
Dim COUNTDOWN      As Byte
' DIMS for 18b20 temp sensor

Dim Raw_Temp        As  Word
Dim rawtemp        As  Word
Dim DS18b20_temp    As  Float
Dim DS18b20_temp1  As  Float
Dim D              As  Bit                         
Dim SIGN            As  Byte
Dim DegF            As  Float
'crc variables
Dim Temp1M          As Byte
Dim CRC            As Byte
Dim I              As Byte
Dim J              As Byte
Dim DataByteM      As Byte
Dim CarryBit        As Bit
Dim ExtraBit        As Bit
Dim TemperatureM    As Word
Dim Count_Remain    As Byte
Dim Count_per_C    As Byte
Dim TempERROR      As  Word
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

DelayMS 100
ADSteps12 = 4.97 / 4095    ' Set A/D Quantization value
COUNTUP = 0

Start:
High Latch_Clear

While

    GoSub GetVolts
    PORTB = COUNTUP
    PulseOut RLY_Bank1, 100
    PulseOut RLY_Bank2, 100
    PulseOut RLY_Bank3, 100
    COUNTUP = COUNTUP + 1

    If Input_1 > 3 Then
        COUNTUP = 13
        PORTB = COUNTUP
        PulseOut RLY_Bank1, 100
        PulseOut RLY_Bank2, 100
        PulseOut RLY_Bank3, 100
        DelayMS 5000
    EndIf

    If Input_2 > 3 Then
        COUNTUP = 129
        PORTB = COUNTUP
        PulseOut RLY_Bank1, 100
        PulseOut RLY_Bank2, 100
        PulseOut RLY_Bank3, 100
        DelayMS 5000
    EndIf



    DelayMS 100
Wend




GetVolts:

        ADC_Result = ADIn 0                                      ' Get Battery voltage. this is 10X less than actual so 25V will read as 2.5V             
        Input_1 = ADC_Result * ADSteps12
        Input_1 = (Input_1 * 5.7)                            ' divider 10.00k And 1.0k .01% resistors total measured of 11k
       
        DelayMS 100
       
        ADC_Result = ADIn 1                                      ' Get Battery voltage. this is 10X less than actual so 25V will read as 2.5V             
        Input_2 = ADC_Result * ADSteps12
        Input_2 = (Input_2 * 5.7)                            ' divider 10.00k And 1.0k .01% resistors total measured of 11k

Return


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

'DS18B20 temp sensor read routine.

Gettemp:
'    Print At 1,20,"T"
    TempERROR = 0
    OWrite DQ, 1, [$CC,$44]                                    ' Send calculate temperature command
    Repeat
        DelayMS 1                                              ' Waiting loop until reading complete
        TempERROR = TempERROR + 1
        ORead DQ, 4, [D]                                        ' Monitor for pin high transition ...
        If TempERROR > 1000 Then
            Cls
'            Print At 1,1,"BATTERY TEMP SENSOR"
'            Print At 2,1,"      ERROR        "
'            DelayMS 4000
'            GetTempFlag = 0
            Return
        EndIf
    Until D <> 0                                                ' Reading complete
        OWrite DQ, 1, [$CC, $BE]                                ' Send read scratchpad command
        ORead DQ, 2, [Raw_Temp.LowByte, Raw_Temp.HighByte]
        rawtemp = Raw_Temp                                      ' copy raw_temp to rawtemp for xmission to Visual basic
        SIGN = Raw_Temp.11

    If SIGN = 0 Then
        DS18b20_temp = Raw_Temp * 0.0625                        ' see notes on resolution at the top of this code
    EndIf

    If SIGN = 1 Then
        Raw_Temp = ~Raw_Temp + 1                                ' convert for negative value
        DS18b20_temp = Raw_Temp * 0.0625                        ' see notes on resolution at the top of this code
        DS18b20_temp = -DS18b20_temp
    EndIf
    DegF = (DS18b20_temp * 1.8) + 32
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

'GetTempFlag = 0

'GetTEMP_Flag = 100  ' 5 seconds
'Print At 1,20," "
Return
                                                                                                                    ' End GetTemp
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''       






'--------------------------------------------------------------------------------------------
' Set the config fuses to use the internal oscillator at 64MHz on a PICxxQ43 device
'
Config_Start
    FEXTOSC = Off                ' Oscillator not enabled
    RSTOSC = HFINTOSC_64MHZ      ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
    CLKOUTEN = Off                ' CLKOUT function is disabled
    PR1WAY = Off                  ' PRLOCKED bit can be set and cleared repeatedly
    CSWEN = On                    ' Writing to NOSC and NDIV is allowed
    FCMEN = On                    ' Fail-Safe Clock Monitor enabled
    MCLRE = EXTMCLR              ' EXTERNAL RESET ENABLED
'    MCLRE = INTMCLR              ' MCLR pin enabled
    PWRTS = PWRT_64              ' PWRT set at 64ms
    MVECEN = Off                  ' Interrupt contoller does not use vector table to prioritze interrupts
    IVT1WAY = Off                ' IVTLOCKED bit can be cleared and set repeatedly
    LPBOREN = On                  ' Low-Power BOR enabled
    BOREN = SBORDIS              ' Brown-out Reset enabled. SBOREN bit is ignored
    BORV = VBOR_2P85              ' Brown-out Reset Voltage (VBOR) set to 2.8V
    ZCD = Off                    ' ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                ' PPSLOCKED bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = On                  ' Stack full/underflow will cause Reset
    LVP = Off                    ' HV on MCLR/VPP must be used for programming
    XINST = Off                  ' Extended Instruction Set and Indexed Addressing Mode disabled
    WDTCPS = WDTCPS_31            ' Divider ratio 1:65536. software control of WDTPS
    WDTE = Off                    ' WDT Disabled. SWDTEN is ignored
    WDTCWS = WDTCWS_7            ' Window always open (100%). Software control. Keyed access not required
    WDTCCS = SC                  ' Software Control
    BBSIZE = BBSIZE_512          ' Boot Block size is 512 words
    BBEN = Off                    ' Boot block disabled
    SAFEN = Off                  ' SAF disabled
    Debug = Off                  ' Background Debugger disabled
    WRTB = Off                    ' Boot Block not Write protected
    WRTC = Off                    ' Configuration registers not Write protected
    WRTD = Off                    ' Data EEPROM not Write protected
    WRTSAF = Off                  ' SAF not Write Protected
    WRTAPP = Off                  ' Application Block not write protected
    Cp = Off                      ' PFM and Data EEPROM code protection disabled
Config_End

trastikata

Out of curiosity, reverse the places for AN0 and AN1 in your ADC sub, and let us know what happens:

GetVolts:
        ADC_Result = ADIn 1                                      ' Get Battery voltage. this is 10X less than actual so 25V will read as 2.5V             
        Input_2 = ADC_Result * ADSteps12
        Input_2 = (Input_2 * 5.7)                            ' divider 10.00k And 1.0k .01% resistors total measured of 11k


        DelayMS 100

        ADC_Result = ADIn 0                                      ' Get Battery voltage. this is 10X less than actual so 25V will read as 2.5V             
        Input_1 = ADC_Result * ADSteps12
        Input_1 = (Input_1 * 5.7)                            ' divider 10.00k And 1.0k .01% resistors total measured of 11k
Return


tumbleweed

From what I can see the compiler's ADIn routine for the Q43 isn't selecting the proper register bank for some of the registers...

; Code Produced by the Positron8 Compiler. Version 4.0.4.0
__adin_
    bsf ADCON0,PP_ADCS      ;<<<< ADCON0 is in bank3 (and not in access bank)
    movlb high(ADPCH)
    movwf ADPCH,1
    bsf ADCON0,PP_ADON

The first 'bsf ADCON0' instruction will end up using whatever the BSR setting is when the ADIn routine is called.
You might want to raise this with Les... I don't think that's what's intended.

Jamie

 - Out of curiosity, reverse the places for AN0 and AN1 in your ADC sub, and let us know what happens:

Thank you for the suggestion Trastikata.

        ADC_Result = ADIn 1                                      ' Get Battery voltage. this is 10X less than actual so 25V will read as 2.5V             
        Input_2 = ADC_Result * ADSteps12
        Input_2 = (Input_2 * 5.7)                            ' divider 10.00k And 1.0k .01% resistors total measured of 11k

        ADC_Result = ADIn 0                                      ' Get Battery voltage. this is 10X less than actual so 25V will read as 2.5V             
        Input_1 = ADC_Result * ADSteps12
        Input_1 = (Input_1 * 5.7)                            ' divider 10.00k And 1.0k .01% resistors total measured of 11k
       
        DelayMS 100
return

this did the same behavior with no change.


Tumbleweed, Thank you for your response. Wish I had the skills to spot these things, I'll wait and see if Les sees this post.


Jamie



top204

#4
You beat me too it tumbleweed. Well spotted

I have a corrections update coming soon to alter some newer PPI files for which library subroutine to use for the jumble of peripherals mechanisms now on the devices, and the Q43 PPI files have the wrong value in their ADIN_TYPE directive. I now have to create several different assembler library subroutines within the compiler's source code and choose which one suits a particular device type, when I add a new device because it is almost guaranteed to be different from the others?

To correct this in the BASIC program, add the line:

Declare ADIn_Type = 2  ' Tell the compiler what type of library file to use for ADIn on this device (anomaly correction)

The ADCC peripheral on the newer devices also needs to be setup before the ADIn command can take a reading with any confidence, because the peripheral's default settings can cause problems, and the ADIn command only accesses the clock mechanism of an ADC. This is because the ADCC peripheral also has multi-samples and filtering capabilities, so is not directly compatible with the standard ADC peripheral, until it is told to be.

So the program listing below shows a way of setting up the ADCC peripheral on a PIC18FxxQ43 device and taking a 12-bit reading, either with ADIn, or a dedicated procedure, that has more control over it, and does not have the TAD delay within the ADIn command. My personal preference would be to use the ADC_Read procedure, because a user has more control over it, and can alter it so suit any extra needs.

The program is set for a PIC18F26Q43 device, but the PIC18F46Q43 device uses the same peripheral mechanisms as the other 18FxxQ43 devices (thankfully). I actually have the program listed below running on a PIC18F27Q43 device sitting in an Amicus18 board on my desk, so they are OK with each other.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A demonstration of setting up and using the ADCC peripheral on PIC18FxxQ43 devices
'
' Written for the Positron8 BASIC compiler by Les Johnson
'
    Device = 18F26Q43                       ' Tell the compiler what device to compile for
    Declare Xtal = 64                       ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare ADIn_Type = 2                   ' Tell the compiler what type of library file to use for ADIn on this device (anomaly correction)
'
' Setup USART1

    Declare Hserial_Baud = 9600
    Declare HRSOut1_Pin = PORTC.6
'
' Create any global veriables here
'    
    Dim wADC_Raw As Word                    ' Holds the ADC's raw 12-bit value

'-------------------------------------------------------------------------------------
' The main program starts here
' Read the ADC peripheral and transmit its raw value to a serial terminal
'
Main:
    Setup()                                 ' Setup the program and any peripherals
     
    Do                                      ' Create a loop
        wADC_Raw = ADC_Read(0)              ' Read the ADCC peripheral using a procedure
        HRSOutLn "ADC_Read = ", Dec wADC_Raw ' Transmit the ADCC value to a serial terminal     
        wADC_Raw = ADIn(0)                  ' Read the ADCC peripheral using the ADIn command
        HRSOutLn "ADIn =     ", Dec wADC_Raw ' Transmit the ADCC value to a serial terminal
        DelayMS 500                         ' A delay to see things changing
    Loop                                    ' Do it forever

'-------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    Osc_Init()                              ' Initialise the internal oscillator for 64MHz operation
    ADC_Init()                              ' Initialise the ADCC peripheral
EndProc

'-------------------------------------------------------------------------------------
' Initialise the ADC peripheral for a PIC18FxxQ43 device
' Input     : None
' Output    : None
' Notes     : Initialised for 12-bit operation
'           : Oscillator set for fOsc / 16
'           : -Vref as Gnd, +Vref as VDD
'           : Pin AN0 is set as analogue
'
Proc ADC_Init()
    ANSELA.0 = 1                            ' Set AN0 as analogue
    ADLTHL = $00
    ADLTHH = $00
    ADUTHL = $00
    ADUTHH = $00
    ADSTPTL = $00
    ADSTPTH = $00
    ADACCU = $00
    ADRPT = $00
    ADPCH = $00
    ADACQL = $00
    ADACQH = $00
    ADCAP = $00
    ADPREL = $00
    ADPREH = $00
    ADCON1 = $00
    ADCON2 = $10                            ' Setup the ADCC for basic mode to match a standard ADC peripheral
    ADCON3 = $00
    ADSTAT = $00
    ADREF = $00                             ' -Vref is VSS. +Vref is VDD
    ADACT = $00
    ADCLK = $07                             ' ADCS is fOsc/16
    ADCON0 = $84                            ' Right justified for 12-bit. ADC enabled. ADCS is fOsc/ADCLK
EndProc


'-------------------------------------------------------------------------------------
' Read the ADC
' Input     : pChannel holds the ADC channel to read
' Output    : Returns the ADC reading
' Notes     : Can be used instead of ADIn, and is faster because it does not have the STime delay
'
Proc ADC_Read(pChannel As Byte), ADC_wADRES
Global Dim ADC_wADRES As ADRESL.Word        ' Create a 16-bit SFR from ADRESL and ADRESH
   
    ADCON0bits_ADON = 1                     ' Turn on the ADC peripheral (just in case)
    ADPCH = pChannel                        ' Select the ADC's Channel          
    ADCON0bits_ADGO = 1                     ' Start the conversion  
    Repeat: Until ADCON0bits_ADGO = 0       ' Wait for the conversion to finish   
    Result = ADC_wADRES                     ' Return the ADC reading
EndProc

'-------------------------------------------------------------------------------------
' Initialise the device's internal oscillator
' Input     : None
' Output    : None
' Notes     : For a PIC18FxxQ43 device.
'           : It is not always required to call this procedure with the HFINTOSC_64MHZ fuse,
'           : but better safe than sorry.
'
Proc Osc_Init() 
    OSCCON1 = $60                           ' NOSC is HFINTOSC. NDIV is 1
    OSCCON3 = $00
    OSCEN = $00 
    OSCFRQ = $08                            ' HFFRQ is 64MHz
    OSCTUNE = $00
    ACTCON = $00
EndProc

'-------------------------------------------------------------------------------------
' Set the config fuses for internal oscillator, running at 64MHz, with the OSC pins as I/O pins
' For use with a PIC18FxxQ43 device
'
Config_Start
    FEXTOSC = Off                           ' External Oscillator not enabled
    RSTOSC = HFINTOSC_64MHZ                 ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
    CLKOUTEN = Off                          ' CLKOUT function is disabled
    PR1WAY = Off                            ' PRLOCKED bit can be set and cleared repeatedly
    CSWEN = On                              ' Writing to NOSC and NDIV is allowed
    FCMEN = On                              ' Fail-Safe Clock Monitor enabled
    MCLRE = EXTMCLR                         ' RE3 pin's function is MCLR
    PWRTS = PWRT_OFF                        ' Power-up timer is disabled
    MVECEN = Off                            ' Interrupt contoller does not use vector table to prioritze interrupts
    IVT1WAY = Off                           ' IVTLOCKED bit can be cleared and set repeatedly
    LPBOREN = On                            ' Low Power BOR enabled
    BOREN = SBORDIS                         ' Brown-out Reset enabled. SBOREN bit is ignored
    BORV = VBOR_1P9                         ' Brown-out Reset Voltage (VBOR) set to 1.9V
    ZCD = Off                               ' ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                           ' PPSLOCKED bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = On                             ' Stack full/underflow will cause Reset
    LVP = Off                               ' Low Voltage Programming disabled
    XINST = Off                             ' Extended Instruction Set and Indexed Addressing Mode disabled
    WDTCPS = WDTCPS_31                      ' WDT Period Divider ratio 1:65536; software control of WDTPS
    WDTE = Off                              ' WDT Disabled; SWDTEN is ignored
    WDTCWS = WDTCWS_7                       ' WDT Window always open (100%), software control and keyed access not required
    WDTCCS = SC                             ' WDT input clock Software Control
    BBSIZE = BBSIZE_512                     ' Boot Block size is 512 words
    BBEN = Off                              ' Boot block disabled
    SAFEN = Off                             ' Storage Area Flash disabled
    Debug = Off                             ' Background Debugger disabled
    WRTB = Off                              ' Boot Block not Write protected
    WRTC = Off                              ' Configuration registers not Write protected
    WRTD = Off                              ' Data EEPROM not Write protected
    WRTSAF = Off                            ' SAF not Write Protected
    WRTAPP = Off                            ' Application Block not write protected
    Cp = Off                                ' PFM and Data EEPROM code protection disabled
Config_End

Jamie

#5
Thank You Les!,

I've added your program into my own and did a read on procedures in the manual.
I've added ANSELA.1 = 1                            ' Set AN1 as analogue
to the Proc ADC_Init()

then changed my code to the following as a test
Input_1 and _2 are floats

What happens now is Input_2 will execute even if the input for it is at 0
Input_1 on ADC_Read(0) works great

when I get rid of the Input_2 code it works as expected using only AN0

Main:
    Setup()                                ' Setup the program and any peripherals

    ADSteps12 = 4.97 / 4095    ' Set A/D Quantization value   
    Do                                      ' Create a loop
        wADC_Raw = ADC_Read(0)              ' Read the ADCC peripheral using a procedure
        Input_1 = wADC_Raw * ADSteps12
        Input_1 = wADC_Raw * 5.7
        DelayMS 100                        ' A delay to see things changing

        wADC_Raw = ADC_Read(1)              ' Read the ADCC peripheral using a procedure
        Input_2 = wADC_Raw * ADSteps12
        Input_2 = wADC_Raw * 5.7


    If Input_1 > 3.0 Then
        COUNTUP = 13
        PORTB = COUNTUP
        PulseOut RLY_Bank1, 100
        PulseOut RLY_Bank2, 100
        PulseOut RLY_Bank3, 100
        DelayMS 5000
    EndIf
    If Input_2 > 3.0 Then
        COUNTUP = 129
        PORTB = COUNTUP
        PulseOut RLY_Bank1, 100
        PulseOut RLY_Bank2, 100
        PulseOut RLY_Bank3, 100
        DelayMS 5000
    EndIf

    PORTB = COUNTUP
    PulseOut RLY_Bank1, 100
    PulseOut RLY_Bank2, 100
    PulseOut RLY_Bank3, 100
    COUNTUP = COUNTUP + 1

    DelayMS 200

    Loop                                    ' Do it forever

top204

#6
The ADC's clock may be operating too fast at fOsc/16 for accurate readings, so it is usually better to test unknown ADC operations using the FRC clock first. This is slower, but more reliable for readings. Then the ADC's clock can be increased in its initialisation if more accuracy or speed is required.

Below is a demo code listing that takes a reading from both AN0 and AN1 pins using the ADC's FRC oscillator and transmits both readings to a serial terminal. The value in the ADCON0 SFR makes the ADCC peripheral use the FRC oscillator and not the Clk divisions, by changing the state of the CS bit. Program this code into your device to make sure you have the ADC channel pins working OK on your board:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A demonstration of setting up and using the ADCC peripheral on PIC18FxxQ43 devices
'
' Written for the Positron8 BASIC compiler by Les Johnson
'
    Device = 18F26Q43                       ' Tell the compiler what device to compile for
    Declare Xtal = 64                       ' Tell the compiler what frequency the device is operating at (in MHz)
'
' Setup USART1

    Declare Hserial1_Baud = 9600
    Declare HRSOut1_Pin   = PORTC.6
'
' Create any global veriables here
'    
    Dim wADC0_Raw As Word                    ' Holds the ADC's raw 12-bit value from AN0
    Dim wADC1_Raw As Word                    ' Holds the ADC's raw 12-bit value from AN1
   
'-------------------------------------------------------------------------------------
' The main program starts here
' Read the ADC peripheral and transmit its raw value to a serial terminal
'
Main:
    Setup()                                 ' Setup the program and any peripherals
     
    Do                                      ' Create a loop
        wADC0_Raw = ADC_Read(0)             ' Read the ADC channel AN0
        HRSOutLn "AN0 = ", Dec wADC0_Raw    ' Transmit the ADC value from AN0 to a serial terminal     
       
        wADC1_Raw = ADC_Read(1)             ' Read the ADC channel AN1
        HRSOutLn "AN1 = ", Dec wADC1_Raw    ' Transmit the ADC value from AN1 to a serial terminal
        DelayMS 500                         ' A delay to see things changing
    Loop                                    ' Do it forever

'-------------------------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    ADC_Init()                              ' Initialise the ADCC peripheral
    ANSELA.0 = 1                            ' Set pin AN0 as analogue
    ANSELA.1 = 1                            ' Set pin AN1 as analogue
EndProc

'-------------------------------------------------------------------------------------
' Initialise the ADCC peripheral for a PIC18FxxQ43 device
' Input     : None
' Output    : None
' Notes     : Initialised for 12-bit operation
'           : ADC's clock oscillator set for FRC
'           : -Vref as Gnd, +Vref as VDD
'           : The ADCC peripheral is setup to be compatible with standard ADC peripherals
'           : Pins AN0 and AN1 are set as analogue
'
Proc ADC_Init()
    ADLTHL = 0b00000000
    ADLTHH = 0b00000000
    ADUTHL = 0b00000000
    ADUTHH = 0b00000000
    ADSTPTL = 0b00000000
    ADSTPTH = 0b00000000
    ADACCU = 0b00000000
    ADRPT = 0b00000000
    ADPCH = 0b00000000
    ADACQL = 0b00000000
    ADACQH = 0b00000000
    ADCAP = 0b00000000
    ADPREL = 0b00000000
    ADPREH = 0b00000000
    ADCON1 = 0b00000000
    ADCON2 = 0b00010000                     ' Setup the ADCC for basic mode to match a standard ADC peripheral
    ADCON3 = 0b00000000
    ADSTAT = 0b00000000
    ADREF = 0b00000000                      ' -Vref is VSS. +Vref is VDD
    ADACT = 0b00000000
    ADCLK = 0b00000000                      ' Contents of ADCLK is ignored because the ADC is using Frc
    ADCON0 = 0b10010100                     ' Right justified For 12-Bit. ADC enabled. ADCS is Frc
EndProc

'-------------------------------------------------------------------------------------
' Read the ADC
' Input     : pChannel holds the ADC channel to read
' Output    : Returns the ADC reading
' Notes     : Can be used instead of ADin, and is faster because it does not have the STime delay
'
Proc ADC_Read(pChannel As Byte), ADC_wADRES
Global Dim ADC_wADRES As ADRESL.Word        ' Create a 16-bit SFR from ADRESL and ADRESH
   
    ADCON0bits_ADON = 1                     ' Turn on the ADC peripheral (just in case)
    ADPCH = pChannel                        ' Select the ADC's Channel          
    ADCON0bits_ADGO = 1                     ' Start the conversion  
    Repeat: Until ADCON0bits_ADGO = 0       ' Wait for the conversion to finish   
    Result = ADC_wADRES                     ' Return the ADC reading
EndProc

'-------------------------------------------------------------------------------------
' Set the config fuses for internal oscillator, running at 64MHz, with the OSC pins as I/O pins
' For use with a PIC18FxxQ43 device
'
Config_Start
    FEXTOSC = Off                           ' External Oscillator not enabled
    RSTOSC = HFINTOSC_64MHZ                 ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
    CLKOUTEN = Off                          ' CLKOUT function is disabled
    PR1WAY = Off                            ' PRLOCKED bit can be set and cleared repeatedly
    CSWEN = On                              ' Writing to NOSC and NDIV is allowed
    FCMEN = On                              ' Fail-Safe Clock Monitor enabled
    MCLRE = EXTMCLR                         ' RE3 pin's function is MCLR
    PWRTS = PWRT_OFF                        ' Power-up timer is disabled
    MVECEN = Off                            ' Interrupt contoller does not use vector table to prioritze interrupts
    IVT1WAY = Off                           ' IVTLOCKED bit can be cleared and set repeatedly
    LPBOREN = On                            ' Low Power BOR enabled
    BOREN = SBORDIS                         ' Brown-out Reset enabled. SBOREN bit is ignored
    BORV = VBOR_1P9                         ' Brown-out Reset Voltage (VBOR) set to 1.9V
    ZCD = Off                               ' ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                           ' PPSLOCKED bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = On                             ' Stack full/underflow will cause Reset
    LVP = Off                               ' Low Voltage Programming disabled
    XINST = Off                             ' Extended Instruction Set and Indexed Addressing Mode disabled
    WDTCPS = WDTCPS_31                      ' WDT Period Divider ratio 1:65536; software control of WDTPS
    WDTE = Off                              ' WDT Disabled; SWDTEN is ignored
    WDTCWS = WDTCWS_7                       ' WDT Window always open (100%), software control and keyed access not required
    WDTCCS = SC                             ' WDT input clock Software Control
    BBSIZE = BBSIZE_512                     ' Boot Block size is 512 words
    BBEN = Off                              ' Boot block disabled
    SAFEN = Off                             ' Storage Area Flash disabled
    Debug = Off                             ' Background Debugger disabled
    WRTB = Off                              ' Boot Block not Write protected
    WRTC = Off                              ' Configuration registers not Write protected
    WRTD = Off                              ' Data EEPROM not Write protected
    WRTSAF = Off                            ' SAF not Write Protected
    WRTAPP = Off                            ' Application Block not write protected
    Cp = Off                                ' PFM and Data EEPROM code protection disabled
Config_End

On the serial terminal, when swapping the AN0 and AN1 pins from +3v3 to Gnd, I got the text below, showing both ADC channels are working as they should. i.e. Full 12-bits value for 3v3 (4095) and 0 for grounded.

AN0 = 4095
AN1 = 0
AN0 = 4095
AN1 = 0
AN0 = 4095
AN1 = 0
AN0 = 4095
AN1 = 0
AN0 = 4095
AN1 = 0
AN0 = 4095
AN1 = 0        <------------\
AN0 = 865      <------------|
AN1 = 389      <------------|
AN0 = 794      <------------| Pins AN0 and AN1 floating while swapped
AN1 = 793      <------------|
AN0 = 0        <------------|
AN1 = 109      <------------/
AN0 = 0
AN1 = 4095
AN0 = 0
AN1 = 4095
AN0 = 0
AN1 = 4095
AN0 = 0
AN1 = 4095
AN0 = 0
AN1 = 4095


If you are not seeing a full 4095 value or the 0 is not quite 0, try adding an STime microceconds delay in the ADC_Read procedure as such:

    ADCON0bits_ADGO = 1                     ' Start the conversion      
    DelayUS 10                              ' Add a small delay to make sure the ADC's capacitor has time to be maintained
    Repeat: Until ADCON0bits_ADGO = 0       ' Wait for the conversion to finish

But the delay is normally only required if rapid ADC readings are done in a loop, and not giving the ADC's internal capacitor long enough to be maintained. The delay can also be changed to smaller or larger and does the same task as the compiler's Declare ADin_Stime.

Jamie

Thank you very much Les that worked perfectly for me!

Jamie