• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Reading ADC of PIC16F877A

Status
Not open for further replies.

Cantafford

Member
Hello,

I'm trying to control a DC motor with PIC16F877A and use a pot to set it's duty cycle.

I wrote this code:

Code:
/* 
 * File:   main.c
 * Author: Paul
 *
 * Created on June 20, 2016, 7:36 PM
 */

#include <stdio.h>
#include <stdlib.h>
#include "header.h"

void ConfigureADC();
void Getspeed();

void main()
{
   
    TRISA = 0x01;
    TRISC = 0;
    TRISD = TRISD & 0x03;
    PORTCbits.RC2 = 1; // motor oprit(enable in 0)

    PR2 = 0b01010010 ;
    T2CON = 0b00000111 ;
    CCP1M3 = 1;
    CCP1M2 = 1;
    CCP1M1 = 1;
    CCP1M0 = 1;

    PORTDbits.RD2=0;
    PORTDbits.RD3=0;
    ConfigureADC();

    while(1)
    {
        ADON = 1;
       
        if(PORTDbits.RD0 == 0 && PORTDbits.RD1 == 1)
        {
            PORTDbits.RD4=1; PORTDbits.RD5=0; // sens
            PORTDbits.RD2=1; PORTDbits.RD3=0; // leduri
            Getspeed();

        }


        if(PORTDbits.RD0 == 1 && PORTDbits.RD1 == 0)
        {
            PORTDbits.RD4=0; PORTDbits.RD5=1;
            PORTDbits.RD2=0; PORTDbits.RD3=1;
            Getspeed();
        }
    }
}

void ConfigureADC()
{
  ADCON0 = 0x00;
  ADCON1 = 0b00001110;
}

void Getspeed()
{
        GO=1;//Start conversion
        while(GO); //wait for the conversion to finish
        ADON=0;  //switch off adc
        CCPR1H = ADRESH;
        CCP1X = ADRESL & 0x80;
        CCP1Y = ADRESL & 0x40;
}
And header:
Code:
// PIC16F877A Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG
#pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)




#define __XTAL_FREQ 8000000
When I try to run the program, the motor runs full speed no matter what the position of the pot is. I don't know what I'm doing wrong but I'm guessing it has something to do with my oscillator. Maybe I have not set it up properly. Please help me identify the issue. Here is the schematic from simulator:

 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
One or two issues here..

A) the CCP1CON has to be addressed in full in ISIS ( don't know why )... The CCP1CON = 0x0C; works.. I think it would also work if the register was cleared first..

B) You write to CCPR1L not CCPR1H... the latter is read only..

C) PR2 is set to 0x52... With a prescale of 16 the PWM is set to 381Hz the pot ( reading 10 bit ) is constantly too high so the PR2 / TMR2 match never resolves..

d) Bit access doesn't work like this " CCP1X = ADRESL & 0x80; "... This is CCP1X = 0 when high or low!! Best way is to shift to 1 bit... ie... CCP1X = ADRESL >> 7 ; then CCP1Y = ADRESL >> 6; This way the result will work as the LSBit is either 0 or 1..

Finally you have no "Stopped" position... A final "if" statement to the motor if both or neither button is pressed to stop motion.
 

Cantafford

Member
One or two issues here..

A) the CCP1CON has to be addressed in full in ISIS ( don't know why )... The CCP1CON = 0x0C; works.. I think it would also work if the register was cleared first..

B) You write to CCPR1L not CCPR1H... the latter is read only..

C) PR2 is set to 0x52... With a prescale of 16 the PWM is set to 381Hz the pot ( reading 10 bit ) is constantly too high so the PR2 / TMR2 match never resolves..

d) Bit access doesn't work like this " CCP1X = ADRESL & 0x80; "... This is CCP1X = 0 when high or low!! Best way is to shift to 1 bit... ie... CCP1X = ADRESL >> 7 ; then CCP1Y = ADRESL >> 6; This way the result will work as the LSBit is either 0 or 1..

Finally you have no "Stopped" position... A final "if" statement to the motor if both or neither button is pressed to stop motion.
I used the calculation with the PR2 register beiing 0x52 with a FOSC of 8Mhz while I was configuring the ADC to use the internal ADC RC in ADCON0. So I configured in ADCON0 and ADCON1 to use FOSC/2(my FOSC is 8Mhz). I think the calculations for period are good for 8Mhz I double checked unless I'm not getting something right. The result is left justified so I'm loading ADRESH to CCPR1L as you said and the other two bits like in your example. Everything seems fine now but the simulations does not change. The motor runs full speed no matter where the pot is. Am I setting the oscillator correctly? I know that for the 18F series you have an OSCCON register, here I'm not finding any register to send the oscillator. And in ISIS I noticed that I don't get the 'ground' signal on both capacitors as you can see in my first snapshot.

Code:
/* 
 * File:   main.c
 * Author: Paul
 *
 * Created on June 20, 2016, 7:36 PM
 */

#include <stdio.h>
#include <stdlib.h>
#include "header.h"

void ConfigureADC();
void Getspeed();

void main()
{
   
    TRISA = 0x01;
    TRISC = 0;
    TRISD = TRISD & 0x03;
    PORTCbits.RC2 = 1; // motor oprit(enable in 0)

    PR2 = 0b01010010 ;
    T2CON = 0b00000111 ;

    CCP1CON = 0x0C;

    PORTDbits.RD2=0;
    PORTDbits.RD3=0;
    ConfigureADC();

    while(1)
    {
        ADON = 1;
       
        if(PORTDbits.RD0 == 0 && PORTDbits.RD1 == 1)
        {
            PORTDbits.RD4=1; PORTDbits.RD5=0; // sens
            PORTDbits.RD2=1; PORTDbits.RD3=0; // leduri
            Getspeed();
        }


        if(PORTDbits.RD0 == 1 && PORTDbits.RD1 == 0)
        {
            PORTDbits.RD4=0; PORTDbits.RD5=1;
            PORTDbits.RD2=0; PORTDbits.RD3=1;
            Getspeed();
        }
    }
}

void ConfigureADC()
{
  ADCON0 = 0b00000000;
  ADCON1 = 0b00001110;
}

void Getspeed()
{
        GO=1;//Start conversion
        while(GO); //wait for the conversion to finish
        CCPR1L = ADRESH;
        CCP1X = ADRESL >> 7;
        CCP1Y = ADRESL >> 6;
        ADON=0;  //switch off adc
}
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Pic16f87x is external crystal only... Three power settings.. RC, XT and HS.... But matters not a jot for ISIS as it doesn't simulate the oscillator anyway!!! You don't even need it on the schematic...

ADC = 0~ 1024..... ADRESH = 0 ~ 255.... You have selected PR2 = 82 therefore your ADC result is too high the majority of the time.... take the HG_POT model..... When you select 50% the ADRES will be 511... ADRESH will hold 127 ( that is twice as much as the PR2...

If the HG_POT was at 25% ADRESH will hold 64 ( nearly maximum CCPR1L /PWM ) ... Just saying is all!!!
 

Cantafford

Member
Pic16f87x is external crystal only... Three power settings.. RC, XT and HS.... But matters not a jot for ISIS as it doesn't simulate the oscillator anyway!!! You don't even need it on the schematic...

ADC = 0~ 1024..... ADRESH = 0 ~ 255.... You have selected PR2 = 82 therefore your ADC result is too high the majority of the time.... take the HG_POT model..... When you select 50% the ADRES will be 511... ADRESH will hold 127 ( that is twice as much as the PR2...

If the HG_POT was at 25% ADRESH will hold 64 ( nearly maximum CCPR1L /PWM ) ... Just saying is all!!!
Ok. My problem was that my function Getspeed was inside the ifs and so if I kept the buttons closed it would've read the ADC and put it into duty cycle but if I realesed them it wouldn't. So I put the function outside the ifs in the main loop and it now works :D
 
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top