Having recently begun to code for the Arduino Mega Funduino it became clear that the ADC read routines had not been
completed. The Atmel datasheet helped with configuring the necessary registers. All extra code is commented for
clear explanation.
Support has been added to access all 16 ADC pins on the AVR mega 2560.
' Analog to Digital conversion routines for Great Cow BASIC'Copyright(C)2006-2010HughConsidine,KentSchafer' Modified 02/2013 by Richard White to correctly configure'AVRAtmel2560asusedontheArduinoMegaFunduino' This library is free software; you can redistribute it and/or'modifyitunderthetermsoftheGNULesserGeneralPublic' License as published by the Free Software Foundation; either'version2.1oftheLicense,or(atyouroption)anylaterversion.' This library is distributed in the hope that it will be useful,'butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU'LesserGeneralPublicLicenseformoredetails.' You should have received a copy of the GNU Lesser General Public'Licensealongwiththislibrary;ifnot,writetotheFreeSoftware' Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA'********************************************************************************'IMPORTANT:'THISFILEISESSENTIALFORSOMEOFTHECOMMANDSINGCBASIC.DONOTALTERTHISFILE'UNLESS YOU KNOW WHAT YOU ARE DOING. CHANGING THIS FILE COULD RENDER SOME GCBASIC'COMMANDSUNUSABLE!'********************************************************************************'OriginalcodebyHughConsidine'18Fxx31 code by Kent Schafer'Commands:'var = ReadAD(port) Reads port, and returns value.'ADFormat(type)ChooseLeftorRightjustified'ADOff Set A/D converter off. Use if trouble is experienced when'attemptingtouseportsindigitalmodeDIMWork_ADCasword#defineFormat_Left0#defineFormat_Right255'Acquisition time. Can be reduced in some circumstances - see PIC manual for details#define AD_Delay 2 10us'Optimisation#defineADSpeedMediumSpeed#defineHighSpeed255#defineMediumSpeed128#defineLowSpeed0#defineInternalClock192'Port names'PICstyle#defineAN00#defineAN11#defineAN22#defineAN33#defineAN44#defineAN55#defineAN66#defineAN77#defineAN88#defineAN99#defineAN1010#defineAN1111#defineAN1212#defineAN1313'AVR style#define ADC0 0#define ADC1 1#define ADC2 2#define ADC3 3#define ADC4 4#define ADC5 5#define ADC6 6#define ADC7 7#define ADC8 8#define ADC9 9#define ADC10 10#define ADC11 11#define ADC12 12#define ADC13 13#define ADC14 14#define ADC15 15macro LLReadAD #IFDEF PIC 'SetupA/D'Make necessary ports analog 'CodeforPICswitholderA/D(NoANSELregister)#IFDEFNoVar(ANSEL)#IFDEFNoVar(ANSEL0)#IFDEFNoVar(ANSELA)#IFDEFNoVar(ANSELB)#IFDEFNoBit(PCFG4)#IFDEFNoVar(ADCON2)#IFDEFNoBit(ANS0)'Example: 16F877A #IFDEF Bit(PCFG3) SET PCFG3 OFF #ENDIF SET PCFG2 OFF SET PCFG1 OFF SET PCFG0 OFF #ENDIF 'Example: 10F220#IFDEFBit(ANS0)SETANS0OFFSETANS1OFF#ENDIF#ENDIF#IFDEFVar(ADCON2)'Example: 18F4620 #IFDEF BIT(PCFG3) SET PCFG3 OFF SET PCFG2 OFF SET PCFG1 OFF SET PCFG0 OFF #ENDIF #ENDIF #ENDIF 'PICswithPCFG4andhigheruseADCON1asanANSELtyperegister'Example: 18F1320 #IFDEF Bit(PCFG4) 'Some18F8xxxxchipshaveerrorinchipdefinition'They claim to have PCFG4, but actually don't,canspotthembypresenceofADCON2DimAllANSELAsByteAliasADCON1AllANSEL=0ADTemp=ADReadPort+1SetCOnDoRotateAllANSELLeftdecfszADTemp,FLoop#ENDIF'ANSELB/A #ENDIF #ENDIF 'Codefor16F193xchips(andothers?)withANSELA/ANSELB/ANSELEregisters#IFDEFVar(ANSELA)SelectCaseADReadPort#IFDEFOneOf(CHIP_16F1826,CHIP_16F1827)Case0: SetANSELA.0OnCase1: SetANSELA.1OnCase2: SetANSELA.2OnCase3: SetANSELA.3OnCase4: SetANSELA.4OnCase11: SetANSELB.1OnCase10: SetANSELB.2OnCase9: SetANSELB.3OnCase8: SetANSELB.4OnCase7: SetANSELB.5OnCase5: SetANSELB.6OnCase6: SetANSELB.7On#ENDIF#IFDEFOneOf(CHIP_16F1933,CHIP_16F1934,CHIP_16F1936,CHIP_16F1937,CHIP_16F1938,CHIP_16F1939)Case0: SetANSELA.0OnCase1: SetANSELA.1OnCase2: SetANSELA.2OnCase3: SetANSELA.3OnCase4: SetANSELA.5On#IFDEFVar(ANSELB)Case12: SetANSELB.0OnCase10: SetANSELB.1OnCase8: SetANSELB.2OnCase9: SetANSELB.3OnCase11: SetANSELB.4OnCase13: SetANSELB.5On#ENDIF#IFDEFVar(ANSELE)Case5: SetANSELE.0OnCase6: SetANSELE.1OnCase7: SetANSELE.2On#ENDIF#ENDIFEndSelect#ENDIF'ANSEL0/ANSEL #ENDIF #ENDIF 'CodeforPICswithnewerA/D(withANSELregister)#IFDEFVar(ANSEL)#IFDEFVar(ANSELH)DimAllANSELAsWordAliasANSELH,ANSEL#ENDIF#IFDEFNoVar(ANSELH)DimAllANSELAsByteAliasANSEL#ENDIFAllANSEL=0ADTemp=ADReadPort+1SetCOnDoRotateAllANSELLeftdecfszADTemp,FLoop#ENDIF'Code for 18F4431, uses ANSEL0 and ANSEL1 #IFDEF Var(ANSEL0) #IFDEF Var(ANSEL1) Dim AllANSEL As Word Alias ANSEL1, ANSEL0 #ENDIF #IFDEF NoVar(ANSEL1) Dim AllANSEL As Byte Alias ANSEL0 #ENDIF AllANSEL = 0 ADTemp = ADReadPort + 1 Set C On Do Rotate AllANSEL Left decfsz ADTemp,F Loop #ENDIF 'SetAutoorSingleConvertMode#IFDEFBit(ACONV)SETACONVOFF'Single shot mode SET ACSCH OFF 'SinglechannelCONVERSION'GroupA IF ADReadPort = 0 OR ADReadPort = 4 OR ADReadPort = 8 Then SET ACMOD1 OFF SET ACMOD0 OFF END IF 'GroupBIFADReadPort=1ORADReadPort=5ThenSETACMOD1OFFSETACMOD0ONENDIF'GroupC IF ADReadPort = 2 OR ADReadPort = 6 Then SET ACMOD1 ON SET ACMOD0 OFF END IF 'GroupDIFADReadPort=3ORADReadPort=7ThenSETACMOD1ONSETACMOD0ONENDIF#ENDIF'Set conversion clock #IFDEF Bit(ADCS0) #IFDEF ADSpeed HighSpeed SET ADCS1 OFF SET ADCS0 OFF #ENDIF #IFDEF ADSpeed MediumSpeed SET ADCS1 OFF SET ADCS0 ON #ENDIF #IFDEF ADSpeed LowSpeed SET ADCS1 ON SET ADCS0 ON #ENDIF #IFDEF ADSpeed InternalClock SET ADCS1 ON SET ADCS0 ON #ENDIF #ENDIF 'Chooseport#IFDEFBit(CHS0)SETADCON0.CHS0OFFSETADCON0.CHS1OFF#IFDEFBit(CHS2)SETADCON0.CHS2OFF#IFDEFBit(CHS3)SETADCON0.CHS3OFF#ENDIF#ENDIFIFADReadPort.0OnThenSetADCON0.CHS0OnIFADReadPort.1OnThenSetADCON0.CHS1On#IFDEFBit(CHS2)IFADReadPort.2OnThenSetADCON0.CHS2On#IFDEFBit(CHS3)IfADReadPort.3OnThenSetADCON0.CHS3On#ENDIF#ENDIF#ENDIF#IFDEFBIT(GASEL0)'GROUP A SELECT BITS IF ADReadPort = 0 THEN SET GASEL1 OFF SET GASEL0 OFF END IF IF ADReadPort = 4 THEN SET GASEL1 OFF SET GASEL0 ON END IF IF ADReadPort = 8 THEN SET GASEL1 ON SET GASEL0 OFF END IF 'GROUPCSELECTBITSIFADReadPort=2THENSETGCSEL1OFFSETGCSEL0OFFENDIFIFADReadPort=6THENSETGCSEL1OFFSETGCSEL0ONENDIF'GROUP B SELECT BITS IF ADReadPort = 1 THEN SET GBSEL1 OFF SET GBSEL0 OFF END IF IF ADReadPort = 5 THEN SET GBSEL1 OFF SET GBSEL0 ON END IF 'GROUPDSELECTBITSIFADReadPort=3THENSETGDSEL1OFFSETGDSEL0OFFENDIFIFADReadPort=7THENSETGDSEL1OFFSETGDSEL0ONENDIF#ENDIF'Enable A/D SET ADCON0.ADON ON 'AcquisitionDelayWaitAD_Delay'Read A/D #IFDEF Bit(GO_DONE) SET ADCON0.GO_DONE ON Wait While ADCON0.GO_DONE ON #ENDIF #IFNDEF Bit(GO_DONE) #IFDEF Bit(GO) SET ADCON0.GO ON Wait While ADCON0.GO ON #ENDIF #ENDIF 'SwitchoffA/D#IFDEFVar(ADCON0)SETADCON0.ADONOFF#IFDEFNoVar(ANSEL)#IFDEFNoVar(ANSELA)#IFDEFNoBit(PCFG4)#IFDEFNoVar(ADCON2)#IFDEFNoBit(ANS0)#IFDEFBit(PCFG3)SETPCFG3OFF#ENDIFSETPCFG2ONSETPCFG1ONSETPCFG0OFF#ENDIF#IFDEFBit(ANS0)SETANS0OFFSETANS1OFF#ENDIF#ENDIF#IFDEFVar(ADCON2)#IFDEFBIT(PCFG3)SETPCFG3ONSETPCFG2ONSETPCFG1ONSETPCFG0ON#ENDIF#ENDIF#ENDIF'For 18F1320, which uses ADCON1 as an ANSEL register #IFDEF Bit(PCFG4) ADCON1 = 0 #ENDIF #ENDIF #ENDIF #ENDIF 'ClearwhateverANSELvariantsthechiphas#IFDEFVar(ANSEL)ANSEL=0#ENDIF#IFDEFVar(ANSELH)ANSELH=0#ENDIF#IFDEFVar(ANSEL0)ANSEL0=0#ENDIF#IFDEFVar(ANSEL1)ANSEL1=0#ENDIF#IFDEFVar(ANSELA)ANSELA=0#ENDIF#IFDEFVar(ANSELB)ANSELB=0#ENDIF#IFDEFVar(ANSELE)ANSELE=0#ENDIF#ENDIF#IFDEFAVR'Select channel ** modified for atmel Mega 2560 'SelectVoltagereferencesourceasVCC(5V)'**new need to modify these bits after writing to ADMUX register. set REFS1 off '**newbecauseallbitsareclearedwhenwritingADreadporttoADMUXsetREFS0on'**new if chipMHZ > 15 then SET ADPS2 On 'forprescalerSETADPS1OnSETADPS0On'**new divide by 128 if chipspeed > 15 Mhz. Runs ADC conversio clock slower end if if ADReadPort >= 8 then set MUX5 on '**NEWformega2560.selects3rdbitinADCSRBregisterforADC8thruADC15ADMUX.0=ADReadPort.0'Dont write bits 3 & 4 to MUX as it selects diferential ADC conversion ADMUX.1 = ADReadPort.1 'manuallycopyindividualbitsADMUX.2=ADReadPort.2elseADMUX.0=ADReadPort.0'Dont write bits 3 & 4 to MUX as it selects diferential ADC conversion ADMUX.1 = ADReadPort.1 'manuallycopyindividualbitsADMUX.2=ADReadPort.2setMUX5off'MUX5 is for selecting ADC8-ADC15 end if ADMUX.3 = 0 'CLEARbits3,4,5**experimentalADMUX.4=0'manually copy individual bits ADMUX.5 = 0 'Setconversionclock#IFDEFBit(ADPS2)'disabled this section experimentally '#IFDEFADSpeedHighSpeed' SET ADPS2 Off 'SETADPS1Off' SET ADPS0 Off '**new'#ENDIF '#IFDEFADSpeedMediumSpeed' SET ADPS2 On 'SETADPS1Off' SET ADPS0 Off '**new'#ENDIF '#IFDEFADSpeedLowSpeed' SET ADPS2 On 'SETADPS1On' SET ADPS0 On '**newdivideby128'#ENDIF #ENDIF 'AcquisitionDelayWaitAD_Delay'Take reading Set ADEN On Set ADSC On Wait While ADSC On Set ADEN Off #ENDIFend macrofunction ReadAD(ADReadPort)'Setupfor8bit#IFDEFAVR#IFDEFBit(ADLAR)SetADReadPort.ADLAROff#endif#ENDIF'Perform conversionLLReadAD'Writeoutput#IFDEFPIC#IFDEFVar(ADRESH)ReadAD=ADRESH#ENDIF#IFDEFNoVar(ADRESH)ReadAD=ADRES#ENDIF#ENDIF#IFDEFAVRWork_ADC=peek(0x78)'**new. need to read low register first. use reserved working variable Work_ADC_H=peek(0x79) 'readhighregisterasadummytoclearDATAregister.OtherwisenextADCconversioncannotberead...Work_ADC=Work_ADC/[word]4'shift right twice to remove 2 LSB READAD=Work_ADC 'copyresulttoREADADsothatfunctioncanreturnvalue#ENDIFendfunction'Large ReadADfunction ReadAD10(ADReadPort) As Word#IFDEF PIC 'SetupA/Dformat#IFDEFBit(ADFM)SETADFMON#ENDIF#ENDIF#IFDEFAVRDimLLADResultAsWordAliasADCH,ADCL#IFDEFBit(ADLAR)SetADReadPort.ADLAROff#EndIf#ENDIF'Do conversionLLReadAD#IFDEF PIC 'Writeoutput#IFDEFNoVar(ADRESL)ReadAD10=ADRES#ENDIF#IFDEFVar(ADRESL)ReadAD10=ADRESL#ENDIF#IFDEFVar(ADRESH)ReadAD10_H=ADRESH#ENDIF'Put A/D format back to normal #IFDEF Bit(ADFM) SET ADFM OFF #ENDIF#ENDIF#IFDEF AVR ReadAD10 = peek(0x78) '**new.needtoreadlowregisterfirstReadAD10_H=peek(0x79)#ENDIFendfunction'This sub is deprecatedsub ADFormat(ADReadFormat) SET ADFM OFF IF ADReadFormat.1 ON THEN SET ADFM ON end sub'ThissubisdeprecatedsubADOff'Disable the A/D converter, and set all ports to digital.'Thissubisdeprecated,InitSysautomaticallyturnsoffA/DSETADCON0.ADONOFF#IFDEFNoBit(PCFG4)#IFDEFNoVar(ANSEL)#IFDEFNoVar(ADCON2)#IFDEFBit(PCFG3)SETPCFG3OFF#ENDIFSETPCFG2ONSETPCFG1ONSETPCFG0OFF#ENDIF#IFDEFVar(ADCON2)SETPCFG3ONSETPCFG2ONSETPCFG1ONSETPCFG0ON#ENDIF#ENDIF#ENDIF#IFDEFBit(PCFG4)#IFDEFBit(PCFG6)SETPCFG6ON#ENDIF#IFDEFBit(PCFG5)SETPCFG5ON#ENDIFSETPCFG4ONSETPCFG3ONSETPCFG2ONSETPCFG1ONSETPCFG0ON#ENDIF#IFDEFVar(ANSEL)ANSEL=0#ENDIF#IFDEFVar(ANSELH)ANSELH=0#ENDIFendsub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Having recently begun to code for the Arduino Mega Funduino it became clear that the ADC read routines had not been
completed. The Atmel datasheet helped with configuring the necessary registers. All extra code is commented for
clear explanation.
Support has been added to access all 16 ADC pins on the AVR mega 2560.