Connect with us

Getting value of ADRESH out of a pic μcu?

Discussion in 'Microcontrollers, Programming and IoT' started by chopnhack, Jun 4, 2016.

Scroll to continue with content
  1. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Can I ask for some assistance in how to get the value of ADRESH out of a pic12f675? It is a single port 8 pin chip and I would like to read the contents into a variable so that I can do operations on/with it. I am using AN1 as my analog input from a potentiometer.

    Thanks in advance.
     
  2. Arouse1973

    Arouse1973 Adam

    5,164
    1,081
    Dec 18, 2013
    Don't know if this is of any use John. Found an example of a volt meter, you might be able to pick the bits out you want.
    Adam

    Code:
    1 // Voltage.c, DW Smith, 1st December 2011
    2 #include < p18f1220. h >
    3 #pragma config WDT = OFF, OSC = INTIO2, PWRT = ON, LVP = OFF, MCLRE = OFF
    4 #include < delays.h >
    5
    6 int READING;
    7 float VOLTAGE; // Voltage is a decimal number not an integer.
    8
    9 void main (void)
    10 {
    11 // SET UP
    12 // OSCCON defaults to 31 kHz. So no need to alter it.
    13 ADCON1 = 0x7E; // AN0 is analogue or 0b01111110 in binary
    14 TRISA = 0b11111111; // sets PORTA as all inputs, bit0 is AN0
    15 PORTA = 0b00000000; // turns off PORTA outputs, not required, no outputs
    16 TRISB = 0b00000000; // sets PORTB as all outputs
    17 PORTB = 0b00000000; // turns off PORTB outputs,
    good start position
    18 ADCON0bits.ADON = 1; // turn on A/ D
    19 ADCON2 = 0b10000000; // right justified, acquisition times are ok at 0 with 31 kHz
    20
    21 while (1)
    22 {
    23 ADCON0bits.GO_DONE = 1; // do A/ D measurement
    24 while (ADCON0bits.GO_DONE = = 1); // wait until bit = 0 measurement completed
    25 READING = ADRESL +( ADRESH * 256);
    26 VOLTAGE = READING/ 204.6;
    27
    28 if (VOLTAGE > 0 && VOLTAGE < = 1) PORTB = 0b00000000;
    29 if (VOLTAGE > 1 && VOLTAGE < = 2) PORTB = 0b00000001;
    30 if (VOLTAGE > 2 && VOLTAGE < = 3) PORTB = 0b00000011;
    31 if (VOLTAGE > 3 && VOLTAGE < = 4) PORTB = 0b00000111;
    32 if (VOLTAGE > 4 && VOLTAGE < =5) PORTB = 0b00001111;
    33 }
    34 }
    
     
    hevans1944 and chopnhack like this.
  3. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Brilliant Adam - its of much use thank you!!! It is clearly commented and not obfuscated with many function calls - very low level and simple, easy to follow along. I will see if I can put it to use later on today, thanks again for finding that :D
     
  4. Arouse1973

    Arouse1973 Adam

    5,164
    1,081
    Dec 18, 2013
    No probs!
    Adam
     
    chopnhack likes this.
  5. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Found this to be cute:

    upload_2016-6-4_17-10-18.png

    Meanwhile, it's together in the same register (ADCON0) so when you initialize the values to turn on the A/D converter and set the channel, you have to set this bit in a separate instruction code. Wonder why that is... Reasons why we RTM ;)
     
  6. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Here is what I have so far:

    Code:
    /*
    * File:   devboard.c
    *
    *
    * Created on June 2, 2015, 9:33 PM
    */
    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.
    
    // CONFIG
    #pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
    #pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
    #pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)
    #pragma config MCLRE = ON       // GP3/MCLR pin function select (GP3/MCLR pin function is MCLR)
    #pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
    #pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
    #pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <xc.h>
    
    
    #define _XTAL_FREQ 4000000
    
    
    
    int AD_IN; //variable to hold value of A/D input from potentiometer.
    
    void main (void)
    {
      // SET UP
      ADCON0 = 0b0000101; // AN1 is analogue, turning on analog channel and starting converter
      TRISIO = 0b001010;          //Only AN1 and AN3/MCLR are inputs all else outputs.
    //good start position
    ADCON0bits.ADON = 1; // turn on A/D
    ANSEL =  0b0110010;         //AN1 set to Analog, other 3 pins are digital, 011 on right side indicates FRC for timing
    
    
    while (1)
    {
        ADCON0bits.GO_DONE = 1;           // do A/ D measurement
        while (ADCON0bits.GO_DONE == 1); // wait until bit = 0 measurement completed
        {AD_IN = ADRESH;          //ADRESL +( ADRESH * 256);
        AD_IN = AD_IN/256; //
    
        if ((AD_IN > 0) && (AD_IN <=50))            //compiler ok with this if conditional the next two get flagged with various syntax issues??
            {
            GPIO = 0b000100;
            }   
      
                if ((AD_IN > 75) && (AD_IN < = 150))
                    {   
                    GPIO = 0b010000;
                    }
      
                        if ((AD_IN > 175) && (AD_IN < =255))
                         {
                            GPIO = 0b100000;
                            }
    }
    }
    
    }
    
    
    
    The example code posted by Adam looked really promising, but the XC8 compiler had a fit with it. It specifcially did not care for the if conditionals being joined on one line - like this:
    Code:
    if (VOLTAGE > 0 && VOLTAGE < = 1)
    I separated it and the compiler accepted the first instance shown above, but the copies after that all got flagged for syntax errors. I had it fixed when I tab spaced out the code, but for some reason it flagged again and I have not been able to get it to work since!! Touchy compiler..
    Any help here - I don't want to write a case/switch statement. I even started a new file, new name, etc. :mad:
     
    Last edited: Jun 5, 2016
  7. NorthGuy

    NorthGuy

    53
    16
    Mar 24, 2016
    "<=" is an operator and cannot have spaces inside.
     
    chopnhack and Arouse1973 like this.
  8. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Thank you North - syntax kills me!!d LOL
     
  9. Arouse1973

    Arouse1973 Adam

    5,164
    1,081
    Dec 18, 2013
    I didn't spot that, it appears that when pasted into word it automatically puts a space in. I'll have to watch that in future.
    Adam
     
  10. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    No worries mate, it was a good challenge to learn to spot things in code for me too!! The code works and now my dev. board responds appropriately, in this case it compares the range of the potentiometer and when the input is between:
    0.00-0.97v (000-050 in 0b) GP2 lights up
    1.46-2.87v (075-150 in 0b) GP4 lights up
    3.37-4.89v (175-255 in 0b) GP5 lights up

    I left 25 or 0.47v between ranges for clean on/off switching.
    Thanks again for that code!!

    Code:
    /*
    * File:   devboard.c
    
    *
    * Created on June 2, 2015, 9:33 PM
    */
    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.
    
    // CONFIG
    #pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
    #pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
    #pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)
    #pragma config MCLRE = ON       // GP3/MCLR pin function select (GP3/MCLR pin function is MCLR)
    #pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
    #pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
    #pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <xc.h>
    
    
    #define _XTAL_FREQ 4000000
    
    
    
    int AD_IN; //variable to hold value of A/D input from potentiometer.
    
    void main (void)
    {
      // SET UP
      ADCON0 = 0b0000101; // AN1 is analogue, turning on analog channel and starting converter
      TRISIO = 0b001010;          //Only AN1 and AN3/MCLR are inputs all else outputs.
    
    
    while (1)
    {
        //good start position
        //ADCON0bits.ADON = 1; // turn on A/D
        ANSEL =  0b0110010;         //AN1 set to Analog, other 3 pins are digital, 011 on right side indicates FRC for timing
        ADCON0bits.GO_DONE = 1;           // do A/ D measurement
      
            while (ADCON0bits.GO_DONE == 1) // wait until bit = 0 measurement completed
            {
             AD_IN = ADRESH;          //ADRESL +( ADRESH * 256); //changed value of 256 to 1024 since this chip is 10 bit
                          
                if ((AD_IN) > 0 & (AD_IN <=50))
                {
                 GPIO = 0b000100;
                }
              
      
                        if ((AD_IN > 75) && (AD_IN <= 150))
                        {
                         GPIO = 0b010000;
                        }
      
                            if ((AD_IN > 175) && (AD_IN <= 255))
                            {
                                 GPIO = 0b100000;
                            }
            }
    }
      
    
    }
    
    
     
  11. hevans1944

    hevans1944 Hop - AC8NS

    4,541
    2,116
    Jun 21, 2012
    If you right-justify the A/D converter results by setting bit 7=1 in ADCON0, you can read all ten bits with this expression:
    AD_IN = ADRESL + (ADRESH * 256).
     
    chopnhack likes this.
  12. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Thanks Hop, I am having some trouble following this logically. Please assist:

    • Changing ADCON register to 1 gives right justified result in ADRESL - ok :)
    • ADRESL contents from 0 to 7 are LSB - ok :)
    • Adding the MSB back to our variable with ADRESL contents - ok :)
    • Why are we multiplying ADRESH by 256?:confused:

    Shouldn't we be adding 256 to bump the MSB 8 bits to the left so that it is where it belongs as highest value bits? But by adding, are we not turning each bit to a value of 1 from bit 0-7? :eek: Now that would be a real mess!
    Sorry, my binary is not always that great :oops:

    I noticed that my word count was fairly high with little code in C for the pic12f675, so I believe that ASM will be a necessity again for the dust collector code. I will still toy with C to get the concept down, but the bit shifting operator will certainly be very helpful in saving ops and code space later!!

    BTW you're missing one hell of a shower down here :rolleyes:
     
  13. hevans1944

    hevans1944 Hop - AC8NS

    4,541
    2,116
    Jun 21, 2012
    I watched it on TV. You guys made the national news. Are you still dry?
    The PCB arrived in the afternoon mail! Yes, the regulator holes need to be enlarged. Will work on getting parts mounted in the coming week. The board looks great! Wish I could still do this kind of work. <sigh>

    The two bits stored in bit positions 0 and 1 of the 8-bit register ADRESH must represent the two most significant bits of a 10-bit result stored in a 16-bit unsigned integer variable, AD_IN. You need to get those two bits to transfer over to bit positions 8 and 9 in AD_IN.

    There are (at least) two ways to do this: (1) multiply the 8-bit register ADRESH by 256 (weight of bit 8) and store the result in unsigned 16-bit variable AD_IN or (2) copy ADRESH into AD_IN and then left-shit AD_IN by 8, thereby moving bit 1 of ADRESH into bit 9 position of AD_IN and moving bit 0 of ADRESH into bit 8 position of AD_IN. After you have the two bits of ADRESH in the correct bit positions of AD_IN you can either add ADRESL to the AD_IN or logically OR the contents of ADRESL with the contents of AD_IN.

    Why does multiplying by 256 result in a left-shift of ADRESH? Well, multiplying by 1 doesn't do anything. Multiplying by 2 is the same as a left-shift of all the bits by one bit position. Multiply by 4, left shift everything two bit positions. Multiple by 8, left shift three bit positions. X16 --> shift left 4 bit positions. X32 --> shift left 5 bit positions. X64 --> shift left 6 bit positions. X128 --> shift left 7 bit positions. X256 --> shift left 8 bit positions. If you haven't extended the 8-bit register to 16 bits, then shifting left by 8 or multiplying by 256 will yield a zero result, assuming zeroes are shifted in from the right and arithmetic overflow during multiplication isn't flagged as a run-time error.

    So bit 1 in ADRESH shifts over to bit 9 in AD_IN and bit 0 in ADRESH shifts over to bit 8 in AD_IN. After adding or ORing ADRESL with AD_IN, bits 0 through 9 of AD_IN contain the 10-bit result of the A/D conversion.

    I don't remember all the rules associated with mixed byte and word arithmetic in C, but if you just copy ADRESH into AD_IN first, before doing the multiplication or left-shifting, it should work.

    Multiplying an 8-bit byte by 256, or left-shifting that byte by 8 bit positions, without extending the byte to a 16-bit result will result in either zero results or a run-time error. Shifting is usually a faster operation than multiplying. So maybe a construct like this will work:

    AD_IN = ADRESL + (ADRESH << 8)

    or maybe (to make sure ASRESH is treated as a 16-bit variable):

    AD_IN = ADRESH
    AD_IN = (AD_IN << 8) + ADRESL
     
  14. chopnhack

    chopnhack

    1,573
    352
    Apr 28, 2014
    Yep! Lots of rain, but inside all is well :)

    Cool!! Glad it finally got there. Yes, test fit your parts, you never know since I sized this for the parts I had on hand. I am glad I have a working version, its a lot better than breadboarding in the sense that you know that you have a working baseline. Thanks for the compliment on the board, I think it came out pretty spiffy for a home made job, despite the failed solder mask (again) LOL. I am sure once you are settled you will be able to crank out some of your own boards. Especially since I found you that great deal on Amazon for ferric chloride LOL.

    I find this strange since when I think of a multiplication operation, that its a decimal event, meaning 3x2=6. In our example, lets say we have 0000 0001 and we multiply by 256 then we have 1000 0000! But its not ten million but the binary representation of 256 which indeed is what 1x256 is. And its even stranger that it's simply a shift to the left like that. I get it, but it takes awhile for the info to take hold, thanks for explaining it and yes, shifting is the way to go!!!

    I believe that is what the code Adam posted did, IIRC.

    makes sense, you're in a way, typecasting, since we set AD_IN as an unsigned integer. That is a good pickup Hop!!

    Thanks again, this is a small step, but I find it very exciting since now I have access to interface analog components which opens up a world of ideas. Next on the list of learning is interrupts and sleep and of course porting this to ASM.

    BTW, even though the field notes you linked me indicated that a schottky diode was ok to separate the MCLR circuitry from the ICSP, this is what a forum member at microchip noted:
    Code:
    Re: ICSP failure to program while in circuit? Yesterday
    <<
    From me:
    I don't see how the Schottky diode idea ever worked.  Many PICs have an internal pullup for /MCLR, and if the diode is oriented to block current from the /MCLR pin to the reset circuit, it is impossible for the reset circuit to pull /MCLR low against the pullup. 
     >>
     
    It was my understanding that the MCLR pin has to be held high and when it goes low, then the reset occurs. The schottky in my accompanying schematic does work (physically tested on a working board, resets fine via a tactile switch with a r/c debounce). The diode allows current to pass towards the chip from R2 which is fed by Vdd. 
     
    In my example, I am not using the WPUA register.
    
    [IMG]http://www.microchip.com/forums/app_themes/MCHP/image/noavatar.gif[/IMG]
    Ian.M
    
    Super Member
    Re: ICSP failure to program while in circuit? Yesterday
    The /MCLR pin is a somewhat modified CMOS input that also has a circuit to detect if its above Vdd enough for VPP to be present.  The max /MCLR leakage current at input voltages between the supply rails is +/-5uA and +/-0.1uA is quoted as typical.  (parameter D061)
     
    Probably either the diode's reverse leakage current and/or the junction capacitance of the diode was enough to pull /MCLR low momentarily.  *NOT* something I would trust to work with *ANY* combination of PIC and small signal Schottky diode.
    
    So if I see any issues, I will recall to take out the schottky and work in a 10k resistor. I have cycled the MCLR several times with various LED's illuminated with no issues though....

    Off to bed, tomorrow is going to be slammed at work!
     
  15. hevans1944

    hevans1944 Hop - AC8NS

    4,541
    2,116
    Jun 21, 2012
    Close, but no cigar! 0000 0001 multiplied by 256 is 1 0000 0000. Or regrouping the digits for base eight, 100 000 000 which I suppose you could read aloud as one hundred million. But nobody I know does that. And base eight notation died a deserved death in the twentieth century.

    You have to consider the "weight" of each bit at each bit position. The weight of bit 0 is 1 if the bit is set, zero if it is cleared. The weight of bit 1 is either 2 or 0 depending on whether it is set or cleared. And so on in powers of 2 for bits 2 through 7 which have weights of 4, 8, 16, 32, 64 and 128 if set to one or zero if cleared. Bit 8 does not exist in an 8-bit register, but if it did exist (in a longer register) it would have a weight of 256. So, 1 0000 0000 = 256 and 0000 0001 x 256 = 1 0000 0000. If all the bits are set in an 8-bit register, the sum of their weights is 255: 1111 1111 = 255. Adding one to this results in all the bits clearing to zero and a carry out of the most significant bit: 1 (CY) + 0000 0000.

    There are assembler instructions that allow you to add arbitrarily wide binary numbers by using the carry bit to extend byte or word additions to arbitrary lengths. Well, you have to define what you are doing in the code, but there is no "built in" limit to how far you can take the process. Back in the 1980s I wrote a program that would allow arithmetic on very large decimal numbers, just to prove I understood the process. Satisfied that I did, I never used it again. That's what mainframes are for: crunching large numbers. I just wanted to "prove" my "toy" computer could play with the big boys, albeit slower.

    On how to interface /MCLR input and still be compatible with ICSP, read this thread and use the schematic below, No Schottky diode necessary.

    [​IMG]

    Minimum circuit for /MCLR is a 10 kΩ pull-up to +5 V or Vdd. And I never worry about contact bounce on reset. Why care how many times it resets as long as it does reset? I am sure someone, somewhere, can provide a counter-example where one and only one reset must result from a single button-press, but I haven't encountered that yet. Heck, sometimes I just pull off the wire providing power to effect a "reset" condition.
     
    Arouse1973 likes this.
  16. Arouse1973

    Arouse1973 Adam

    5,164
    1,081
    Dec 18, 2013
    Hi Guys
    The capacitor that's part of the reset RC circuitry is for slow rising Vdd and slows down the rise of MCLR to create a POR. The Vdd must be stable before MCLR. If you look on the data sheet you should see some timings which show this.
    Thanks
    Adam
     
    hevans1944 likes this.
  17. hevans1944

    hevans1944 Hop - AC8NS

    4,541
    2,116
    Jun 21, 2012
    Some more observations on "shifting" to obtain a multiplication result:

    In the decimal or base 10 number system, we "shift" the decimal point to the right to multiply a number by powers of 10. So 1234. becomes 12340. Similarly, "shift" the decimal point to the left to divide a number by powers of 10. So 1234. become 123.4.

    A similar effect occurs with binary or base 2 number systems. If we "shift" the binary point to the right by one bit position the effect is to multiply the binary number by 2: 1010 become 10100. Check: 1010 is decimal 10 and 10100 is decimal 20. So far so good. But what we have really done in moving the binary point to the right (and filling in with zeroes) is to left-shift all the bits by one bit position, filling in the blanks with zeroes. Note that this type of multiplication (moving the binary point or the decimal point) is valid only for multiplication by integer powers of the number base. So you can move the decimal point for multiplication by powers of ten: 10, 100, 1000, etc. And you can move the binary point for multiplication by powers of two: 2, 4, 8, 16, etc.

    Where you can get into trouble is thinking you can shift in the other direction for division operations. Well, you can, but the results may not be to your expectations. 1010 binary divided by 2 becomes 0101 (shifting zeroes in from the left) which makes sense. But what does it mean if we divide 1010 binary by 4? The answer is 0010 plus a remainder of .1 to deal with. We know 1010 is the binary representation of the decimal number 10, so 10 / 2 = 5 or 0101 binary. But decimal 10 / 4 = 2.5 decimal, or binary 0010.1 with that .1 appended to the end having a "weight" of 1/2 or two to the minus one power. What do we do with that?

    [BEGIN RANT] It's a can of worms working with negative powers of two when everything else is signed or un-signed binary integers! Best to do divisions using floating-point math functions. And multiplications, too, if multiplying by something that is not an integral power of two. In general, math operations on small microprocessors are a PITA that should be avoided. Floating-point math takes up a lot of program space for even the most trivial functions and operations. If at all possible, avoid having to use floating-point arithmetic. Sure, it's easy to use FP variables and constants in C, but take a look at the assembly code it produces. Caveat: some microprocessors have floating-point processors built in. That doesn't mean you should liberally sprinkle your code with floating-point operations![/END RANT]
     
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-