Forum Index
HomeZBasic Home   Forum RulesForum Rules   Forum FAQForum FAQ   MemberlistMemberlist   UsergroupsUsergroups   RSS FeedRSS Feed
Site SearchSite Search   LinksLinks   DownloadDownload   Digests and SubscriptionsDigests and Subscriptions
ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in   RegisterRegister
Reading analogue values

 
Post new topic   Reply to topic    Forum Index -> ZBasic Language
Author Message
FFMan



Joined: 09 Jan 2010
Posts: 236

Posted: 16 January 2012, 16:48 PM    Post subject: Reading analogue values Reply with quote

a while back i implemented a battery monitor routine in one of my projects and used the code below (cadged from an example) to do this reliably.

Question - why is this code required and can't a simple call to getadc work ?

What amendments are required to the code to work on a 128a1 cpu ?

Code:

'Function to read an adc voltage using the internal reference
Function readADC(ByVal chan as Byte) as Single
   ' Wait for the ADC to be available to use.
   Do While CBool(Register.ADCSRA And &H80)
      Sleep(1)
   Loop
   Call LockTask()

   ' Select the desired channel and the internal 2.56V reference.
   Register.ADMUX = (chan And &H07) Or &Hc0

   ' Start a conversion using the 128 prescaler (the resulting
   ' conversion clock must be between 50KHz and 200KHz).
   Register.ADCSRA = &Hd7

   ' Wait for conversion completion. Using the 128 prescaler,
   ' the conversion should only take about 0.2mS.
   Do While Not CBool(Register.ADCSRA And &H10)
      Sleep(1)
   Loop

   ' Read the conversion result and turn off the converter.
   Dim adcVal as UnsignedInteger
   adcVal = Register.ADC
   Register.ADCSRA = 0
   Call UnlockTask()

   ' Convert the ADC value to a voltage (2.56V is full scale
   ' voltage, 1024 is the number of quantization steps).
   readADC = CSng(adcVal) * (2.56 / 1024.0)
End Function
Back to top
dkinzer
Site Admin


Joined: 03 Sep 2005
Posts: 2514
Location: Portland, OR

Posted: 16 January 2012, 17:21 PM    Post subject: Re: Reading analogue values Reply with quote

FFMan wrote:
why is this code required and can't a simple call to getadc work ?
If the capabilities of GetADC() meet your requirements you can use it directly. For the xmega, the GetADC() function uses a reference voltage of Vcc/1.6 and performs a single-ended conversion. If this is suitable for your application then you're all set.

The forum contains at least two posts with a readADC() function: one for differential conversion and one for using an internal reference voltage. The same general ideas can be implemented on the xmega but the specifics are different as described in the xmega datasheet.
Back to top
FFMan



Joined: 09 Jan 2010
Posts: 236

Posted: 18 January 2012, 20:50 PM    Post subject: Reply with quote

I think i will be fine using getadc.

I am trying to read a voltage of 2.23, with an aref of 3.3v

However i get the same value whether reading 2.23v or 2.45v of approx 1135

I see you note about the reference being aref/1.6, does this mean this is the max voltage that can be read. I can scale it some more if required.

thanks
Back to top
dkinzer
Site Admin


Joined: 03 Sep 2005
Posts: 2514
Location: Portland, OR

Posted: 18 January 2012, 22:54 PM    Post subject: Reply with quote

FFMan wrote:
I see you note about the reference being aref/1.6, does this mean this is the max voltage that can be read.
The referenced used by GetADC() is Vcc/1.6 rather than aref/1.6. If you want to use an external reference voltage you'll have to implement a function something like the one below (untested). Except for the reference selected, this is essentially equivalent to the xmega code for GetADC().
Code:
' Function to read an adc voltage using an external reference.
Function readADC(ByVal chan as Byte) as Single
   ' Define the external reference voltage value.
   Const ADC_REF_VOLTS as Single = 2.56

   ' Wait for the ADC to be available to use.
   Do While CBool(Register.ADCA_CTRLA And &H01)
      Sleep(1)
   Loop
   Call LockTask()

   ' Set the prescaler to ensure the ADC clock is < 800KHz.
   Register.ADCA_PRESCALER = &H04

   ' Select the REFA external reference.
   Register.ADCA_REFCTRL = &H20
   Register.ADCA_CTRLB = 0

   ' Select the desired channel.
   Register.ADCA_CH0_MUXCTRL = Shl(chan, 3) And &H38
   Register.ADCA_CH0_CTRL = 1

   ' Ensure the "done" flag is clear, enable the ADC and start a conversion.
   Register.ADCA_INTFLAGS = 1
   Register.ADCA_CTRLA = &H05

   ' Wait for conversion completion.
   Do While Not CBool(Register.ADCA_INTFLAGS And &H01)
      Sleep(1)
   Loop

   ' Read the conversion result.
   Dim adcVal as UnsignedInteger
   adcVal = Register.ADCA_CH0RES

   ' Disable the ADC and Clear the completion flag.
   Register.ADCA_CTRLA = 0
   Register.ADCA_INTFLAGS = 1

   Call UnlockTask()

   ' Convert the ADC value to a voltage.
   readADC = CSng(adcVal) * (ADC_REF_VOLTS / 4096.0)
End Function


Last edited by dkinzer on 19 January 2012, 17:57 PM; edited 1 time in total
Back to top
dkinzer
Site Admin


Joined: 03 Sep 2005
Posts: 2514
Location: Portland, OR

Posted: 19 January 2012, 0:53 AM    Post subject: Reply with quote

I made a change to the code setting the CH0_MUXCTRL register. The code is still untested, however.

Note, also, that if an internal reference is used, the ADC must be enabled and then a certain amount of time (called the settling time) must pass before the first conversion is started. The code above doesn't include this detail because it uses an external reference, assumed to be on always.
Back to top
FFMan



Joined: 09 Jan 2010
Posts: 236

Posted: 19 January 2012, 11:56 AM    Post subject: Reply with quote

i think this may be getting more involved than i need. I simply need to read the battery voltage which i can scale as required.

I have wired in the reference voltage using the choke and the capacitors exist already on the break out board but if i don't need to use this then that is fine.

So some advice, best way to read voltage on 128a1. i'm using pin b.5, ideally using getadc to keep it simple and non-atomic (as there are up to 4 serial streams running concurrently).

For clarity what is the maximum voltage that can be read ?

thanks
Back to top
dkinzer
Site Admin


Joined: 03 Sep 2005
Posts: 2514
Location: Portland, OR

Posted: 19 January 2012, 18:10 PM    Post subject: Reply with quote

FFMan wrote:
For clarity what is the maximum voltage that can be read ?
The maximum voltage that can be converted is one quantization level below the reference voltage (due to the fact that the digital representation ranges from 0 to 2^N - 1). For an xmega, which has a 12-bit ADC, running at 3.3V and using the internal Vcc/1.6 reference (as does the GetADC() function) the maximum voltage that can be converted is (3.3V/1.6 * 4095/4096)=2.062V.

Note that if you use the internal Vcc/1.6 reference, the external reference voltage (Aref or Bref) is not needed. If you do use an external reference, the value is limited to the range 1.0V <= Vref <= (Vcc-0.6V).
Back to top
FFMan



Joined: 09 Jan 2010
Posts: 236

Posted: 19 January 2012, 20:02 PM    Post subject: Reply with quote

something is not going quite right. i get the same values returned from getadc for a voltage of 1.2v of approx 1107 and the same for voltage 1.87v

I am using pin b.5 on a 128a1 and i have set it to inputtristate before use.

I have a voltage of 3.28v on avcc but am not using it in this instance.

is this behaving properly or do i have a problem somewhere ?

thanks
Back to top
dkinzer
Site Admin


Joined: 03 Sep 2005
Posts: 2514
Location: Portland, OR

Posted: 19 January 2012, 23:26 PM    Post subject: Reply with quote

FFMan wrote:
I am using pin b.5 on a 128a1 and i have set it to inputtristate before use.
It could be that there is an issue in the ZBasic xmega code for GetADC() for the pins of PortB. If you get expected results on a pin of PortA that's probably the issue. We'll look into it here.
Back to top
FFMan



Joined: 09 Jan 2010
Posts: 236

Posted: 20 January 2012, 8:17 AM    Post subject: Reply with quote

ok - I think I can easily switch to a port A pin but won't be able to try this until saturday evening probably now, but i shall and let you know, unless of course in the mean time you find a problem.

the documentations lists port B as usable in the getadc section.
Back to top
dkinzer
Site Admin


Joined: 03 Sep 2005
Posts: 2514
Location: Portland, OR

Posted: 20 January 2012, 15:45 PM    Post subject: Reply with quote

FFMan wrote:
the documentations lists port B as usable in the getadc section.
True enough. My point was that it should work but there may be a flaw in the ZBasic library code that prevents it from working.
Back to top
FFMan



Joined: 09 Jan 2010
Posts: 236

Posted: 20 January 2012, 16:26 PM    Post subject: Reply with quote

dkinzer wrote:
My point was that it should work but there may be a flaw in the ZBasic library code that prevents it from working.
i understand, i was just pointing it out for compelteness because my experience is that your documentation is usually very accurate.
Back to top
dkinzer
Site Admin


Joined: 03 Sep 2005
Posts: 2514
Location: Portland, OR

Posted: 20 January 2012, 21:07 PM    Post subject: Reply with quote

FFMan wrote:
I am using pin b.5 on a 128a1 and i have set it to inputtristate before use.
We confirmed that the ADC configuration was not correct for PortB inputs. You can download a new ZBasic Library (v3.3.4) for the xmegaA1 using the link below. Since the change only affects the xmegaA1, there is no update for other devices at this time. This update must be used with a ZBasic compiler in the v3.3 series.

http://www.zbasic.net/download/zlib/3.3/zlib_3-3-4_xmegaA1.zip
Back to top
FFMan



Joined: 09 Jan 2010
Posts: 236

Posted: 21 January 2012, 10:37 AM    Post subject: Reply with quote

thanks - that seems to be returning more expected values

I'll calibrate it later.

thanks
Back to top
Display posts from previous:   
Post new topic   Reply to topic    Forum Index -> ZBasic Language Time synchro. with the server - Timezone/DST with your computer
Page 1 of 1

 


All content Copyright © 2005-2012 Elba Corp. All Rights Reserved.
Opinions expressed in posts are those of the author and not necessarily those of Elba Corp.
Powered by phpBB © 2001, 2005 phpBB Group