首页 > 解决方案 > 如何检测PIC中的周期性GPIO变化

问题描述

我正在使用带有 MPLAB X IDE 的 PIC12F675 微控制器。我试图通过用光敏电阻监控 LED 来检测机器的状态。我有电路工作,当机器的 LED 亮起时,我的芯片正在获取输入并打开自己的 LED 以匹配。我现在没有使用中断,而是不断地轮询光敏电阻电路的输入。

当机器开启时,LED 的两种可能状态是闪烁和开启。机器通电时,它永远不会只是关闭。

我可以使用中断,但我陷入了如何在轮询时等待一定时间的想法。我正在监控的 LED 大约每秒闪烁两次。所以我需要观察一秒钟,然后如果在那一秒钟内的任何时候引脚变低,则将其记录为“关闭”。(输入引脚上有一个下拉电阻。)

我对C不是很有经验,只用它来编写像这样的小芯片来完成小任务。C 的某些特性或功能对此有用吗?或者在我忽略的逻辑中是否有某种方式?请帮我弄清楚如何检测闪烁的灯与 ON 灯。

到目前为止,这是我的代码:

// 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;
        }
    }
}

标签: cpicgpiomicrochipmplab

解决方案


您甚至不必使用中断来跟踪时间。您所要做的就是设置一个自由运行的计时器,然后计时器将为您保留时间。您只需在需要时读取计时器,并保存当前时间值。因此,当您检测到输入发生变化时,您会比较您首先读取计时器值和当前计时器值之间的经过时间。请注意,我们在这里使用的“时间”一词不是指小时或分钟。它只是您将为滴答事件定义的时间基准,即 1 毫秒。例如,使用 PIC12F675 的 Timer0 模块,您可以生成这个时基。您只需要添加 Timer0 初始化函数并重建您的主代码。让我告诉你如何通过修改你自己的代码......

// 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
        }
    }
}

希望它对您的目的有所帮助。上面的代码在 MPLAB 仿真中进行了测试,并通过了仿真测试。你在你的真实硬件中测试它,如果你遇到任何问题,请告诉我。祝你好运!


推荐阅读