如何实现两次按钮中断PIC

时间:2018-02-01 17:06:47

标签: c embedded microcontroller interrupt pic

我正在使用16F1703 PIC mcu,我想按一下按钮(A1)开始7段lcd循环(0-9)循环,之后如果我触摸按钮(A1)两次,我希望Pic进入睡眠模式。

为此,我实施了这个:

#include <test_interrupt.h>
byte const DataExit[10]={0b01000100,
                               0b01011111,  
                               0b01100010,
                               0b01001010,
                               0b01011001,
                               0b11001000,
                               0b11000000,
                               0b01011110,
                               0b01000000,
                               0b01001000};
byte const bitMask[8]={1,2,4,8,16,32,64,128};

//show seven numbers
void segmentCycle(void){
   int i, j; 
   for(i=0;i<10;i++){
         for (j=0; j<8;j++){
            output_low(CLK);
            output_bit(DATA,DataExit[i] & bitMask[j]);
            output_high(CLK);  
         }

         delay_ms(7000);
         output_low(CLR);
         delay_ms(6000);
         output_high(CLR); 
   }
}

#INT_IOC
void  IOC_isr(void) 
{
  segmentCycle(); 
  sleep(); 

}

void main()
{
   port_a_pullups(0x02);
   enable_interrupts(INT_IOC_A1);
   enable_interrupts(INT_IOC_A1_H2L);
   enable_interrupts(GLOBAL);

   while(TRUE);

}

现在,如果我触摸按钮,有时它会启动,否则它不启动。 你有什么建议?

我正在使用ccs编译器。

2 个答案:

答案 0 :(得分:4)

Your code lacks a proper debounce algorithm and your circuit design is probably flawed. Hooking a button to an interrupt is a waste of a valuable resource, especially if it lacks a debounce circuit. That aside for now, your ISR is going off and doing at least 13000ms of work (well "delay")! ISR's should be short and fast. When they happen, they interrupt whatever code is running at the time, and in the absence of any hard/soft debounce mechanisms, are likely to fire many times per button press (put a scope on that button). That means you're ISR routine might be entered many times before it ever exits from the first call, but even that depends on pin configurations we can only guess at because the relevent code is missing from your OP.

Normally, you'd have a main loop that does whatever work needs to happen and the ISR's simply signal state changes via flags, counters or enumerations. When the main loop detects a state change, it calls whatever function(s) handle that change. In your case, it probably needs to check the current time and the last time the button was pressed, and verify that a minimum period has elapsed (500ms is usually good enough on pin with reasonable pull-up). If not enough time has passed, it resets the flag, otherwise it does the needed work.

See page 72 of the device spec. and take note that there are multiple interrupt sources and the ISR is responsible for determining which source caused it to fire. Your code doesn't look at the interrupt flags, nor does it clear the previous interrupt before exit, so you're never going to see more than one interrupt from any particular source.

With a little bit of searching, you should be able to find free code written to work on your specific PIC chip that handles button debounce. I recommend that you find and study that code. It will make for a very good starting point for you to learn and evolve your project from.

答案 1 :(得分:1)

看起来你的挂机就是你希望PIC在按下按钮之前一直处于睡眠状态。我会做这样的事情,使用CCS C编译器:

#include <16f1703.h>

#use delay(int=8MHz)

#use fast_io(A)

#include <stdbool.h>
#include <stdint.h>

bool g_isr_ioc_flag = 0;
uint8_t g_isr_ioc_porta = 0;

#int_ioc
void isr_ioc(void)
{
  if (!g_isr_ioc_flag)  //only trap first IOC
  {
     g_isr_ioc_flag = 1;
     g_isr_ioc_porta = input_a();
  }
}

void main(void)
{
   uint8_t debounced_a;

   set_tris_a(2);
   port_a_pullups(0x02);
   enable_interrupts(INT_IOC_A1);
   enable_interrupts(INT_IOC_A1_H2L);
   enable_interrupts(GLOBAL);

   for(;;)
   {
      sleep();

      if (g_isr_ioc_flag)
      {
         // cheap debounce.  bit in debounced_a set if pin has been low 
         // for at least 72ms.
         delay_ms(72);
         debounced_a = ~g_isr_ioc_porta & ~input_a();
         g_isr_ioc_flag = 0;
         input_a();  // clear IOC flags left by race condition

         if (bit_test(debounced_a, 1))
         {
            // TODO: user code - handle RA1 press
         }
      }
   }
}

正常情况下,去抖动例程必须轮询引脚以查看它是否变为低电平以启动去抖定时 - 但在您的情况下,更改中断(IOC)ISR会为我们做一些工作。

CCS函数input_a()自动清除IOCAF中的相关IOC标志位。这意味着调用input_a()将清除ISR标志,直到下一次更改。

此设计允许您处理主循环中的其他唤醒源。请注意,任何其他外设ISR或WDT都会唤醒PIC。