Search code examples
c++microcontrollerpicmplab8-bit

Detect digital input from 2v5 src on a chip with 3v3 power?


I'm using a 12F675 PIC and I have programmed it to make 3 LEDs flash in sequence. I want it to only do this when a particular input is NOT received. The PIC is running at 3v3 and that seems to be enough to power the chip and the LEDs when I test it. The input is from another LED on a different PCB, basically I want to detect whether it is on or off. It lights at 2v5 so that's the input into my input pin. When I test it out, turning off the 2v5 source or starting with it turned off doesn't trigger the 3 LEDs to flash. Here's my code:

/*
 * File:   main.c
 */

// PIC12F675 Configuration Bit Settings
// 'C' source line config statements
// CONFIG

#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: CLKOUT function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = ON       // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // GP3/MCLR pin function select (GP3/MCLR pin function is MCLR)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#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)

// #pragma config statements should precede project file includes.

#define LED_GRN   GP0
#define LED_YLW   GP1
#define LED_RED   GP2
#define LED_IN    GP3 // I don't think this is used but it's here to show which pin the IO is on.

#define _XTAL_FREQ 4000000
#include <xc.h>
#include <stdlib.h>
#include <htc.h>


void init_ports(void) {
    ANSEL   = 0X00;  // Set ports as digital IO not analog input.
    ADCON0  = 0x00;  // Shut off ADC.
    CMCON   = 0x07;  // Shut off comparator.
    VRCON   = 0x00;  // Shut off the voltage reference.
    TRISIO  = 0x08;  // All GPIO pins output except 3.
    GPIO    = 0x00;  // Make all pins LOW.
}


void main(void) {
    init_ports();

    // Wait ~ 1s
    __delay_ms(1000);

    // Only flash LEDs if the backlight is off.
    // Do nothing while the backlight is on.
    while (GPIO & 0b001000);
    if (GPIO & 0b000000) {


        LED_GRN = 1;
        __delay_ms(200);
        LED_GRN = 0;
        __delay_ms(5000);

        LED_YLW = 1;
        __delay_ms(200);
        LED_YLW = 0;
        __delay_ms(1000);

        LED_RED = 1;
        __delay_ms(200);
        LED_RED = 0;
    }
}

Is there something about my code that's wrong, or is 2v5 too low below the operating voltage of the chip to be detected as receiving an input? If the latter, can I somehow set in code a different threshold, or use the comparator somehow to detect above a ~2v threshold? Or is there another way I should fix this problem?

UPDATE: Now I'm really confused, I have loaded some code onto the chip to blink green if (GPIO & 0b000000), blink yellow if (GPIO & 0b001000), and blink red else. It blinks yellow and then blinks red, whether the backlight is on or not. This is baffling to me because afaict it should not be possible for an "if" condition and the "else" to both fire.


Solution

  • There is a problem in your code here: if (GPIO & 0b000000).

    You do a bitwise AND between something and 0 - that is always 0, and 0 always evaluates to false.

    You want something like: if ((GPIO & 0b001000) == 0b001000) or if ((GPIO & 0b001000) == 0b000000)

    • extra parenthesis because I can't remember if & or == has precedence.

    On the other hand, you should be fine on the voltage level. On page 8 of the datasheet you linked it says that GP3 has a TTL input buffer, and on page 93 it says that the Input High Voltage with a TTL buffer is (0.25 VDD+0.8) = 1.625V (with 3.3V VDD).

    But of course, you should also measure that you actually have the 2.5V you think you have, since a diode drop over a LED could potentially put you under.