Let me begin slowly and clear: recently I started with PIC microcontrollers; having done several basic projects for newscomers to PIC microcontrollers such as flashing an LED on/off, interfacing a 7-segment display, and even interfacing a LCD display. To be honest; most of the things I've learned about PIC microcontrollers have been thanks to YouTube channel Student Companion; as well as webpage electroSome. I had no previous experience with PIC microcontrollers (and microcontrollers in general tho...). However my problem begins when I want to use the ADC module of a PIC16F877A. I'm using MPLAB X IDE v3.55 with XC8 compiler. Now I know that for the ADC I have to know how to use 4 registers that control the behavior of the ADC which are:
The first two ones are for configuring the behavior of the ADC; whereas the last two are just registers on where the ADC conversion value will be stored.
Now I'm going to explain my circuit with this figure:
What I want to do is to control five LEDs using a potentiometer through a PIC16F877A. This is my line of code I wrote in MPLAB X:
I want to declare that I actually don't know how to "read" the value of the potentiometer; so the part of the function read_ADC(){} was actually taken from the electroSome site. For more details check the page at: https://electrosome.com/adc-pic-microcontroller-mplab-xc8/
However I kind of know how to initialize my ADC module and this is done declaring the bits of the ADC module registers ADCON0 and ADCON1.
Now as you can see in the schematic the only bit of PORTA that I want to use as analog input is RA0/AN0; and I want to use the rest of PORTA as digital I/O which is where I'm going to connect my five LEDs. I could have connected my LEDs to either PORTB, PORTC, or PORTD, however for the sake of saving pins I will just use one port: PORTA so I can use the other unused ports for other tasks (like interfacing a LCD display, a keypad, or any other thing for the like).
The description so is that I want to use FOSC/2; only 1 analog channel and the rest as digital I/O with reference voltages in Vss and Vdd, and the channel to be read is AN0; with my result to be left justified. Therefore with all these descriptions and since I only want to initialize my ADC then the init_ADC(){} function is:
There is no syntax error in my code since when I built it MPLAB terminal said BUILD SUCCEDEED. I then had put the resulting hex file in the PIC16F877A microcontroller from the simulation in Proteus and setting the processor clock frequency to 4MHz. I know that the value to be read from the ADC is from 0-1023 (there are 1024 values that can be stored in 10 bits after the conversion which are from 0000000000 to 1111111111) in integer form so when the potentiometer analog input is between 300 and 500 then ALL LEDs must turn on. However when I ran the circuit in Proteus this never happens; and pins RA1-RA5 are always in logic 0.
I don't know where the problem is because I previously did the electroSome circuit in the link I posted in blue (the circuit with the 10 LEDs); however the LEDs were in a different PORT that has no analog inputs and they declared ALL pins of PORTA as analog inputs (PCFG=0000) yet they only use ONE pin; which I think is a waste of pins that could be used for other tasks. I don't know if it is actually possible to do what I want in this circuit and if it is I would appreciate your answers on where my code is wrong and how I could improve it so I can correctly use the ADC module of the PIC16F877A.
Moderator edit: added code tags
- ADCON0
- ADCON1
- ADRESH
- ADRESL
The first two ones are for configuring the behavior of the ADC; whereas the last two are just registers on where the ADC conversion value will be stored.
Now I'm going to explain my circuit with this figure:
I want to declare that I actually don't know how to "read" the value of the potentiometer; so the part of the function read_ADC(){} was actually taken from the electroSome site. For more details check the page at: https://electrosome.com/adc-pic-microcontroller-mplab-xc8/
However I kind of know how to initialize my ADC module and this is done declaring the bits of the ADC module registers ADCON0 and ADCON1.
Code:
// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS 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)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
#include <stdlib.h>
#include <stdio.h>
#define _XTAL_FREQ 4000000
void init_ADC(void){
//ADCON0 register bits
ADCON0=0b01000000;
//ADCON1 register bits
ADCON1=0b00001110;
return;
}
unsigned int read_ADC(unsigned int channel){
if(channel>7){ //ADC channels are through AN0-AN7
return 0;
}else{
ADCON0 &= 0xC5; //Clearing channel selection bits
ADCON0 |= channel<<3; //Setting channel selection bits
__delay_ms(2); //Acquisition time to charge hold capacitor
GO_nDONE = 1; //Initializes A/D conversion
while(GO_nDONE); //Waiting for conversion to complete
return ((ADRESH<<8)+ADRESL); //Return result
}
}
void main(void){
TRISAbits.TRISA1=0;
TRISAbits.TRISA2=0;
TRISAbits.TRISA3=0;
TRISAbits.TRISA4=0;
TRISAbits.TRISA5=0;
init_ADC();
int adc;
while(1){
adc=read_ADC(0);
if(adc>300&&adc<500){
PORTAbits.RA1=1;
PORTAbits.RA2=1;
PORTAbits.RA3=1;
PORTAbits.RA4=1;
PORTAbits.RA5=1;
}else{
PORTAbits.RA1=0;
PORTAbits.RA2=0;
PORTAbits.RA3=0;
PORTAbits.RA4=0;
PORTAbits.RA5=0;
}
}
return;
}
The description so is that I want to use FOSC/2; only 1 analog channel and the rest as digital I/O with reference voltages in Vss and Vdd, and the channel to be read is AN0; with my result to be left justified. Therefore with all these descriptions and since I only want to initialize my ADC then the init_ADC(){} function is:
Code:
void init_ADC(void){
//ADCON0 register bits
ADCON0=0b01000000;
//ADCON1 register bits
ADCON1=0b00001110;
return;
}
I don't know where the problem is because I previously did the electroSome circuit in the link I posted in blue (the circuit with the 10 LEDs); however the LEDs were in a different PORT that has no analog inputs and they declared ALL pins of PORTA as analog inputs (PCFG=0000) yet they only use ONE pin; which I think is a waste of pins that could be used for other tasks. I don't know if it is actually possible to do what I want in this circuit and if it is I would appreciate your answers on where my code is wrong and how I could improve it so I can correctly use the ADC module of the PIC16F877A.
Moderator edit: added code tags