1. ivars88

    Thread Starter New Member

    Feb 17, 2013
    5
    0
    Hello! I am struggling with my program. With Arduino everything is easy, but with my PIC16F873 is harder. I hope some smart people will watch code and tell whats wrong. I'm using MPLAB IDE and HI-TECH compiler. Build hapens succesfully but when writing code in MC it doesnt go very well.. It doesnt read A0.

    Code:
    //Simple program to read analog sensor(potenciometer)
    //and control 3 leds.
    #include "htc.h"
    __CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & CP_OFF);
    void main()
    {
    TRISB = 0x00; // B ports are outputs
    PORTB = 0; //Beginning condition 0
    TRISA = 0xFF; //A port are input
    unsigned int val; //Variable for storing converted anolog signal

    ADCON0 = 0b01000101; //A/D control bit register
    ADCON1 = 0b10000000; //ADFM 1

    while(1)
    {
    GO_DONE = 1; //Start conversion
    while(GO_DONE) continue;
    val = ADRESL >> 2; //Assign converted value to variable
    if (val > 500) {PORTB = 0x01;}
    else {PORTB = 0b00000110;} //Turn on 2 LED diodes
    }
    }

    Here the schematic:
    http://www.bildites.lv/viewer.php?file=q6hefcnqyezzgjkaukg7.png
     
  2. nigelwright7557

    Senior Member

    May 10, 2008
    487
    71
    I think you have to set the ansel register too to set input as analogue.
     
  3. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,395
    1,607
    Excellent first post, a simple program defining your pboblem and a full schematic of a simple target device. All I would ask is you use the code tag button (#) so your code is more readable.

    I believe you are correctly running the A2D, just misinterpreting the results. Since the result is a 10 bit number and larger then any one register, ADRES comes in hi and low sections. I don't have the HiTech compiler handy but look thru the user's guide and there should be some sort of macro to read a register pair like this.

    If not...
    Code ( (Unknown Language)):
    1.  
    2.    val = ADRESH<<8 + ADRESL;
    3.  
    should always do the trick (albeit the long way).

    Next, since you put just 8 bits of the result into val, then further divided it by 4 (via the >>2) it will never be 500; even without the shift it would never get above 255.

    Try changing how you read into val and your code should start working.

    And welcome to the forums!
     
  4. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,395
    1,607
    I believe he did.
     
  5. ivars88

    Thread Starter New Member

    Feb 17, 2013
    5
    0
    Thank you very much ErnieM. It little bit helped, but still some issues reading. I will keep learning about bit shifting ;)



     
  6. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,395
    1,607
    There's several things happening here that may not be apparent (and I also sometimes make silly mistakes)

    A PIC holds the A2D result inside two 8 bit registers, as the result is 10 bits long. If you want to put them into one variable you need to squich em together the right way.

    Code ( (Unknown Language)):
    1. val = ADRESH<<8 + ADRESL;
    I don't offhand know the size (in bytes) of an unsigned int (as you chose for val) but I am assuming it is larger then an unsigned char. Unsigned char is 8 bits or 1 byte.

    When C is handed some math with variables of different sizes it "promotes" those in smaller sizes to larger ones. Here when working with ADRESL and ADRESH C makes unsigned int size places to hold them.

    First, ADRESH holds the top 2 bits, but in the lowest 2 bits of the register. So you need to shift them before you add in the lower part.

    ADRESH<<8 means shift ADRESH 8 bits to the left (larger).
    So if it started as: 00000001
    It ended as:...... 0100000000

    Note since it was "promoted" there is room for a larger quantity.

    Then there is room in the lower 8 bits for the lower 8 bits of the result.

    Hope this helps you on the way!
     
  7. ivars88

    Thread Starter New Member

    Feb 17, 2013
    5
    0
    Hi, thank you for response! I tried some things, changed the code to see on LEDS how big is "val" and how it changes. Everything else left the same.

    val = ADRESH<<8 + ADRESL; //Assign converted value to variable
    if (val < 100) {PORTB = 0b00000001;} //Turn on 1st diode
    else if (val < 100 && val < 500) {PORTB = 0b00000010;} //Turn on 2nd diode
    else if (val > 500) {PORTB = 0b00000100;} //Turn on 3rd diode
    else {PORTB = 0b00000000;} //Turn off all diods if all F

    In result 1st LED only turns on, the 3rd blinks for few ms and everything don't work as expected.

    So in the conclusion:
    1. Im still reading bits wrong;
    2. The code isnt writted well;
    3. Something wrong with chip or in schematic;

    If i shift bits <<8 isn't they go out of ADRESH register and are lost?
    Maybe i need to clear ADIF bit?
     
  8. RG23

    Active Member

    Dec 6, 2010
    301
    2
    while(1)
    {
    GO_DONE = 1; //Start conversion
    while(GO_DONE) continue;
    val = ADRESL >> 2; //Assign converted value to variable
    if (val > 500) {PORTB = 0x01;}
    else {PORTB = 0b00000110;} //Turn on 2 LED diodes
    }
    }
    _____________________________________________________________

    500 is 0x1F4
    After performing the A to D conversion,
    put the value of ADRESL in val2 and value of ADRESH in val1

    In the loop where you are using val>500,make use of val1 and val2

    check if val1 is 0x01 and val2 is > F4 at the same time

    Also try
    ADCON0 = 0x41
    ADCON1 = 0x00
     
    Last edited: Oct 1, 2013
  9. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,395
    1,607
    How do you program your PIC? If you have a PICkit (or several other tools) you can step theu the code as it is running on your device, and read out registers and variables to see what is actually happening in as much (or little) detail you want.
     
  10. djsfantasi

    AAC Fanatic!

    Apr 11, 2010
    2,815
    834
    In this code, the second LED will never be lit. If val<100, the first if statement will be executed and none of the others. In the first else if clause, val must be both <100 and <500. But the program will only get here if val>=100 and the first if trapped that condition. So your second condition will never be satisfied. Try removing "Val<100 &&" from the first else if clause.

    Note this isn't perfect, but hopefully you will see how the program operates and figure out the improvements needed.
     
  11. ivars88

    Thread Starter New Member

    Feb 17, 2013
    5
    0
    Thanks for mentioning that ;)

    @ErnieM Im using PicKit2 and dont really know how to do that..

    But proper readings i still cant get, even when i tried mentioned things.. :/
     
  12. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,395
    1,607
    debugging with a PICkit II under MPLAB is actually really simple. (I've yet to use MPLAB X so someone else will have to tell you that way).

    You just leave the PICkit connected to your PIC. In MPLAB, on the menu pick DEBUGGER and hunt out the PICkit II. If you have a pull down that says "Release" pull it and change to "Debug." Rebuild your code and BAM, you are ready to in circuit debug.

    Check the Debugger menu for useful things to do like single step. You can just hover over variables (I believe) and see their values but under the view menu you can open windows to see (and change!) all or selected registers and variables.
     
  13. ivars88

    Thread Starter New Member

    Feb 17, 2013
    5
    0
    Thanks, i found the way how to fix my code and use debugger in MPLAB ;)
     
  14. ligo.george

    New Member

    Feb 2, 2013
    19
    2
    I think the code for pic 16f877a will work for you..

    Code ( (Unknown Language)):
    1.  
    2. #include<htc.h>
    3. #include<pic.h>
    4.  
    5. #define _XTAL_FREQ 8000000
    6.  
    7. void ADC_Init()
    8. {
    9.   ADCON0 = 0x41; //ADC Module Turned ON and Clock is selected
    10.   ADCON1 = 0xC0; //All pins as Analog Input
    11.                  //With reference voltages VDD and VSS
    12. }
    13.  
    14. unsigned int ADC_Read(unsigned char channel)
    15. {
    16.   if(channel > 7) //If Invalid channel selected
    17.     return 0;     //Return 0
    18.  
    19.   ADCON0 &= 0xC5; //Clearing the Channel Selection Bits
    20.   ADCON0 |= channel<<3; //Setting the required Bits
    21.   __delay_ms(2); //Acquisition time to charge hold capacitor
    22.   GO_nDONE = 1; //Initializes A/D Conversion
    23.   while(GO_nDONE); //Wait for A/D Conversion to complete
    24.   return ((ADRESH<<8)+ADRESL); //Returns Result
    25. }
    26.  
    27. void main()
    28. {
    29.   unsigned int a;
    30.   TRISB = 0x00; //PORTB as output
    31.   TRISC = 0x00; //PORTC as output
    32.   TRISA = 0xFF; //PORTA as input
    33.   ADC_Init(); //Initializes ADC Module
    34.  
    35.   do
    36.   {
    37.     a = ADC_Read(4); //Reading Analog Channel 0
    38.     PORTB = a; //Lower 8 bits to PORTB
    39.     PORTC = a>>8; //Higher 2 bits to PORTC
    40.     __delay_ms(100); //Delay
    41.   }while(1); //Infinite Loop
    42. }
    43.  
    [​IMG]
    Try this link :
    Using ADC of PIC Microcontroller - Hi Tech C
     
Loading...