Menu

A2D usage

Help
2009-02-14
2013-05-30
  • Edward LaBudde

    Edward LaBudde - 2009-02-14

    Hi all, it's the Ex-PIC virgin a.k.a. "newbie" (since I lost my virginity by completing a simple program that actually works!)

    #1. Question on A2D use.  Is it necessary to use the “#include a-d.h” when using the A2D channels?  What is the purpose of this file and what are the advantages of using it or not?

    #2.  Does the readAD10 automatically dim the results as word?  It suggests this in the help file.

    Thanks, Ed.

     
    • kent_twt4

      kent_twt4 - 2009-02-14

      1)  Not required to use the #include <a-d.h>, as GCBasic picks thru the include/lowlevel header files when compiling.  If you developed your own header say, and had it in the include folder (not lowlevel) then you would use:

      #include <MyA-D.h>

      The advantages of the ReadAD and ReadAD10 functions is a quick and easy read of an a-d input, scaled to 8 and 10 bits respectively, and referenced between Vdd and Vss.  The unique functionality of the a-d.h is that it can be used across the broad spectrum of device selections (10f-18f).  For more advanced functionality then you can set the sampling speed, V+ref, V-ref bits  etc. as you see fit.  Modify the a-d.h into MyA-D.h and have all kinds of fun!

      Using header files just make your main code a lot cleaner, and easier to read.

      2)  The readAD10 handles the word value results, just be sure that any assigned variables are dimensioned as words, or you will think to yourself, why are my results stuck at 255?

       
    • Edward LaBudde

      Edward LaBudde - 2009-02-14

      Kent thanks, Ed.

       
    • Keith Renecle

      Keith Renecle - 2009-02-15

      Hi Kent,
      I am back fiddling with the A/D and low pin count 12F675 again. You kndly helped me before with this, but I ran out of time to check it all out. What I found when I can't store anything in the high order byte, is that maybe my loop is too fast for the A/D cap to charge properly, so I tried inserted delays in the loop. This changes the results. Here is my short test program:

      #chip 12F675, 4
      #config Osc = Int
      dir GPIO.0 in
      dim num as word

      CheckAD:
      num = ReadAD10(AN0)
      wait 100 ms 'This makes a difference
      EPWrite (0, num_H)
      EPWrite (1, num)

      Goto CheckAD

      The "wait 100 ms" allows me to read a bigger number on my PicKit 2 proto board from the pot connected between the supply rails. The problem now is that I need to use this in a servo loop that cycles in 20 ms, so I can't use this longer delay. I tried various delay lengths and get different results each time, so the question is.....am I correct in assuming that the delay is in fact allowing the internal A/D cap to charge up properly? Is there another way around this? Thanks.

      Keith R

       
    • kent_twt4

      kent_twt4 - 2009-02-15

      GCBasic doen't like the EPWrite (0, num_H), try the starting address at 1.

       
    • Nobody/Anonymous

      Ussually AD conversion takes no more than 20 us, if the source impedance is very very hight then is possible to grow to 40 us... is recomended source impedance not higher than 5 Kohm.

      I see GCBasic adc functions has  acquisition delay and "wait for end of conversion" loop,..

      Then it should read correctly without adding any delay... anyway when you add a delay afther the "ReadAD" function, the conversion is already done and the readed values are already passed to the register/s... that delay just waste time for nothing...

      Regards.

       
    • Keith Renecle

      Keith Renecle - 2009-02-15

      Hi Guy's, I tried using the eeprom numbers from 1 instead of 0, and it made no difference. Leaving out any delay, makes the high order bytes read FF and the low order read to a max of 3E. If I make the delay 10 ms, the eeprom mem reads 00 3E maximum. As soon as the delay is set over 84 mS, then it reads from 00 to 03 4E.

      Just by the way, the feed to the AD input is via a 1K resistor that comes with the demo board. Any ideas??

      Keith R

       
    • Keith Renecle

      Keith Renecle - 2009-02-15

      Just another test for this......I used a 16F690 chip, and it does the same. If the A/D reads immediately or no more than 20 uS, then how come adding a delay makes a difference? Do I need to add something else like the sampling speed, V+ref, V-ref bits etc.? Thanks.

      Keith R

       
    • Nobody/Anonymous

      Hi Keith... i had a look to the generated asm for your code, and may be there is a bug or something not working ok... i don't know if a compiler problem or a wrong use... or may be there is not problems and i am in a mistake...

      The asm code for the ReadAD10:

      FN_READAD10
          bsf    ADCON0,ADFM
          banksel    ALLANSEL
          clrf    ALLANSEL  ;..........<<<<---------- ANSEL = 0 (ALLANSEL = ANSEL)
          banksel    ADREADPORT
          incf    ADREADPORT,W
          movwf    ADTEMP
          bsf    STATUS,C
      SysDoLoop_S1
          banksel    ALLANSEL
          rlf    ALLANSEL,F;........<<< rlf ANSEL when ANSEL=0 ?? missing bsf some bits..???
          banksel    ADTEMP
          decfsz    ADTEMP,F
          goto    SysDoLoop_S1
      SysDoLoop_E1
          banksel    ANSEL
          bcf    ANSEL,ADCS1
          bsf    ANSEL,ADCS0
          banksel    ADCON0
          bcf    ADCON0,CHS0
          bcf    ADCON0,CHS1
          btfsc    ADREADPORT,0
          bsf    ADCON0,CHS0
          btfsc    ADREADPORT,1
          bsf    ADCON0,CHS1
          bsf    ADCON0,ADON
          movlw    2
          movwf    SysWaitTemp10US
          call    Delay_10US
          bsf    ADCON0,GO_DONE
      SysWaitLoop2
          btfsc    ADCON0,GO_DONE
          goto    SysWaitLoop2
          bcf    ADCON0,ADON
          banksel    ANSEL
          clrf    ANSEL
          movf    ADRESL,W
          banksel    READAD10
          movwf    READAD10
          clrf    READAD10_H
          movf    ADRESH,W
          movwf    READAD10_H
          bcf    ADCON0,ADFM
          return

      It looks like ANSEL,0-3 (analog select bits) will be always 0... then no inputs will be analog....

      If this is right you're reading a digital input as analog.. unsected behaivor is sure .

      Greetings..

       
    • kent_twt4

      kent_twt4 - 2009-02-15

      Keith, O.K. see what you are saying now.  The EEProm address at 0 or 1 shouldn't matter, as it seemed to be an effect of my test program.  You definitely miss the some high bytes when the wait state goes below 20ms, at least with the on board 10k pot.  Had me chasing my tail there, too.  Must have had something else going on in previous programs so as not to notice that effect.

      Change to the previously suggested 5k pot and you will not miss a beat.  The impedance is even more critical for 18f's I believe, with a 2.5K suggested limit.  You could test it with an off board pot too see for yourself.

      If this is for your rc planes, then you probably won't be recording a reading every 20ms anyway, or else you will have to go with an off board eeprom to hold all the readings.

       
    • Keith Renecle

      Keith Renecle - 2009-02-16

      I only had higher resistance pot in my junk box, but I did try a 1K pot, and it reads exactly the same as the 10K. It will give a smooth reading from one extreme to the other, if I use a wait period of more than 84 mS.

      I am using the PIC in my model plane for the electric motor control, so it has to have a frame rate of 20 mS, as per a normal model servo pulse ie. 1 to 2 mS pulse width and a frame rate of 20 mS.

      First question: I read a voltage on the pin for te A/D input of 3.9 volts, but I read the eeprom as 03 4E or 846 decimal. How does this number relate to the input voltage?

      2nd question: Is the problem due to the way the A/D conversion is done, or is it the way that the data is being written to the eeprom? How would I check this?

      It sounds to me like there could be a problem in the ad read code. If I understood the assembler posted above, I could suggest a cure......but I don't, and that's why I'm playing with GC Basic.

       
    • Nobody/Anonymous

      In the asm i can not see where ANSEL 0-2 bits are set to select channel as analog, may be i just cannot see... and my simulator does not support 16f675.

      Suggestion:
      Simulate the adread10 code and have a look to the ANSEL register...

      Add a breakpoint at the begining of FN_READAD10.... then step by step...
      The ANSEL 0-2 bits should set to 1 depending on the chanel to be redaded, in your case ANSEL,0 should be to 1 before ADC conversion is started.

      Other cuestion:
      There is a 20 us delay to ensure acquisition of the selected channel:

      bsf ADCON0,ADON
      movlw 2
      movwf SysWaitTemp10US
      call Delay_10US

      There is a loop to ensure that ADC cap is fully charged and conversion is correctly done:

      SysWaitLoop2
      btfsc ADCON0,GO_DONE
      goto SysWaitLoop2

      this means that the adc registers (ADRESL, ADRESH) are not readed until the conversion is correctly done, once this registers are readed any aditional delay should not do anything to the adc read... the conversion is already done and registers are already readed....

      Greetings...

       
    • Keith Renecle

      Keith Renecle - 2009-02-16

      Hi, I presume that you are referring to the asm for the read a/d code in GC Basic? I unfortunately do not understand at this time, so Kent or Hugh could maybe comment on this. Maybe this code just cannot work for the smaller chips like the 12 and 16 series of PIC's.

      Keith R

       
    • Nobody/Anonymous

      Ok... you can try to configure ADC yourself instead of using gcbasic function.
      This way you can know if the problem is in the gcbasic function or not.

      This is an example to read adc channel 0 with 12f675 and 4 MHz clock.

      To avoid problems with EPWrite:
      A led attached to GPIO.1 (or any other you want) can be used as feedback, with  511 value in the "if num >...." the led will toggle just when pot is at 50%. you can try with other values to ensure led toggle at the desired Voltage. (don't forget led resistor)
      Readed values go from 0 to 1023 -> 0 to 5V .

      #chip 12F675, 4
      #config Osc = Int

      dir GPIO out 'Needed to attach the led
      dir GPIO.0 in

      dim num as word

      'Configure ADC to read channel 0 (10 bits) 4 MHz clock:
      ANSEL =   b'01010001
      ADCON0 = b'10000001'

      wait 1 ms 'As this delay is outside the main loop it can be very  long (just 20 us needed)

      CheckAD:

      set ADCON0.1 on '...................Start conversion

      conv:
      if ADCON0.1 on then goto conv '...Wait for conversion finished

      num = ADRESL
      num_H = ADRESH

      if num > 511 then set GPIO.1 on 'you can connect  a led to GPIO.1 to have feedback
      if num < 511 then set GPIO.1 off 'Don't worry about num_H GCBasic does the work

      EPWrite (0, num_H)
      EPWrite (1, num)

      Goto CheckAD

       
    • kent_twt4

      kent_twt4 - 2009-02-16

      Keith,  if you are reading 03 4E or 846 decimal at 3.9, then that is the correct value.  The math for ReadAD10 is 10 bits, with the max reading in hex 03 FF, or 1023 decimal, make sense?

      So realizing that the default ReadAD10 (or ReadAD)  function is set between Vdd (5V nominal) and Vss (0V).  Then for the ReadAD10 and its 10 bits of resolution would equate to:

      X  /  Vdd =  846 / 1023

      My Pickit 2 Vdd is 4.86V though, probably because of a reverse polarity protection diode.  Took an a-d reading of 03 4C, 844 decimal, from the  EEProm, and with a DVM reading flopping from 4.00 to 4.02V.

      X = 4.86 * 844  / 1023
      X = 4.01 V ;Hurray!

      It wouldn't hurt to read the a-d prior to Main once, and tossing it out, before reading again and storing it in EEProm.

       
    • Edward LaBudde

      Edward LaBudde - 2009-02-16

      Kent thanks for your help (yet again).

      I managed to get this first order filter code to work in two different PIC's (12F675 & 16F88).  It is for filtering an input signal:

      Regards, Ed.

      'init on power up
      set pulse off
      dim Input as word
      dim outputn as word
      dim output as word

      outputn = 0                'Intial condition
      tp = 10    'time constant in seconds (ratio of tp/dt inthis case tp=1 dt=.1sec)

      ready:                    'Waiting for inputs
      if trig on then    'must keep pulse on
      set indicator on
      gosub FirstLag
      end if
      wait 1 ms        'set sample rate to 1000Hz
      goto ready

      sub FirstLag 'reads input and computs output (set to +5V)
      do
      Input = readad10(an0)    'get new data
      output = (input-outputn)/tp + outputn 'compute output
      outputn = output    'set n-1 value of output
      wait 100 ms    'set sample rate = dt
      'diagnostic
      if output >= 646 then set pulse on '1-e^-1 for a step input

      end sub

       
    • Keith Renecle

      Keith Renecle - 2009-02-17

      Bingo! Thanks so much to you guys for the help. I really appreciate it. I had a similar idea to "anonymous" (you should tell us your name) but did not know how to peek into the a/d registers. I used your program and just changed the LED output to suit my board's wiring. I tried various numbers to see how the AD was working and it works with the full range of the pot.

      However......when I looked into the eeprom, then it only shows the low bytes...as before. So I tried putting a delay before the write eeprom function as you can see below:

      if num > 511 then set GPIO.5 on 'you can connect a led to GPIO.1 to have feedback
      if num < 511 then set GPIO.5 off 'Don't worry about num_H GCBasic does the work

      wait 90 ms 'I added this and then EPWrite shows full number

      EPWrite (0, num_H) 
      EPWrite (1, num) 

      Goto CheckAD 

      This worked fine, so I now see that it is nothing to do with the way that I'm reading the A/D, it means that writing to the eeprom needs more time than my loop is giving it. I also tried jumping out of the loop with one of the pushbuttons, and writing to the eeprom this way. This also works perfectly. This is so great, and now I can get on with my project.

      Thanks again Kent for your regular help and for clearing up the math. This makes perfect sense to me now.

      To Edward..........humble apologies for highjacking your thread! I hope that some of this helped you as well. Keep well.

      Keith R

       
    • kent_twt4

      kent_twt4 - 2009-02-17

      ED, Haven't done much digital filtering, although it would be useful for sure.  Seems like the algorithm will do the trick, although the initial offset seems large, and takes a long while to get back to a mean?  Haven't had time for a full study, or try.

      Keith, can't argue with success, or being happy with an outcome.  The extra wait state for EEPRom writes still seems unecessary.  Now that you have tried anonymous's code, and you still have an unnecessary wait period, may suggest some corrupting hardware or setup problem.  It's a mystery.

      Using AN0 with the 10k pot, the very first EEProm write/read can "sometimes" give an erroneous (and usually low) result on initial startup.  Using PWRTE=ON in config, is a definite benefit.  One set of readings with a quick power on, power off, and no PWRTE, might look like:
      00    03    AC    03    E1    03    E1    03    E1    03    E1    03    E1    03    E1    03    E1
      10    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF
      20    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF    FF
      ...
      ...
      ...
      Below is my last shot at trying to give an example, no external wait states.

      #chip 12f675,4
      #config  _INTRC_OSC_NOCLKOUT '& _PWRTE_ON
      dir GPIO.0 in 'Analog input from 10k pot connected to VDD 
      dir GPIO.1 out 'Set up output for led
      dir GPIO.4 in 'Analog input of 5k or less
      dim Volt as word
              '#include <a-d_AVR.h>

      EEPromCount = 0
      Start:
      Volt = ReadAD10(AN0) ;toggle between AN0 and AN3
      'Volt = ReadAD10(AN3) ;to see the effect of less impedance
      EPWrite(EEPromCount, Volt_H) ;lpc devices have byte size EEProm addr's
      EEPromCount += 1 'increment counter/address 
      EPWrite(EEPromCount, Volt)
      If EEPromCount = 15 Then goto blink ;Read 16 word values
      EEPromCount += 1 'increment counter/address 
      goto Start

      blink:
      Do Loop
      Set GPIO.1 On
      wait 1 s
      Set GPIO.1 Off
      wait 1 s
      nop
      Loop 

       
    • Keith Renecle

      Keith Renecle - 2009-02-17

      Thanks again Kent, I'll keep on playing with this thing, and I'll try your example as well. The pot that's on my board right now, is a 1K pot and this feeds AD0 via a 1K resistor. So far it works the same with the 10k, 5k, and 1k pots that I had. Maybe you are right, and there is some hardware hassle somewhere, but right now, I can at least carry with my model motor control project.

      A friend of mine in Slovakia has his system working now that adds power on the uphills and backs off on the downhills. Remember that these are control-line aerobatic models, and we are not allowed to use any remote control of the throttle. He uses a model gyro and/or accelerometer to do the g-force sensing. He is an old hand at the PIC stuff, and mainly uses C to program, but I'm certain that I can do most of what I need in GCBasic. So far, I have amazed myself with what I have learned in such a short space of time....as a non-programmer. GCBasic has done this for me. I am really grateful to you guys.

      Keith R

       
    • Edward LaBudde

      Edward LaBudde - 2009-02-17

      Kent, This filter is identical to an r-c filter.  The initial condition is equivalent to the starting charge on the capacitor.  So you are correct it does take time to reach the mean.  That is how it filters out high freqency effects.

      Now that I have "mastered" the a-d command, I will work on something more useful: a PID controller.  It will not be much more complex, but then I will have to learn how to use the PWM stuff.

      I LOVE this stuff!  Hugh has done a really great job.  I really appreciate all you help.

      Regards, Ed.

       
    • Santiago

      Santiago - 2009-02-17

      Hello Kent, Keith and Ed...

      I'm anonymus... just too lazy to sign-up...  :)

      Keith:
      I'm still unsure about the problem with adc and eeprom.
      You tried with "adc manual configuration" in my code and the led is working as expected..
      but... have yo tried ReadAD10(AN0) function with the led feedback and different trigger values?... if you could do it and tell us we can be totally sure about this issue.

      It could be good when you exit the program by an external switch or save eeprom by an external switch.. or something like that, to be sure the eeprom write is not breaked just when a write operation is taking place.

      You can try the following code with a write-eeprom function that should work for 12f675, if this code doesn't work properly without any delay then is very possible that there is a harware issue involved in the problem:

      '******************************************************************************
      '******************************************************************************

      #chip 12F675, 4 
      #config Osc = Int 

      dir GPIO out 'Needed to attach the led
      dir GPIO.0 in 

      dim num as word 

      'Configure ADC to read channel 0 (10 bits) 4 MHz clock:
      ANSEL = b'01010001
      ADCON0 = b'10000001'

      wait 1 ms 'As this delay is outside the main loop it can be very long (just 20 us needed)

      CheckAD: 

      set ADCON0.1 on '...................Start conversion

      conv:
      if ADCON0.1 on then goto conv '...Wait for conversion finished

      num = ADRESL
      num_H = ADRESH

      if num > 511 then set GPIO.1 on 'you can connect a led to GPIO.1 to have feedback
      if num < 511 then set GPIO.1 off 'Don't worry about num_H GCBasic does the work

      my_EPWrite (0, num_H)
      my_EPWrite (1, num)

      Goto CheckAD

      '_____ my_EPWrite subroutine _________________________________________________

      Sub my_EPWrite(epadr, value)
          EEADR =epadr
          EEDAT = value
          set EECON1.WREN on
          EECON2 = 85
          EECON2 = 170
          set EECON1.WR on
      thisisaLoop1:
          if EECON1.WR on then goto thisisaLoop1
          set EECON1.WREN off
      End Sub

      '******************************************************************************
      '******************************************************************************

      Ed:
      Just a thought... in this line:

      output = (input-outputn)/tp + outputn 'compute output

      Whta's the matter when input < outputn?
      I think "word" is an unsiged variable, then -1=65536, -2=65535, -3=65534....

      Interesting this filter, i'm managing some adc reads and need something like this... but i don't totally understand yet how it works... what  i was doing is just: read=(read+previous_read+2ºprevious_read....+nºprevious_read1)/n; but your method looks simple... i will use it... when i can understand how it works .... :)

      Greetings...

       
    • Santiago

      Santiago - 2009-02-17

      Keith:

      It could be great when we can be sure that ReadAD10 function is working properly.
      When i check the asm code generated by GCBasic i think it should not work properly because ANSEL register is not correctly set; but may be there are things i cannot see and i would like to know what's really happening...

      I have not any 16f675 to try and cannot simulate that PIC.

      Checking the ReadAD10 function with the led system is a try but is not totally clear.
      The only thing that is totally clear is having a look to the ANSEL register... then i think that when you can be sure eeprom write is working properly you can add this line to your code (using ReadAD10 function):

      EPWrite (2, ANSEL)

      this way we can know what is really happening inside the PIC...

      Good luck with your proyects!!

       
    • Santiago

      Santiago - 2009-02-18

      Sorry... forget the idea of:

      EPWrite (2, ANSEL)

      It has no sense, when the ReadAD10 function is finished, ANSEL register is set to 0...

       
    • Keith Renecle

      Keith Renecle - 2009-02-18

      Hi Santiago,
      Thanks for giving us your name and registering. Thanks also for the extra suggestions. I did try the program with ReadAD10, and it works properly on the 12F675 and 16F690 as well. At the moment your suggestions work well for my program, and most of the time I don't have to write to the eeprom in my main loop of 20 mS to keep the motor running, so it's no problem.

      When I see your's and Kent's programs, then I realise just how much I need to learn. All I need now is more time......!!

      Keith R

       
    • Edward LaBudde

      Edward LaBudde - 2009-02-22

      Hi all, here is a patch to the lag filter to correct the sign problem discussed in the PID thread.
      This works both directions.  Try to keep the ratio of tp/dt over 10, it helps stability.

      Regards, Ed.

      'A first order lag with PWM output
      'Tested 02-22-09

      'Chip model
      #chip 16F88, 8
      #config INTRC_IO

      'Set the pin directions
      dir portA.0 in    'input test signal pin #17 (an0)
      dir portB.4 out    'output testsignal pin #10
      dir portB.0 out  'set pwm output pin 6

      'name I/O
             
      #define pulse portB.4   

      'init on power up
      set pulse off
      dim Input as word
      dim outputn as word
      dim output as word
      dim PWMDC as word

      outputn = 0        'Initial condition
      PWMDC = 0        'Initial condition
      tp = 10            'time constant = tp in seconds (ratio of tp/dt )

      FirstLag:         'reads input and computes output
      Input = readad10(an0)    'get new data
      If input >= outputn then
          output = (input-outputn)/tp + outputn 'compute output
      end if
      if input < output then
          output = outputn - (outputn - input)/tp
      end if
      outputn = output    'set n-1 value of output

      PWMon                'Turn PWM on so we can see the internal calulations
      PWMDC = output/4    'scale PWM
      HPWM  1, 10, PWMDC    'output PWM
      wait 100 ms            'set sample rate = dt
      goto firstlag

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.