PIC单片机有无用中断,如何进行判断和过滤

在工作中使用的PIC24单片机,外部有一个干簧管作为中断源,3.3V拉高,目的是在休眠中通过干簧管产生的低电平唤醒CPU。
但是在使用过程中发现在这个管脚上,只要一进入休眠就会产生一个1500us的低电平,然后把CPU从休眠状态中拉出来了,每次都是。
花了很长时间来找这个低电平是怎么产生的,实在是不好找在哪里
想请问一下各位同行,这个中断源可以设置时间吗,设置成这个中断发生后,判断低电平时间超过10ms以上才算是一个正常的中断,可接受
然后,听说有占空比这个功能可以实现,但是我从来也没用过,不知道怎么用,希望能给予帮助

基于最新版ChatGPT4的回答,望采纳!!!有其他问题也可以询问我哦、”(最新版更智能,功能更加强大)

要实现这个功能,你可以使用一个定时器来判断低电平的持续时间。当外部中断触发时,启动定时器并在中断结束时停止定时器。然后根据定时器的计数值判断低电平持续时间是否超过10ms。下面是一个简化的实现示例:

  1. 配置外部中断和定时器:
void init(void) {
    // 配置外部中断
    configureExternalInterrupt();

    // 配置定时器
    configureTimer();
}
  1. 配置外部中断:
void configureExternalInterrupt(void) {
    // 以下代码仅作为示例,具体配置取决于你的硬件和需求
    _INT0IE = 0;          // 关闭INT0中断
    _INT0IF = 0;          // 清除INT0中断标志
    INTCON2bits.INT0EP = 0; // 配置INT0为负边沿触发
    _INT0IE = 1;          // 使能INT0中断
}
  1. 配置定时器:
void configureTimer(void) {
    // 以下代码仅作为示例,具体配置取决于你的硬件和需求
    T1CONbits.TON = 0;      // 关闭定时器1
    T1CONbits.TCS = 0;      // 使用内部时钟
    T1CONbits.TGATE = 0;    // 关闭门控模式
    T1CONbits.TCKPS = 0b11; // 预分频器设置为256
    PR1 = 0xFFFF;           // 设置定时器周期
    TMR1 = 0x00;            // 清除定时器计数值
    _T1IF = 0;              // 清除定时器1中断标志
    _T1IE = 1;              // 使能定时器1中断
}
  1. 实现外部中断服务例程:
void __attribute__((interrupt, no_auto_psv)) _INT0Interrupt(void) {
    _INT0IF = 0; // 清除INT0中断标志

    if (INTCON2bits.INT0EP == 0) { // 负边沿触发
        TMR1 = 0x00;        // 清除定时器计数值
        T1CONbits.TON = 1;  // 开启定时器1
        INTCON2bits.INT0EP = 1; // 配置INT0为正边沿触发
    } else { // 正边沿触发
        T1CONbits.TON = 0;  // 关闭定时器1
        INTCON2bits.INT0EP = 0; // 配置INT0为负边沿触发

        if (TMR1 >= TIMER_COUNT_THRESHOLD) {
            // 低电平持续时间超过10ms,执行唤醒处理
            handleWakeUp();
        }
    }
}

请注意将TIMER_COUNT_THRESHOLD 替换为表示10ms持续时间的定时器计数值。具体的值取决于你的时钟频率和定时器预分频器设置。例如,如果你的时钟频率是8MHz(Fcy = 4MHz),并且你将定时器预分频器设置为256,则需要将TIMER_COUNT_THRESHOLD设置为:

TIMER_COUNT_THRESHOLD = 10ms * Fcy / 256 = 10 * 10^-3 * 4 * 10^6 / 256156
  1. 实现定时器中断服务例程(如果需要):
void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void) {
    _T1IF = 0; // 清除定时器1中断标志

    // 如果需要在定时器溢出时执行操作,请在此处添加代码
}
  1. 实现handleWakeUp()函数来处理唤醒事件:
void handleWakeUp(void) {
    // 在这里执行唤醒后的处理,例如唤醒其他外设、执行特定任务等
}

通过这种方式,你可以在外部中断触发时启动定时器,然后在中断结束时停止定时器。根据定时器的计数值判断低电平持续时间是否超过10ms。如果超过10ms,执行唤醒处理。希望这个示例对你有所帮助!

基于最新版ChatGPT4的回答,望采纳!!!有其他问题也可以询问我哦💕(最新版更智能,功能更加强大):

为了判断和过滤中断,您可以在中断服务程序中添加一个计时器。当中断触发时,计时器开始计时。您可以检查低电平持续的时间,如果低电平时间超过10ms,那么认为是一个有效的中断,否则将其忽略。

占空比通常用于脉冲宽度调制(PWM)信号,表示高电平时间与总周期时间的比例。在您的情况下,占空比可能不适用。您需要关注的是低电平持续的时间,而不是占空比。

另外,您可以尝试使用硬件去抖动电路,例如RC滤波器,来减少误触发的可能性。这将有助于消除干簧管产生的短暂低电平信号。

由于您提供的搜索结果无法提供具体的解决方案,建议您查询PIC单片机的相关资料和手册,或者寻求同行的帮助。同时,您也可以尝试使用其他搜索引擎进行搜索,可能会找到更多有关PIC单片机中断处理和过滤的信息。

https://blog.csdn.net/zzq496281494/article/details/117998201

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
PIC24单片机的中断有两种,一种是优先级中断(Priority Interrupt),另一种是轮询中断(Polling Interrupt)。

对于你的问题,可以基于轮询中断的方式进行判断和过滤。具体步骤如下:

  1. 设置干簧管对应的IO口为输入模式,等待干簧管输出低电平。

  2. 进入休眠模式并设定唤醒模式为引脚变化唤醒模式。

  3. 当休眠模式被唤醒时,检测IO口的状态,如果是低电平,则进行下一步;否则返回第1步。

  4. 使用定时器,在一定时间内检测IO口的状态。如果在设定的时间内IO口仍然是低电平,则触发中断,并将中断状态置为未处理;否则返回第1步。

  5. 在中断处理程序中,检测中断状态是否未处理,如果是,则进行下一步;否则返回第1步。

  6. 将中断状态置为已处理,并执行相应的处理操作。

对于这个中断源可以设置时间的问题,可以通过占空比的方式进行实现。具体步骤如下:

  1. 设置定时器的工作模式为占空比测量模式。定时器会在每次输入的PWM波形的周期结束时,自动将占空比计算出并保存在寄存器中。

  2. 将干簧管作为PWM的输入信号,将占空比设定为一定的值,比如50%。

  3. 进入休眠模式并设定唤醒模式为引脚变化唤醒模式。

  4. 当休眠模式被唤醒时,检测IO口的状态,如果是低电平,则进行下一步;否则返回第3步。

  5. 在一定时间内,检测定时器中保存的占空比是否满足要求。如果满足,则触发中断,并将中断状态置为未处理;否则返回第3步。

  6. 在中断处理程序中,检测中断状态是否未处理,如果是,则进行下一步;否则返回第3步。

  7. 将中断状态置为已处理,并执行相应的处理操作。

以下是示例代码:

#include <p24Fxxxx.h>

// 中断状态,初始为未处理状态
volatile int interrupt_flag = 0;

void __attribute__((interrupt, auto_psv)) _DefaultInterrupt(void)
{
    // 处理未知中断
    INTCON1bits.NSTDIS = 0;
    INTCON2bits.ACKD = 1;
}

void __attribute__((interrupt, auto_psv)) _OC1Interrupt(void)
{
    // 处理干簧管中断
    interrupt_flag = 1;
    IFS0bits.OC1IF = 0;
}

int main(void)
{
    // 初始化IO口
    TRISA = 0xFFFF;
    TRISBbits.TRISB0 = 1;
    ANSA = 0;
    ANSBbits.ANSB0 = 0;
    CNPU1bits.CN2PUE = 0;
    CNPU1bits.CN1PUE = 0;

    // 初始化定时器1
    T1CONbits.TON = 0;
    T1CONbits.TCS = 0;
    T1CONbits.TGATE = 0;
    T1CONbits.TCKPS = 0;
    TMR1 = 0x0000;
    PR1 = 0xFFFF;
    T1CONbits.TON = 1;

    // 初始化PWM模块
    OC1CON1bits.OCM = 0b110;
    OC1CON1bits.OCTSEL = 1;
    OC1R = TMR1;
    OC1RS = PR1 / 2;
    IPC2bits.OC1IP = 4;
    IFS0bits.OC1IF = 0;
    IEC0bits.OC1IE = 1;

    // 进入休眠模式
    asm("disi #0x3FFF"); // 关闭所有中断,除了NMI和TRAP
    _CNIF = 0;
    CNEN1bits.CN2IE = 1;
    IEC1bits.CNIE = 1;
    _DSLP = 1;
    asm("nop"); // 关闭外设之前需要延时
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");

    while (1) {
        // 检测是否有中断触发
        if (interrupt_flag) {
            // 处理中断
            interrupt_flag = 0;
        } else {
            // 执行其他任务
        }
    }
}

如果我的回答解决了您的问题,请采纳!

该回答引用于gpt与OKX安生共同编写:
  • 该回答引用于gpt与OKX安生共同编写:

针对您的问题,可以考虑以下几个步骤来判断和过滤PIC单片机的无用中断:

    1. 通过代码编程控制中断响应时间:在中断服务程序中添加一个计时器,记录中断引脚低电平持续的时间,并进行比较。如果低电平持续时间小于设定的阈值(例如10ms),则认为这是一个无用中断,不执行相应的操作。否则,执行正常的中断处理操作。
    1. 利用占空比功能过滤中断信号:占空比是指信号高电平占总周期的比例,可以用于过滤周期性的信号。您可以使用定时器模块中的输入捕获功能,将中断信号转换为数字脉冲信号,然后测量其占空比。如果占空比低于一定阈值,即可过滤掉这个中断信号。

下面是一些具体的实现细节:

  1. 在中断服务程序中添加计时器功能:

首先需要配置定时器模块,选择一个计时器,使其在中断引脚低电平触发时开始计时,并在高电平触发时停止计时。可以使用Timer1模块来实现这一功能,具体代码如下:

void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void)
{
    IFS0bits.T1IF = 0; // 清除T1中断标志位
    
    if (PORTAbits.RA0 == 0) { // 如果中断引脚为低电平
        TMR1 = 0; // 重置计数器
        T1CONbits.TON = 1; // 开始计时
    } else {
        T1CONbits.TON = 0; // 停止计时
    }
}

然后在主程序中添加一个变量来保存计时器的值,每次执行中断处理程序时更新该值。可以在主循环中检查该变量的值,并根据阈值进行比较,以判断是否为有效中断。

int interrupt_time = 0;

while (1) {
    if (T1CONbits.TON == 1) {
        interrupt_time = TMR1;
    } else {
        interrupt_time = 0;
    }
    
    if (interrupt_time > 10000) {
        // 执行有效中断处理程序
    }
}
  1. 使用占空比功能过滤中断信号:

您可以利用定时器模块中的输入捕获功能来实现占空比的测量。首先需要配置定时器模块,将其设置为输入捕获模式,并连接到中断引脚。当中断引脚上出现一个脉冲信号时,定时器会自动记录下当前计数器的值,从而获取信号的高电平和低电平时间长度。然后可以根据占空比的计算公式计算出占空比值,并与设定阈值进行比较,以判断是否为有效中断。

示例代码如下:

void __attribute__((interrupt, no_auto_psv)) _IC1Interrupt(void)
{
    IFS0bits.IC1IF = 0; // 清除IC1中断标志位
    
    if (IC1CONbits.ICBNE == 1) {
        int ic1buf = IC1BUF;
        int high_time = ic1buf - last_buf;
        int low_time = PR2 - ic1buf;
        int duty_cycle = high_time * 100 / (high_time + low_time); // 计算占空比
        
        if (duty_cycle > 50) {
            // 执行有效中断处理程序
        }
        
        last_buf = ic1buf; // 更新缓存
    }
}

其中last_buf为缓存变量,用于记录上次捕获

如有用的话,还望采纳一下哦~

不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

首先,您可以尝试使用外部中断的上升沿或下降沿触发模式,而不是高电平触发模式。这样,只有在干簧管输出低电平时才会产生中断,从而避免了您遇到的问题。在PIC24中,可以通过INTCON2寄存器的INTEDGx位来设置中断的触发模式。

其次,如果您希望在中断发生后检测低电平持续的时间,可以使用定时器模块来测量低电平持续的时间。您可以使用定时器模块的外部时钟源,将其连接到干簧管的输出引脚上。然后在中断服务程序中,读取定时器计数器的值,计算低电平持续的时间。如果低电平持续时间超过您设定的阈值,则处理该中断,否则忽略该中断。

至于占空比控制,可以通过定时器模块的PWM功能来实现。在PWM模式下,定时器会以一定的频率产生方波信号,可以通过调节占空比来控制输出信号的高低电平时间比例。您可以将干簧管的输出引脚连接到PWM输出引脚上,通过调节占空比来控制干簧管输出的低电平持续时间。具体实现细节可以参考PIC24的数据手册和应用笔记。

首先,需要明确一点,PIC单片机的中断是有用中断和无用中断之分的。有用中断是指在程序执行过程中,中断请求的处理是必须的,否则程序无法正常运行。而无用中断则是指在程序执行过程中,中断请求的处理是可选的,不处理也不会影响程序的正常运行。
对于本问题中的干簧管中断源,可以通过以下步骤进行判断和过滤:
1. 判断中断源是否为有用中断。根据问题描述,干簧管中断源的作用是唤醒CPU,因此可以认为这是一个有用中断。如果确认为无用中断,则可以直接忽略该中断请求。
2. 判断中断源的触发条件。根据问题描述,每次进入休眠状态后,都会产生一个1500us的低电平,因此可以认为这是中断源的触发条件。如果需要过滤掉这个触发条件,可以在程序中加入相应的判断逻辑,只有当低电平时间超过10ms以上才认为是一个正常的中断。
3. 使用占空比功能进行过滤。占空比是指信号的高电平时间与周期时间的比值,可以用来判断信号的稳定性。如果干簧管中断源的信号不稳定,可以使用占空比功能进行过滤。具体操作方法可以参考PIC单片机的相关文档和资料。
总之,对于PIC单片机的中断处理,需要根据具体情况进行判断和过滤,以确保程序的正常运行。同时,需要注意中断的优先级和中断处理程序的编写,以避免出现死锁等问题。

外部中断可以对中断引脚用示波器调试
内部中断可以看中断表