C 如何实现两次按键中断
我正在使用16F1703 PIC mcu,我想在触摸按钮(A1)时开始7段lcd循环(0-9),然后如果我触摸按钮(A1)两次,我希望PIC进入睡眠模式 为此,我实施了以下措施: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,
#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标志位。