CrazyProgrammer
CrazyProgrammer

Reputation: 19

Analog data operations do not work in PIC12F675, there is not even a reaction on GPIO pins

This Analog data is read and the number 1-5 is shown on the 7 segment common anode display with 7447, but I can't set this number for analog value because I can't show analog values or output I wrote this code in MPLAB X IDE.

#include <xc.h>

#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   

#define _XTAL_FREQ 4000000
#define HIGH 1
#define LOW 0

unsigned int adc_value=0;

void main(void) {
    TRISIObits.TRISIO0 = 1;
    TRISIObits.TRISIO1 = 0;
    TRISIObits.TRISIO2 = 0;
    TRISIObits.TRISIO4 = 0;
    TRISIObits.TRISIO5 = 0;
    
    ANSELbits.ADCS2 = 0;
    ANSELbits.ADCS1 = 0;
    ANSELbits.ADCS0 = 0;
    ANSELbits.ANS0 = 1;
    
    ADCON0bits.CHS0 = 0;
    ADCON0bits.CHS1 = 0;
    ADCON0bits.ADON = 1;
    ADCON0bits.GO = 1;
    ADCON0bits.ADFM = 1;

    while(1) {
        ADON = 1;
        GO_DONE = 1;
        while(GO_DONE);
        adc_value = (((unsigned int) ADRESH << 8) + ADRESL);
        ADON = 0;
        if (adc_value >= 0 && adc_value <= 200) {
            GP4 = 0;
            GP5 = 0;
            GP2 = 0;
            GP1 = 0;
        } else if (adc_value > 200 && adc_value <= 400) {
            GP4 = 0;
            GP5 = 0;
            GP2 = 0;
            GP1 = 1;
        } else if (adc_value > 400 && adc_value <= 600) {
            TRISIObits.TRISIO4 = 0;
            TRISIObits.TRISIO5 = 0;
            TRISIObits.TRISIO2 = 1;
            TRISIObits.TRISIO1 = 0;
        } else if (adc_value > 600 && adc_value <= 800) {
            TRISIObits.TRISIO4 = 0;
            TRISIObits.TRISIO5 = 0;
            TRISIObits.TRISIO2 = 1;
            TRISIObits.TRISIO1 = 1;
        } else if (adc_value > 800 && adc_value <= 1023) {
            TRISIObits.TRISIO4 = 0;
            TRISIObits.TRISIO5 = 1;
            TRISIObits.TRISIO2 = 0;
            TRISIObits.TRISIO1 = 0;
        } else {
            TRISIObits.TRISIO4 = 1;
            TRISIObits.TRISIO5 = 1;
            TRISIObits.TRISIO2 = 1;
            TRISIObits.TRISIO1 = 1;
        }
        __delay_ms(100);
    }
    return;
}

my aim in this project is to print the number between 0-5 on the 7 segment common anode display according to the analog data between 0-1023, but I could not solve this problem.

Schema

Upvotes: 1

Views: 111

Answers (2)

CrazyProgrammer
CrazyProgrammer

Reputation: 19

As a solution, according to the code given by @Kozmotronik, the problem was solved when 74hc595 was used instead of 7447.

This is the solved code and scheme:


#include <xc.h>

#pragma config FOSC = INTRCIO   // Internal oscillator
#pragma config WDTE = OFF       // Watchdog Timer disabled
#pragma config PWRTE = OFF      // Power-up Timer disabled
#pragma config MCLRE = ON      // GP3/MCLR pin function is digital I/O
#pragma config BOREN = ON       // Brown-out Reset enabled
#pragma config CP = OFF         // Code Protection disabled
#pragma config CPD = OFF        // Data Memory Code Protection disabled

#define _XTAL_FREQ 4000000

#define ST_CP GP4
#define DS GP2
#define SH_CP GP1


unsigned int adc_value = 0;
float volt=0;
uint8_t LED [10]={
  0xE7, //0    0xE7
  0x21, //1
  0xDB, //2   0xD3
  0x6B, //3   0xD6
  0x3D, // 4  0xB4
  0x7E, // 5  0x76
  0xEE, //6
  0x23, //7   0xE4
  0xEF, //8
  0x7F, //9   0xF6
};

void spi_shift_out(uint8_t data) {
    uint8_t i;
    for (i = 0; i < 8; i++) {
        if (data & (1 << (7 - i))) {
            DS = 1;
        } else {
            DS = 0;
        }
        
        SH_CP = 1;
        __delay_us(1);
        SH_CP = 0;
    }
    
    ST_CP = 1;
    __delay_us(1);
    ST_CP = 0; 
}

void display_digit(uint8_t digit) {
    spi_shift_out(LED[digit]);
}

void main(void) {
    GPIO = 0; // Clear output latches
    CMCON = 7; // Turn off analog comparators
    TRISIO = 1; // GP0 and GP3 (GP3 is an only input pin) are input and other pins are output
    ANSEL = 0x21; 
    ADCON0 = 0x81; 
    while (1) {
        ADCON0bits.GO = 1;
        while (ADCON0bits.GO);
        adc_value = (ADRESH <<8) + ADRESL;
        volt=(adc_value*5)/1023;
        if (volt >= 0 && adc_value < 0.99) {
            display_digit(0);
        } else if (volt >= 1.0 && volt < 1.99) {
            display_digit(1);
        } else if (volt >= 2.0 && volt < 2.99) {
            display_digit(2);
        } else if (volt >= 3.0 && volt < 3.99) {
            display_digit(3);
        } else if (volt >= 4.0 && volt <= 4.99) {
            display_digit(4);
        } else {
            display_digit(4);
        }
        __delay_ms(100);
    }

    return;
}

Shema

Upvotes: -1

Kozmotronik
Kozmotronik

Reputation: 2520

You haven't configured GPIO<1:5> as digital IOs. That's why you cannot control them. According to the device's datasheet you muxt configure them using the CMCON and the ANSEL register.

Turn off the analog comparators

The CMCON register controls the built in analog comparators that uses several pins that connect the internal hardware to the outside world via the GP0 (CIN+), GP1 (CIN-) and GP2 (COUT) pins respectively. So you need to turn off the comparators hardware first by setting the CM2:CM0 bits to 7 (111 in binary).

CMCON = 7;

Configure analog and digital outputs

The ANSEL register is where you can tell the micro what pins you wanna use for ADC operation. In your case, since you use only the AN0 (GP0) and the rest must be configured as digital. What you wanna do is to set the corresponding ANSx bit for the pin you wanna use as analog input (you use AN0 hence you must set ANS0), and the rest of the ANSx bits must be set to 0 to use other pins as digital IO.

ANSEL = 1;

Let's tidy up your code

So if we wrap up the information above and merge it into your code, and also tidy up your code, the final code should look like this:

#include <xc.h>

#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

#define _XTAL_FREQ 4000000
#define HIGH 1
#define LOW 0


void setupInputs() {
    GPIO = 0; // Clear output latches
    CMCON = 7; // Turn off analog comparators
    TRISIO = 1; // GP0 and GP3 (GP3 is an only input pin) are input and other pins are output
}

void setupADC() {
    ANSEL = 0x21; // Set the GP0 pin as analog input and the rest is digital IO
                  // and use the internal RC osc for ADC
    ADCON0 = 0x81; // Right justify, sample CH0, ADC turn on
}

unsigned int getAnalogValueOnCh0() {
    ADCON0bits.GO = 1;
    while(ADCON0bits.GO)
        ;                // Wait for the ADC conversion to complete
    return (unsigned int) ( ADRESH << 8) + ADRESL;
}

void setDisplay(char value) {
    GP1 = value & 1;
    GP2 = (value & 2) >> 1;
    GP4 = (value & 4) >> 2;
    GP5 = (value & 8) >> 3;
}

void main(void) {

    setupInputs();
    setupADC();
    setDisplay(0);
    __delay_us(20); // See datasheet 7.2 A/D ACquisition Requirements

    while(1) {
        unsigned int adc_value = getAnalogValueOnCh0();
        if (adc_value >= 0 && adc_value <= 200) {
            setDisplay(0);
        } else if (adc_value > 200 && adc_value <= 400) {
            setDisplay(1);
        } else if (adc_value > 400 && adc_value <= 600) {
            setDisplay(2);
        } else if (adc_value > 600 && adc_value <= 800) {
            setDisplay(3);
        } else if (adc_value > 800 && adc_value <= 1023) {
            setDisplay(4);
        } else {
            setDisplay(5);
        }
        __delay_ms(100);
    }
}

PS: You shoud have ranged the values in 1024 / 6 = 170 approx. But you sliced the ADC valur into the chunks of 200. You choose.

Upvotes: 3

Related Questions