1. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,515
    784
    Hi.

    I got stuck and maybe blind. I have an LED connected to RA2, and a POT connected to RC3/AN7. The idea is that the LED will flash at different rates according the to ADC reading.

    Code ( (Unknown Language)):
    1.  
    2. // ADC test program
    3.  
    4. #include <htc.h>
    5.  
    6. #define _XTAL_FREQ 4000000
    7. #define led RA2
    8.  
    9. unsigned int adc_raw;
    10.  
    11. // Configuration
    12. __CONFIG(FOSC_XT &      // Crystal/resonator on RA4 & RA5
    13. WDTE_OFF &              // Watchdog timer off
    14. PWRTE_OFF &             // POwer up timer enable off
    15. MCLRE_OFF &             // MCLR pin function is digital input, MCLR internally tied to VDD
    16. CP_OFF &                // Code protection off
    17. CPD_OFF &               // Data code protection off
    18. BOREN_OFF &             // Brown out off
    19. IESO_OFF &              // Internat switchover off
    20. FCMEN_ON);              // Fail-Safe clock monitor on
    21.  
    22. void adc_init(void)
    23. {
    24. ADCON0bits.ADFM = 0;        // Left justified
    25. ADCON0bits.VCFG = 0;        // VDD as reference
    26. ADCON0bits.CHS = 0b111;         // Analog channel set to AN7
    27. ADCON0bits.ADON = 1;        // ADC is enabled
    28. ADCON1bits.ADCS = 0b001;        // ADC Conversion Clock Select bit
    29.  
    30. } // End adc_init
    31.  
    32. void adc_read(void)
    33. {
    34.  
    35. ADCON0bits.GO = 1;
    36. __delay_us(10);
    37.     while(ADCON0bits.nDONE);
    38. } // End adc_read
    39.  
    40. void main (void)
    41. {
    42. CMCON0  = 0x07;             // Turn off comparators
    43. ANSEL   = 0b00001000;       // Analog input on RC3/AN7
    44. ADCON1  = 0b01000000;       // Conversion Clock
    45.  
    46. TRISA = 0b00000000;
    47. TRISC = 0b00001000;
    48.  
    49. led = 0;
    50.  
    51. adc_init();
    52.  
    53. while (1)
    54. {
    55.     adc_read();
    56. adc_raw = ADRESH << 8;
    57. adc_raw |= ADRESL;
    58.  
    59. if (adc_raw <= 512)
    60.     {
    61.     led = 1;
    62.     __delay_ms(500);
    63.     led = 0;
    64.     __delay_ms(500);
    65.     }
    66. else
    67. {
    68.     led = 1;
    69.     __delay_ms(100);
    70.     led = 0;
    71.     __delay_ms(100);
    72. }
    73. }
    74. }
    75.    
    76.  
    When I run the code on the chip, the LED flashes at the fastest rate, regardless of the POT.

    I need some advice.
     
  2. JohnInTX

    Moderator

    Jun 26, 2012
    2,339
    1,022
    For a raw count of 512, ADRESH will be B'10000000' and ADRESHL will be B'00000000' which is 8000h. If you shift ADRESH, you lose the data and read 0000h.
     
  3. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,515
    784
    That is one of the things that confuses me. The ADRESH and ADRESL, and how to make the one number...
     
  4. JohnInTX

    Moderator

    Jun 26, 2012
    2,339
    1,022
    Right justified range:
    Each ADC count = 1
    Range is 0000h-03ffh (0-1023 - 10 bits)

    When left justified, you effectively multiply the two byte result by 2^6:
    Each ADC count = 64 (because of the implied shift resulting from the left justify)
    Range is 0000h - FFC0h

    Regardless of how you justify the number you can put it into an unsigned int by
    adc_raw = (unsigned int)ADRESH;
    adc_raw = adc_raw *256 (or <<8); //shift it up 8 bit)
    adc_raw += (unsigned int)ADRESL;

    You now have the bit pattern from ADRESH:ADRESL in the int. What its value is is determined by whether its left (result*64) or right (result*1) justified. Note that the int must be unsigned for left justified because the MSbit is the sign in a signed int. Left justified ADC values more than half-scale will be negative in a signed int (because the MSbit==1).
     
    nerdegutta likes this.
  5. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Shouldn't the ADFM bit be set to '1' for right justification?

    I ended up borrowing the sequence used in the library code for a couple different high level languages. Those functions turn the ADC module on before reading, wait for acquisition, start the conversion, turn the ADC module off, then copy the ADC result. Here's a snippet from a 16F688 BoostC program (below).

    Good luck on your project.

    Cheerful regards, Mike

    Code ( (Unknown Language)):
    1.  
    2.   /*                                                                *
    3.    *  initialize ADC module for AN2(RA2)                            *
    4.    *                                                                */
    5.      ansel = 0b00000100;        // RA2/AN2 analog, others digital
    6.      adcon0 = 0b10000000;       // right justified adc result
    7.      adcon1 = 0b01010000;       // Fosc/16 conversion clock
    8.  
    Code ( (Unknown Language)):
    1.  
    2.    int getadc(char channel)     // channel, 0..7
    3.    { int result;                //
    4.      adcon0.CHS0 = channel.0;   // select channel
    5.      adcon0.CHS1 = channel.1;   //   "
    6.      adcon0.CHS2 = channel.2;   //   "
    7.      adcon0.ADON = 1;           // turn ADC on
    8.      delay_us(20);              // acquisition delay
    9.      adcon0.GO_DONE = 1;        // start conversion
    10.      while(adcon0.GO_DONE);     // wait for conversion complete
    11.      adcon0.ADON = 0;           // turn ADC off
    12.      result = adresh << 8;      // collect ADC reading
    13.      result |= adresl;          //
    14.      return result;             // 0..1023
    15.    }
    16.  
     
    nerdegutta likes this.
  6. nerdegutta

    Thread Starter Moderator

    Dec 15, 2009
    2,515
    784
    Thanks a lot, guys.

    I got it working, and posting the program for others to see.

    Code ( (Unknown Language)):
    1.  
    2. // ADC test program
    3.  
    4. #include <htc.h>
    5.  
    6. #define _XTAL_FREQ 4000000
    7. #define led RA2
    8.  
    9. unsigned int adc_raw;
    10.  
    11. // Configuration
    12. __CONFIG(FOSC_XT &      // Crystal/resonator on RA4 & RA5
    13. WDTE_OFF &              // Watchdog timer off
    14. PWRTE_OFF &             // POwer up timer enable off
    15. MCLRE_OFF &             // MCLR pin function is digital input, MCLR internally tied to VDD
    16. CP_OFF &                // Code protection off
    17. CPD_OFF &               // Data code protection off
    18. BOREN_OFF &             // Brown out off
    19. IESO_OFF &              // Internat switchover off
    20. FCMEN_ON);              // Fail-Safe clock monitor on
    21.  
    22. // Functions
    23. void adc_init(void)
    24. {
    25. ADCON0bits.ADFM = 1;        // Right justified
    26. ADCON0bits.VCFG = 0;        // VDD as reference
    27. ADCON0bits.CHS = 0b111;     // Analog channel set to AN7
    28. ADCON0bits.ADON = 1;        // ADC is enabled
    29. ADCON1bits.ADCS = 0b001;    // ADC Conversion Clock Select bit
    30. } // End adc_init
    31.  
    32. void adc_read(void)
    33. {
    34.     ADCON0bits.GO = 1;
    35.     __delay_us(10);
    36.     while(ADCON0bits.nDONE);
    37. } // End adc_read
    38.  
    39. // Main program
    40. void main (void)
    41. {
    42. CMCON0  = 0x07;             // Turn off comparators
    43. ANSEL   = 0b00001000;       // Analog input on RC3/AN7
    44.  
    45. TRISA = 0b00000000;
    46. TRISC = 0b00001000;
    47.  
    48. led = 0;
    49.  
    50. adc_init();
    51.  
    52. while (1)
    53. {
    54.     adc_read();
    55.     adc_raw = (unsigned int) ADRESH;
    56.     adc_raw = adc_raw*256;
    57.     adc_raw += (unsigned int) ADRESL;
    58.  
    59. if (adc_raw <= 512)
    60.     {
    61.     led = 1;
    62.     __delay_ms(500);
    63.     led = 0;
    64.     __delay_ms(500);
    65.     }
    66. else
    67. {
    68.     led = 1;
    69.     __delay_ms(100);
    70.     led = 0;
    71.     __delay_ms(100);
    72. }
    73. }
    74. }
    75.    
    76.  
    77.  
    Have a wonderful Saturday evening. (I'm wondering if the Saturday Nite Live show from Fort Lauderdale is sending tonight?)
     
  7. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    First Hi-Tech C is Little-endian. In a Little-endian system. A two byte variable like a typical ADC result the First byte (lowest address) will hold the least significant byte. So set the ADC result byte order correct. Second if you look at the 16f688 header file. I am quite sure that HI-Tech have defined a 16 bit variable for the ADC result. Given that ADFM bit is set to one. It should just be plug a play. I am not on a computer with HI-Tech installed so I can not help more than this. But if you are in doubt you can post a snippet of your PIC header file.
    The common way to join bytes to say an int or long. Is to use the Union Declaration. I can see you have solved your problem. But it is kind of cycle wasting ;)
     
  8. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Sorry I was somewhat wrong here. Have not worked much with PIC16F lately and forgot that the ADRES registers in most 16F are NOT consecutive Like in the 18F series. They are most often placed different banks. So coding like this make no sense
    Code ( (Unknown Language)):
    1. volatile unsigned short ADRES @ 0x09E;
    So we are left with the union way joining the the two ADRES register to one variable. This is the least cycle consuming way of doing it. I post my code here
    Code ( (Unknown Language)):
    1. // ADC test program
    2. #include <htc.h>
    3. #define _XTAL_FREQ 4000000
    4. #define led RA2
    5. union {unsigned short ADRES;
    6.             char ad_hi_low[2];
    7.           } ad_data;
    8.  
    9. // Configuration
    10. __CONFIG(FOSC_XT &  // Crystal/resonator on RA4 & RA5
    11. WDTE_OFF &    // Watchdog timer off
    12. PWRTE_OFF &    // POwer up timer enable off
    13. MCLRE_OFF &    // MCLR pin function is digital input, MCLR internally tied to VDD
    14. CP_OFF &    // Code protection off
    15. CPD_OFF &    // Data code protection off
    16. BOREN_OFF &    // Brown out off
    17. IESO_OFF &     // Internat switchover off
    18. FCMEN_ON);    // Fail-Safe clock monitor on
    19. void adc_init(void)
    20. {
    21. ADCON0bits.ADFM = 1;  // Right justified!!!!!
    22. ADCON0bits.VCFG = 0;  // VDD as reference
    23. ADCON0bits.CHS = 0b111;   // Analog channel set to AN7
    24. ADCON0bits.ADON = 1;  // ADC is enabled
    25. ADCON1bits.ADCS = 0b001;  // ADC Conversion Clock Select bit
    26. } // End adc_init
    27. void adc_read(void)
    28. {
    29. ADCON0bits.GO = 1;
    30. __delay_us(10);
    31.  while(ADCON0bits.nDONE);
    32. } // End adc_read
    33. void main (void)
    34. {
    35. CMCON0 = 0x07;    // Turn off comparators
    36. ANSEL = 0b00001000;  // Analog input on RC3/AN7
    37. ADCON1 = 0b01000000;  // Conversion Clock
    38. TRISA = 0b00000000;
    39. TRISC = 0b00001000;
    40. led = 0;
    41. adc_init();
    42. while (1)
    43. {
    44.  adc_read();
    45.   ad_data.ad_hi_low[0]=ADRESL;
    46.  ad_data.ad_hi_low[1]=ADRESH;
    47. if ( ad_data.ADRES <= 512)
    48.  {
    49.  led = 1;
    50.  __delay_ms(500);
    51.  led = 0;
    52.  __delay_ms(500);
    53.  }
    54. else
    55. {
    56.  led = 1;
    57.  __delay_ms(100);
    58.  led = 0;
    59.  __delay_ms(100);
    60. }
    61. }
    62. }
     
    nerdegutta likes this.
Loading...