A2D question


Closed Thread
Results 1 to 11 of 11

Thread: A2D question

  1. #1
    Join Date
    Jul 2010
    Posts
    10

    Default A2D question

    I am working on what I thought was a simple PIC project and I need some help.

    What I need to do is an Analog to digital conversion on an 0-5v signal on RA0 and then put the result in a 4 byte array so that I can send the data to a serial port.

    I have used the example for USART and have that working, so I can send data to the serial port ok. I just need to do the A2D conversion and convert to characters I can transmit
    IM using an PIC 16F876.

    Thanks in Advance!

    Dave

  2. #2
    Join Date
    Dec 2005
    Location
    Salt Lake City, Ut, USA
    Posts
    108


    Did you find this post helpful? Yes | No

    Default

    Hey Dave,

    I don't know if I can help, but my project is basically doing that now... I think the more experienced gurus on the forum are going to request your code so far. Post that, and you'll have tons of help.

    Chris

  3. #3
    Join Date
    Jul 2010
    Posts
    10


    Did you find this post helpful? Yes | No

    Default Here is my code.

    Here is my code, feel free to offer suggestions or modifications.

    Code:
    ' Read and write hardware USART
    
    B1      var     byte
    Done    var     byte
    TxBuf   var     byte[3]
    STX     var     byte
    ETX     var     byte
    Period  var     byte
    i       var     byte
    tmpval var     byte
    ' Initialize USART
            TRISC = %10111111       ' Set TX (PortC.6) to out, rest in
            SPBRG = 25              ' Set baud rate to 2400
            RCSTA = %10010000       ' Enable serial port and continuous receive
            TXSTA = %00100000       ' Enable transmit and asynchronous mode
    
    ' Define ADCIN parameters
    Define    ADC_BITS    10         ' Set number of bits in result
    Define    ADC_CLOCK    3         ' Set clock source (3=rc)
    Define    ADC_SAMPLEUS    50     ' Set sampling time in uS
    
    adval    var    word        ' Create adval to store result
    
    
        TRISA = %11111111    ' Set PORTA to all input
        ADCON1 = %10000010    ' Set PORTA analog and right justify result
        Pause 500        ' Wait .5 second
    
    
    ' Echo received characters in infinite loop
    STX = 2
    ETX = 3
    Period = 46
    TxBuf[1] = 51
    TxBuf[2] = 54
    TxBuf[3] = 56
    mainloop: 
            ADCIN 0, adval    ' Read channel 0 to adval
    'basicaly here i want to convert advar into 3 ascii numbers
    'representing advar
    'So a result like 936 would put 
    '57 in txbuf[1] 
    '51 in txbuf[2]
    '54 in txbuf[3]
    'Then call the serial output routine which adds a stx char, 2 digits
    'a period then the last digit followed by an ETX char
            Gosub StringOut         ' Send character to serial output
            pause 500               ' Wait half second
            Goto mainloop           ' Do it forever
    
    
    ' Subroutine to get a character from USART receiver
    charin: B1 = 0                  ' Preset to no character received
    
            If PIR1.5 = 1 Then      ' If receive flag then...
                    B1 = RCREG      ' ...get received character to B1
            Endif
    
    ciret:  Return                  ' Go back to caller
    
    
    ' Subroutine to send a character to USART transmitter
    charout: If PIR1.4 = 0 Then charout     ' Wait for transmit register empty
                   
            TXREG = B1              ' Send character to transmit register
           done = 1
            Return                  ' Go back to caller
    ' Subroutine to send a character string to USART transmitter
    'First Send STX (02)  then 2 digits, then period (46), then 1 digit, then ETX (03)
    StringOut: If PIR1.4 = 0 Then StringOut     ' Wait for transmit register empty
           done = 1
                   
           TXREG = STX              ' Send character to transmit register
           while PIR1.4 = 0
           wend
           for i = 1 to 2
               TXREG = TxBuf[i]              ' Send character to transmit register
               while PIR1.4 = 0
               wend
           next i
           TXREG = Period              ' Send character to transmit register
           while PIR1.4 = 0
           wend
           TXREG = TxBuf[3]              ' Send character to transmit register
           while PIR1.4 = 0
           wend
           TXREG = ETX              ' Send character to transmit register
           while PIR1.4 = 0
           wend
        Return                  ' Go back to caller
    Attached Files Attached Files
    Last edited by ScaleRobotics; - 24th July 2010 at 03:22. Reason: added code tags

  4. #4
    Join Date
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924


    Did you find this post helpful? Yes | No

    Default

    Put your code in code tags and post it. Not going to risk or take the time to download and open a ZIP when a ZIP is not needed.

    put the result in a 4 byte array
    This chip only has a 10 bit resolution so you need to explain what you are after. The ADC result can be sent serially with out an array of ant type...

    Here is a sample to read the ADC at an 8 bit resolution. Maybe it will get you started.
    Code:
    ADCON1 = %00001110
    OUT_TEMP VAR BYTE
    
    MAIN_LOOP:
      GOSUB GET_AD
      GOTO MAIN_LOOP
    
    GET_AD:
      ADCON0=00000001
      GOSUB READ_AD
      OUT_TEMP = ADRESH
      RETURN
      
      READ_AD:
      PAUSE 50
      ADCON0.2=1
      WHILE ADCON0.2=1:WEND
      RETURN
    Dave
    Always wear safety glasses while programming.

  5. #5
    Join Date
    Nov 2003
    Location
    Wellton, U.S.A.
    Posts
    5,924


    Did you find this post helpful? Yes | No

    Default

    Code:
        txbuf[1] = advar / 1000  
        txbuf[2] = (advar - txbuf[1] * 1000) /100  
        txbuf[3] = (advar-((txbuf[1] * 1000) + (txbuf[2] * 100)))/10  
        txbuf[4] = advar - ((txbuf[1] * 1000) + (txbuf[2] * 100)+ txbuf[3] * 10)
    Dave
    Always wear safety glasses while programming.

  6. #6
    Join Date
    May 2008
    Location
    Italy
    Posts
    825


    Did you find this post helpful? Yes | No

    Default


    TxBuf var byte[3]

    'basicaly here i want to convert advar into 3 ascii numbers
    'representing advar
    'So a result like 936 would put
    '57 in txbuf[1]
    '51 in txbuf[2]
    '54 in txbuf[3]
    'Then call the serial output routine which adds a stx char, 2 digits
    'a period then the last digit followed by an ETX char
    Dave, with referece to your code please note that when you declare an array, the number you state is the real number of elements of your array. you stated 3 elements, so you will have the following bytes available:

    txbuf[0]
    txbuf[1]
    txbuf[2]

    Now since you are decoding a 10bits adc then the maximum reading you can obtain in adval is 1023, which are four digits so you will need a 4 bytes array for your data transfer.
    Hence, you have to declare:

    txbuf var byte [4]

    and you will have the following bytes available:

    txbuf[0]
    txbuf[1]
    txbuf[2]
    txbuf[3]

    Please read page 33 of PBP manual, you will find the DIG instruction that could help you in moving the single digits into your array. Here a snippet as an example:

    Code:
    A  var byte   ' used for the FOR/NEXT loop
    
    For A=0 to 3
    txbuf[A]= adval DIG A
    next A
    
    'assuming adval contains the value 1023 then your array will end up as follows:
    
    'txbuf[0]="3"
    'txbuf[1]="2"
    'txbuf[2]="0"
    'txbuf[3]="1"
    
    In case you want them the other way then
    
    For A=0 to 3
    txbuf[A]= adval DIG (3-A)
    next A
    
    
    'will yield:
    
    'txbuf[0]="1"
    'txbuf[1]="0"
    'txbuf[2]="2"
    'txbuf[3]="3"
    Al.
    Last edited by aratti; - 24th July 2010 at 15:05.
    All progress began with an idea

  7. #7
    Join Date
    Jul 2010
    Posts
    10


    Did you find this post helpful? Yes | No

    Default

    Thanks Everyone for the input! I'm now able to read values from my sensor. I now have 2 additional questions.

    1. Is there a better way to send serial; data than the way I'm doing it? Anyone have a routine that they think works better?

    2. It seems like my returned values vary quite a bit. I don't have access to a scope, but it seems that the sensor is returning pretty constant voltage. it returns 0 - 10 v I am using a voltage divider made up of 2 2.2 K resistors to shift the sensor output to 0 - 5 volts. Any hints on making the system more stable? Slow down the conversion time? My requirements are pretty easy, i need to read the sensor no more than twice a second.

    Thanks again for everyone's help!

    Dave

  8. #8
    Join Date
    May 2008
    Location
    Italy
    Posts
    825


    Did you find this post helpful? Yes | No

    Default

    1. Is there a better way to send serial; data than the way I'm doing it? Anyone have a routine that they think works better?
    Yes, use HSEROUT.

    HSEROUT[STR txbuf \ 4] , will send your array out at the baud rate choosen in your define.

    See page 79 - 80 of PBP manual.

    2. It seems like my returned values vary quite a bit. I don't have access to a scope, but it seems that the sensor is returning pretty constant voltage. it returns 0 - 10 v I am using a voltage divider made up of 2 2.2 K resistors to shift the sensor output to 0 - 5 volts. Any hints on making the system more stable? Slow down the conversion time? My requirements are pretty easy, i need to read the sensor no more than twice a second.
    Read the thread at the given link, you will find the technique and snippets to keep your adc reading stable.

    www.picbasic.co.uk/forum/showthread.php?t=6734


    Al.
    Last edited by aratti; - 25th July 2010 at 09:00.
    All progress began with an idea

  9. #9
    Join Date
    Sep 2007
    Location
    USA, CA
    Posts
    271


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by dbodenheimer View Post
    1. Is there a better way to send serial; data than the way I'm doing it? Anyone have a routine that they think works better?
    For certain, Al's method is the preferred way if you are going to send ascii. However, in most situations you can send the actual data instead of the ascii representation of it. Doing so makes it MUCH faster and MUCH smaller code, because you are sending half the data and doing do it without ascii conversions.

    Instead of
    dim TxBuf[4] as byte 'var declaration
    HSEROUT[STR txbuf \ 4] 'sending data

    dim TxBuf as word 'new var declaration
    HSEROUT[TxBuf] 'new sending data

    now your pic will send two bytes, low byte first.

    Side Note: As a personal preference, I like to make the first letter of a variable the first letter of the type. So I would make it wTxBuf, since it is a word. This makes it a lot easier to find type mismatch errors.

  10. #10
    Join Date
    Jul 2010
    Posts
    10


    Did you find this post helpful? Yes | No

    Default

    Want to thank everyone for their help on this! I'm posting my code as of right now for review and comments.

    Al, Even with the multiple collections, sorting and averaging routines put in, I'm still getting a wider variance of data than I think I should ]. Do I have the code right? If so, could my voltage divider be the wrong value?

    Also, I tried to increase the baudrate to 9600 and it seemed to stop transmitting, does my serial setup code look OK? I am using a 4 mhz crystal.

    Thanks again Everyone!

    Dave
    Code:
    ' Read and write hardware USART
    
    B1      var     byte
    Done    var     byte
    TxBuf   var     byte[3]
    SendBuf var     byte[6]
    STX     var     byte
    ETX     var     byte
    Period  var     byte
    i       var     byte
    tmpval var     byte
    A       var     byte        'for for next loop
    DatAvg  var     word
        CounterA var Word
        DataA var Word
        RawData var Word [16]
    
    
    ' Initialize USART
    
            TRISC = %10111111       ' Set TX (PortC.6) to out, rest in
            ' Set receive register to receiver enabled
            DEFINE HSER_RCSTA 90h
            ' Set transmit register to transmitter enabled
            DEFINE HSER_TXSTA 20h
            ' Set baud rate
            DEFINE HSER_BAUD 2400
            DEFINE HSER_SPBRG 25 'Hser spbrg init 
    
    ' Define ADCIN parameters
    Define	ADC_BITS	10	     ' Set number of bits in result
    Define	ADC_CLOCK	3	     ' Set clock source (3=rc)
    Define	ADC_SAMPLEUS	50	 ' Set sampling time in uS
    
    adval	var	word		' Create adval to store result
    
    
    	TRISA = %11111111	' Set PORTA to all input
    	ADCON1 = %10000010	' Set PORTA analog and right justify result
    	Pause 500		' Wait .5 second
    
    
    ' Echo received characters in infinite loop
    STX = 2
    ETX = 3
    Period = 46
    TxBuf[1] = 51
    TxBuf[2] = 54
    TxBuf[3] = 56
    mainloop: 
    'Collect 17 AD samples
    for A = 0 to 16
            ADCIN 0, RawData[A] 	' Read channel 0 to array
    Next A
    'Now Lets sort the array
    Gosub SortArray
    'Now Sum the middle 8 values
    for A = 4 to 11                    ' pick out middle 8 readings
     DatAvg = DatAvg + RawData[A]
    NEXT A
    'Now Divide by 8 (by shifting) too get an average
    DatAvg = DatAvg >>3
    'Now put data in TxBuf
            For A=0 to 3
                txbuf[A]= DatAvg DIG (3-A)
            next A
            for A = 0 to 3
                TxBuf[A] = TxBuf[A] + 48
            next  A
    'Send it!
            Gosub SendString         ' Send character to serial output
            pause 500               ' Wait half second
            Goto mainloop           ' Do it forever
    
            '
            '    Sort Array
            '    ----------
    SortArray:
        CounterA=0
    SortLoop:
        If RawData(CounterA+1) < RawData(CounterA) then
            DataA=RawData(CounterA)
            RawData(CounterA)=RawData(CounterA+1)
            RawData(CounterA+1+0)=DataA
            If CounterA > 0 then CounterA=CounterA-2
            endif
        CounterA=CounterA+1
        If CounterA < 15 then goto SortLoop
    Return
    ' Subroutine to send a character string to USART transmitter
    'First Send STX (02)  then 2 digits, then period (46), then 1 digit, then ETX (03)
    SendString:
        'Build Buffer
        SendBuf[0] = STX
        SendBuf[1] = TxBuf[0]
        SendBuf[2] = TxBuf[1]
        SendBuf[3] = TxBuf[2]
        SendBuf[4] = Period
        SendBuf[5] = TxBuf[3]
        SendBuf[6] = ETX
        'Now Send it
           HSEROUT[STR SendBuf \ 7] 
        
    Return                  ' Go back to caller

  11. #11
    Join Date
    May 2008
    Location
    Italy
    Posts
    825


    Did you find this post helpful? Yes | No

    Default

    Code:
    ' Read and write hardware USART
    
    B1      var     byte
    Done    var     byte
    TxBuf   var     byte[3]
    SendBuf var     byte[6]
    STX     var     byte
    ETX     var     byte
    Period  var     byte
    i       var     byte
    tmpval var     byte
    A       var     byte        'for for next loop
    DatAvg  var     word
        CounterA var Word
        DataA var Word
        RawData var Word [16]
    
    
    
    ' Initialize USART
    
            TRISC = %10111111       ' Set TX (PortC.6) to out, rest in
            ' Set receive register to receiver enabled
            DEFINE HSER_RCSTA 90h
            ' Set transmit register to transmitter enabled
            DEFINE HSER_TXSTA 20h
            ' Set baud rate
            DEFINE HSER_BAUD 2400
            DEFINE HSER_SPBRG 25 'Hser spbrg init 
    
    ' Define ADCIN parameters
    Define	ADC_BITS	10	     ' Set number of bits in result
    Define	ADC_CLOCK	1	     ' Set clock source to 1.6 us Tad @ Fosc/8 (xtal = 4 MHz)
    Define	ADC_SAMPLEUS	50	 ' Set sampling time in uS
    
    adval	var	word		' Create adval to store result
    
    
    	TRISA = %11111111	' Set PORTA to all input
    	ADCON1 = %10000010	' Set PORTA analog and right justify result
    	Pause 500		' Wait .5 second
    
    
    ' Echo received characters in infinite loop
    STX = 2
    ETX = 3
    Period = 46
    TxBuf[1] = 51
    TxBuf[2] = 54
    TxBuf[3] = 56
    mainloop: 
    'Collect 17 AD samples
    for A = 0 to 15
            ADCIN 0, RawData[A] 	' Read channel 0 to array
    Next A
    'Now Lets sort the array
    Gosub SortArray
    'Now Sum the middle 8 values
    
    DatAvg = 0  ' set DatAvg to zero
    
    for A = 4 to 11                    ' pick out middle 8 readings
     DatAvg = DatAvg + RawData[A]
    NEXT A
    'Now Divide by 8 (by shifting) too get an average
    DatAvg = DatAvg >>3
    'Now put data in TxBuf
            For A=0 to 3
                txbuf[A]= DatAvg DIG (3-A)
            next A
            for A = 0 to 3
                TxBuf[A] = TxBuf[A] + 48
            next  A
    'Send it!
            Gosub SendString         ' Send character to serial output
            pause 500               ' Wait half second
            Goto mainloop           ' Do it forever
    
            '
            '    Sort Array
            '    ----------
    SortArray:
        CounterA=0
    SortLoop:
        If RawData(CounterA+1) < RawData(CounterA) then
            DataA=RawData(CounterA)
            RawData(CounterA)=RawData(CounterA+1)
            RawData(CounterA+1+0)=DataA
            If CounterA > 0 then CounterA=CounterA-2
            endif
        CounterA=CounterA+1
        If CounterA < 15 then goto SortLoop
    Return
    ' Subroutine to send a character string to USART transmitter
    'First Send STX (02)  then 2 digits, then period (46), then 1 digit, then ETX (03)
    SendString:
        'Build Buffer
        SendBuf[0] = STX
        SendBuf[1] = TxBuf[0]
        SendBuf[2] = TxBuf[1]
        SendBuf[3] = TxBuf[2]
        SendBuf[4] = Period
        SendBuf[5] = TxBuf[3]
        SendBuf[6] = ETX
        'Now Send it
           HSEROUT[STR SendBuf \ 7] 
        
    Return                  ' Go back to caller
    I found three errors in your code (corrected in red) .

    The ADC clock source must be set the closesest possible to 1.6 us Tad.

    Very likely the fact you didn't reset DatAvg to zero was responsible for the non stable reading.

    As far as the baud rate is concerned you can use 4800 as the maximum baud rate with your 4 MHz oscillator.

    Tray and see you should have rock stable reading now, good luck.

    Al.
    Last edited by aratti; - 26th July 2010 at 07:30.
    All progress began with an idea

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts