One thing to note is that most recent devices (including the K40, K42, K83, and entire Q family) have a different ADC peripheral that is not supported by the ADC.bas module.
Here's an updated ADC.bas module (v1.3) that will detect this and issue an appropriate error message.
Code: Select all
{
*****************************************************************************
* Name : ADC.bas *
* Author : David John Barker *
* Notice : Copyright (c) 2007 Mecanique *
* : All Rights Reserved *
* Date : 13 FEB 2023 *
* Version : 1.3 13 FEB 2023 *
* : - add 'unsupported' error if '#define _adc2' detected *
* : 1.2 4 MAY 2022 *
* : - minor edits, adc consts, fix missing comma AN11 *
* : 1.1 2009 *
* : - Corrected bitnames for 18F1220, 18F1320 devices *
* : 1.0 2007 *
* : - initial release *
* Notes : This module does not support devices with ADCC/ADC2 peripheral *
*****************************************************************************
}
module ADC
// check for _adc2 peripheral and flag as unsupported
#if defined(_adc2) and (_adc2 > 0)
#error "ADC.bas does not support the ADCC/ADC2 peripheral"
#endif
// check if device file has defined the number of adc channels
#if (_adc = 0)
#error "device file '_adc' is 0... no adc channels defined"
#endif
// conversion time constants...
public const
FOSC_2 = %000,
FOSC_4 = %100,
FOSC_8 = %001,
FOSC_16 = %101,
FOSC_32 = %010,
FOSC_64 = %110,
FRC = %011
// channel select constants...
public const
AN0 = $00,
AN1 = $01,
AN2 = $02,
AN3 = $03,
AN4 = $04,
AN5 = $05,
AN6 = $06,
AN7 = $07
#if (_adc > 8)
public const
AN8 = $08,
AN9 = $09,
AN10 = $0A,
AN11 = $0B,
AN12 = $0C,
AN13 = $0D,
AN14 = $0E,
AN15 = $0F
#endif
#if (_adc > 16)
public const
AN16 = $10,
AN17 = $11,
AN18 = $12,
AN19 = $13,
AN20 = $14,
AN21 = $15,
AN22 = $16,
AN23 = $17
#endif
public dim
#if _device in (18F1220, 18F1320)
// ADCON0...
VCFG1 as ADCON0.6,
VCFG0 as ADCON0.5,
CHS2 as ADCON0.4,
CHS1 as ADCON0.3,
CHS0 as ADCON0.2,
GO_DONE as ADCON0.1,
ADON as ADCON0.0,
// ADCON1...
PCFG6 as ADCON1.6,
PCFG5 as ADCON1.5,
PCFG4 as ADCON1.4,
PCFG3 as ADCON1.3,
PCFG2 as ADCON1.2,
PCFG1 as ADCON1.1,
PCFG0 as ADCON1.0,
// ADCON2...
ADFM as ADCON2.7,
AQT2 as ADCON2.5,
AQT1 as ADCON2.4,
AQT0 as ADCON2.3,
ADCS2 as ADCON2.2,
ADCS1 as ADCON2.1,
ADCS0 as ADCON2.0,
// extended alias...
Convert as ADCON0.Booleans(1), // GO_DONE, POR = 0
RightJustify as ADCON2.Booleans(7) // ADFM, POR = false
#elseif (_adc > 8)
// ADCON0...
CHS3 as ADCON0.5,
CHS2 as ADCON0.4,
CHS1 as ADCON0.3,
CHS0 as ADCON0.2,
GO_DONE as ADCON0.1,
ADON as ADCON0.0,
// ADCON1...
VCFG1 as ADCON1.5,
VCFG0 as ADCON1.4,
PCFG3 as ADCON1.3,
PCFG2 as ADCON1.2,
PCFG1 as ADCON1.1,
PCFG0 as ADCON1.0,
// ADCON2...
ADFM as ADCON2.7,
ADCS2 as ADCON2.2,
ADCS1 as ADCON2.1,
ADCS0 as ADCON2.0,
// extended alias...
Convert as ADCON0.Booleans(1), // GO_DONE, POR = 0
RightJustify as ADCON2.Booleans(7) // ADFM, POR = false
#else
// ADCON0...
ADCS1 as ADCON0.7,
ADCS0 as ADCON0.6,
CHS2 as ADCON0.5,
CHS1 as ADCON0.4,
CHS0 as ADCON0.3,
GO_DONE as ADCON0.2,
ADON as ADCON0.0,
// ADCON1...
ADFM as ADCON1.7,
ADCS2 as ADCON1.6,
PCFG3 as ADCON1.3,
PCFG2 as ADCON1.2,
PCFG1 as ADCON1.1,
PCFG0 as ADCON1.0,
// extended alias...
Convert as ADCON0.Booleans(2), // GO_DONE, POR = 0
RightJustify as ADCON1.Booleans(7) // ADFM, POR = false
#endif
// ADCON(x) extended alias...
public dim
Enabled as ADCON0.Booleans(0), // ADON, POR = 0
ADResult as ADRESL.AsWord // 16 bit ADC result
// local helper variables...
dim
FAcquisitionTime as byte
{
****************************************************************************
* Name : SetConvTime *
* Purpose : Set the conversion time. Valid parameters include FOSC_2, *
* : FOSC_4, FOSC_8, FOSC_16, FOSC_32, FOSC_64 and FRC *
****************************************************************************
}
public sub SetConvTime(pValue as byte)
ADCS2 = pValue.2
ADCS1 = pValue.1
ADCS0 = pValue.0
end sub
{
****************************************************************************
* Name : SetAcqTime *
* Purpose : Sets the ADC acquisition time, in microseconds (us) *
****************************************************************************
}
public sub SetAcqTime(pATime as byte)
FAcquisitionTime = pATime
end sub
{
****************************************************************************
* Name : SetConfig *
* Purpose : Set configuration control bits *
****************************************************************************
}
public sub SetConfig(pConfig as byte)
#if (_adc > 8) or _device in (18F1220, 18F1320)
ADCON1 = pConfig and $3F
#else
ADCON1 = ADCON1 and $F0
pConfig = pConfig and $0F
ADCON1 = ADCON1 or pConfig
#endif
end sub
{
****************************************************************************
* Name : Read *
* Purpose : Read currently uses delayus for the acquistion time, which has *
* : the following minimum overheads *
* : 4Mhz - 24us *
* : 8Mhz - 12us *
* : 10Mhz - 8us *
* : 16Mhz - 5us *
* : 20Mhz plus - 2us *
* : If your acquistion time requirements fall below the above, *
* : just create a copy of this function in your main program (or *
* : another module) and replace delayms(ATime) with a constant *
****************************************************************************
}
public function Read(pChannel as byte) as word
// set channel...
CHS0 = pChannel.0
CHS1 = pChannel.1
CHS2 = pChannel.2
#if (_adc > 8)
CHS3 = pChannel.3
#endif
// read ADC...
if FAcquisitionTime = 0 then
Enabled = true
Convert = true
else
Enabled = true
delayus(FAcquisitionTime)
Convert = true
endif
// wait for completion, then disable ADC...
while Convert
wend
Enabled = false
Result = ADResult
end function
{
****************************************************************************
* Name : ShellSort (PRIVATE) *
* Purpose : Shell-Metzner sorting algorithm *
****************************************************************************
}
sub ShellSort(byref pArray() as word)
dim Finished as boolean
dim Jump, Index, LoopIndex as word
dim SwapTemp as word
Jump = bound(pArray)
while Jump > 1
Jump = Jump / 2
repeat
Finished = true
for LoopIndex = 0 to bound(pArray) - Jump
Index = LoopIndex + Jump
if pArray(LoopIndex) > pArray(Index) then
SwapTemp = pArray(LoopIndex)
pArray(LoopIndex) = pArray(Index)
pArray(Index) = SwapTemp
Finished = false
endif
next
until Finished
wend
end sub
{
****************************************************************************
* Name : GetMedian (PRIVATE) *
* Purpose : Returns the median of a sample data set *
****************************************************************************
}
function GetMedian(byref pSamples() as word) as word
ShellSort(pSamples)
result = pSamples((bound(pSamples) + 1) / 2)
end function
{
****************************************************************************
* Name : ReadMedian *
* Purpose : Takes 64 ADC samples and returns the median average. Although *
* : computationally expensive, this routine is quite useful as the *
* : result is not influenced by extreme high and low sample values *
****************************************************************************
}
public function ReadMedian(pChannel as byte) as word
dim Index as byte
dim Sum(64) as word
for index = 0 to bound(Sum)
Sum(Index) = Read(pChannel)
delayus(20)
next
Result = GetMedian(Sum)
end function
{
****************************************************************************
* Name : ReadMean *
* Purpose : Takes pRange ADC samples and returns the mean average. Much *
* : quicker than median average, but can be influenced by extreme *
* : high and low sample values *
****************************************************************************
}
public function ReadMean(pChannel as byte, pRange as byte = 64) as word
dim Index as byte
dim Sum as longword
if pRange = 0 then
Result = 0
else
Sum = 0
for index = 0 to pRange - 1
Sum = Sum + Read(pChannel)
delayus(20)
next
Result = Sum / pRange
endif
end function
// defaults
RightJustify = true
FAcquisitionTime = 20
end module
When you compile, if you get errors it's usually best to scroll down, find the first one, and work backwards.
Since you can't copy the contents of the 'Results' window, you can get a list of all the errors by opening the project's .sfp file with a text editor and look for the [COMPILE_ERROR] section...