C 如何实现两次按键中断

C 如何实现两次按键中断,c,embedded,microcontroller,interrupt,pic,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,

我正在使用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);

}
#包括
字节常量DataExit[10]={0B01000000,
0b01011111,
0b01100010,
0b01001010,
0b01011001,
0b11001000,
百万元,
0b01011110,
0b01000000,
0b01001000};
字节常量位掩码[8]={1,2,4,8,16,32,64128};
//显示七个数字
空段循环(void){
int i,j;
对于(i=0;i您的代码缺少正确的接口,并且您的电路设计可能有缺陷。将一个按钮挂接到一个中断是浪费宝贵的资源,特别是如果它缺少去抖动电路。暂且不提这一点,您的ISR正在运行,并且至少完成13000毫秒的工作(好的“延迟”)!ISR应该短而快。当它们发生时,它们会中断正在运行的任何代码,并且在没有任何硬/软去抖动机制的情况下,每次按下按钮都可能触发多次(在该按钮上放置一个范围)。这意味着您的ISR例程在第一次调用退出之前可能会被多次输入,但即使如此,这也取决于pin配置,我们只能猜测,因为您的OP中缺少相关代码

通常情况下,主循环执行任何需要执行的工作,ISR的信号状态通过标志、计数器或枚举进行更改。当主循环检测到状态更改时,它调用任何函数处理该更改。在您的情况下,它可能需要检查当前时间和上次按下按钮的时间,并验证是否经过了最短时间(500毫秒通常在具有合理上拉的引脚上足够好)。如果没有足够的时间,它将重置标志,否则它将执行所需的工作

请注意,有多个中断源,ISR负责确定触发它的源。您的代码不会查看中断标志,也不会在退出前清除上一个中断,因此您永远不会看到来自任何特定源的多个中断

通过一点搜索,您应该能够找到在处理按钮去抖动的特定PIC芯片上编写的免费代码。我建议您找到并研究该代码。这将为您学习和发展项目提供一个很好的起点。

您的代码缺乏正确的设计,并且您的电路设计可能是正确的有缺陷。将一个按钮与一个中断挂钩是一种浪费宝贵资源的行为,尤其是当它缺少一个去盎司电路的时候。暂且不提这一点,你的ISR正在运行,并且至少要完成13000毫秒的工作(好吧,“延迟”)!ISR应该短而快。当它们发生时,它们会中断正在运行的任何代码,并且在没有任何硬/软去抖动机制的情况下,每次按下按钮都可能触发多次(在该按钮上放置一个范围)。这意味着您的ISR例程在第一次调用退出之前可能会被多次输入,但即使如此,这也取决于pin配置,我们只能猜测,因为您的OP中缺少相关代码

通常情况下,主循环执行任何需要执行的工作,ISR的信号状态通过标志、计数器或枚举进行更改。当主循环检测到状态更改时,它调用任何函数处理该更改。在您的情况下,它可能需要检查当前时间和上次按下按钮的时间,并验证是否经过了最短时间(500毫秒通常在具有合理上拉的引脚上足够好)。如果没有足够的时间,它将重置标志,否则它将执行所需的工作

请注意,有多个中断源,ISR负责确定触发它的源。您的代码不会查看中断标志,也不会在退出前清除上一个中断,因此您永远不会看到来自任何特定源的多个中断


通过一点搜索,您应该能够找到在处理按钮去抖动的特定PIC芯片上编写的免费代码。我建议您找到并研究这些代码。这将为您学习和发展项目提供一个非常好的起点。

看起来您的挂断是因为您希望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
         }
      }
   }
}
#包括
#使用延迟(int=8MHz)
#使用快速io(A)
#包括
#包括
bool g_isr_ioc_标志=0;
uint8\u t g\u isr\u ioc\u porta=0;
#国际奥委会
无效isr\U ioc(无效)
{
if(!g_isr_ioc_flag)//仅陷阱第一个ioc
{
g_isr_ioc_标志=1;
g_isr_ioc_porta=输入a();
}
}
真空总管(真空)
{
取消公告;
集_tris_a(2);
端口a\U上拉(0x02);
启用中断(INT_IOC_A1);
启用中断(INT_IOC_A1_H2L);
启用_中断(全局);
对于(;;)
{
睡眠();
if(g_isr_ioc_标志)
{
//便宜的脱胶。如果针的位置低,则在一套脱胶中加入一点
//至少72毫秒。
延迟时间(72);
去公告a=~g_isr_ioc_porta&~input_a();
g_isr_ioc_标志=0;
input_a();//清除竞赛条件留下的IOC标志
if(位测试(去抖动a,1))
{
//TODO:用户代码-处理RA1按
}
}
}
}
通常情况下,去盎司例行程序必须轮询引脚,查看引脚是否变低,以开始去盎司计时-但在您的情况下,更改中断(IOC)ISR为我们做了一些工作

CCS函数输入_a()自动清除IOCAF中的相关IOC标志位。