Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
208 views
in Technique[技术] by (71.8m points)

c - How to detect periodic GPIO change in PIC

I am using a PIC12F675 microcontroller with the MPLAB X IDE. I am trying to detect the state of a machine by monitoring an LED with a photoresistor. I have the circuit working such that when the machine's LED is on, my chip is getting the input and turning on an LED of its own to match. I am not using interrupts right now, but instead just polling constantly for the input from the photoresistor circuit.

The two possible states for the LED, when the machine is turned on, are BLINKING and ON. It's never just OFF when the machine is powered.

I could use an interrupt but I am getting stuck on the idea of how to wait a certain amount of time while polling. The LED I am monitoring blinks about twice a second. So I would need to watch it for a second and then record it as "OFF" if at any point during that second the pin went low. ( There's a pull-down resistor on the input pin. )

I am not very experienced with C and have only used it for programming small chips like these to do small tasks. Is there some feature or function of C that would be useful for this? Or is there some way in the logic that I'm overlooking? Please help me figure out how to detect a blinking light vs. an ON light.

Here is my code so far:

// 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 = OFF      // 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)

#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  = 0xA;   // All GPIO pins output except 1&3.
    GPIO    = 0x00; // Make all pins LOW
    T0IE    = 0; // Disable timer interrupt.
    GPIE    = 0; // GPIO port change interrupt
    GIE     = 0; // Global interrupt for recognition of interrupts.
}

void main(void) {
    init_ports();
    /* Wait 1 second for power up. */
    __delay_ms(1000);
    while(1) {
        // Check for input on GPIO 1
        if (GPIO & 0b000010) {
          // Turn on the LED on GPIO 4
          GP4 = 1;
        }
        else{
          // Turn off the LED on GPIO 4
          GP4 = 0;
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

you don't even have to use interrupts to keep track of time. All you have to do is to setup a free-running timer, then the timer will keep the time for you. You just read the timer when you need to, and save the current time value. So when you detect a change on your inputs you compare the elapsed time between the time you read the timer value first and the current timer value. Note that we are not using the term 'time' by means of hours or minutes here. It is only a time base that you will define for tick events i.e. 1 millisecond. For example using Timer0 module of the PIC12F675 you can generate this time base. You just would have to add Timer0 init function and reconstruct your main code. Let me show you how by modifying your own code...

// 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 = OFF      // 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)

#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  = 0xA;   // All GPIO pins output except 1&3.
    GPIO    = 0x00; // Make all pins LOW
    T0IE    = 0; // Disable timer interrupt.
    GPIE    = 0; // GPIO port change interrupt
    GIE     = 0; // Global interrupt for recognition of interrupts.
}

/**
 * Init timer0 for 1 ms overflow @4MHz by setting:
 * prescaler to 1:4
 * reload value to 6
 * and assign the prescaler to the Timer0
 */
#define XTAL_FREQ_MHz       (_XTAL_FREQ / 1000000)
#define T0_PRESCALER        4
#define T0_OVERFLOW_RATE    1000 // in microseconds
#define SECOND              (1000000 / T0_OVERFLOW_RATE)
// Now calculate the TMR0 reload value for a 1 ms time base
#define T0_RELOAD_VALUE     256 - ((T0_OVERFLOW_RATE * XTAL_FREQ_MHz ) / (T0_PRESCALER * 4))

unsigned int ticks = 0;         // Variable to keep time up to 65 seconds
unsigned int lastOffTime = 0;   // Variable to record last OFF time
char lastState = 0, newState = 0; // Variable to hold new and last state of the pin
char offDetected = 0;

void init_timer0(void) {
    OPTION_REG = 0xC1;
    TMR0 = T0_RELOAD_VALUE; // in this case must be 6
    INTCONbits.T0IE = 0; // No timer interrupts
    INTCONbits.T0IF = 0; // Clear the flag for polling
}

void main(void) {
    init_ports();
    /* Wait 1 second for power up. */
    __delay_ms(1000);
    init_timer0();
    while(1) {
        // In the main loop first check the 1 ms
        while(!INTCONbits.T0IF); // Wait for the 1 ms time to elapse
        
        // 1 ms has elapsed proceed
        INTCONbits.T0IF = 0; // First clear the flag for the next use
        TMR0 = T0_RELOAD_VALUE; // Reload timer value
        ticks++; // Count every 1 ms ticks, don't worry for overflow
        
        // Then check your inputs in each tick for once
        // Check for input on GPIO 1
        if (GPIO & 0b000010) {
            newState = 1;
            // Turn on the LED on GPIO 4
            GP4 = 1;
        }
        else{
            newState = 0;
        }
        
        // Now check out the state changes, here is the OFF-control logic
        if(newState != lastState){
            if(newState == 0){
                // Here you detect when LED is off then record the last off time
                // First check if the time elapsed is more than 1 second
                lastOffTime = ticks; // Read current ticks
                offDetected = 1; // set the flag in order to keep track of time
            } else {
                offDetected = 0; // clear this flag to prevent checking time elapse
            }
            lastState = newState; // Save the newState
        }
        
        if(offDetected && (ticks - lastOffTime) > SECOND) {
            /* 
             * If the program flow reaches here, it means that the GPIO signal has shut off
             * more than 1 second, so do the necesary logic here like turning off 
             * the indicator LED
             */
            GP4 = 0;            // Turn off the LED on GPIO 4
            offDetected = 0;    // Clear the flag so that it does not enter here anymore
        }
    }
}

Hope it helps for your purpose. The code above is tested in MPLAB simulation and it passed the simulation test. You test it in your real hardware and let me know if you face any problem. Good luck!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...