在工作中使用的PIC24单片机,外部有一个干簧管作为中断源,3.3V拉高,目的是在休眠中通过干簧管产生的低电平唤醒CPU。
但是在使用过程中发现在这个管脚上,只要一进入休眠就会产生一个1500us的低电平,然后把CPU从休眠状态中拉出来了,每次都是。
花了很长时间来找这个低电平是怎么产生的,实在是不好找在哪里
想请问一下各位同行,这个中断源可以设置时间吗,设置成这个中断发生后,判断低电平时间超过10ms以上才算是一个正常的中断,可接受
然后,听说有占空比这个功能可以实现,但是我从来也没用过,不知道怎么用,希望能给予帮助
基于最新版ChatGPT4的回答,望采纳!!!有其他问题也可以询问我哦、”(最新版更智能,功能更加强大)
要实现这个功能,你可以使用一个定时器来判断低电平的持续时间。当外部中断触发时,启动定时器并在中断结束时停止定时器。然后根据定时器的计数值判断低电平持续时间是否超过10ms。下面是一个简化的实现示例:
void init(void) {
// 配置外部中断
configureExternalInterrupt();
// 配置定时器
configureTimer();
}
void configureExternalInterrupt(void) {
// 以下代码仅作为示例,具体配置取决于你的硬件和需求
_INT0IE = 0; // 关闭INT0中断
_INT0IF = 0; // 清除INT0中断标志
INTCON2bits.INT0EP = 0; // 配置INT0为负边沿触发
_INT0IE = 1; // 使能INT0中断
}
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中断
}
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 / 256 ≈ 156
void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void) {
_T1IF = 0; // 清除定时器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)。
对于你的问题,可以基于轮询中断的方式进行判断和过滤。具体步骤如下:
设置干簧管对应的IO口为输入模式,等待干簧管输出低电平。
进入休眠模式并设定唤醒模式为引脚变化唤醒模式。
当休眠模式被唤醒时,检测IO口的状态,如果是低电平,则进行下一步;否则返回第1步。
使用定时器,在一定时间内检测IO口的状态。如果在设定的时间内IO口仍然是低电平,则触发中断,并将中断状态置为未处理;否则返回第1步。
在中断处理程序中,检测中断状态是否未处理,如果是,则进行下一步;否则返回第1步。
将中断状态置为已处理,并执行相应的处理操作。
对于这个中断源可以设置时间的问题,可以通过占空比的方式进行实现。具体步骤如下:
设置定时器的工作模式为占空比测量模式。定时器会在每次输入的PWM波形的周期结束时,自动将占空比计算出并保存在寄存器中。
将干簧管作为PWM的输入信号,将占空比设定为一定的值,比如50%。
进入休眠模式并设定唤醒模式为引脚变化唤醒模式。
当休眠模式被唤醒时,检测IO口的状态,如果是低电平,则进行下一步;否则返回第3步。
在一定时间内,检测定时器中保存的占空比是否满足要求。如果满足,则触发中断,并将中断状态置为未处理;否则返回第3步。
在中断处理程序中,检测中断状态是否未处理,如果是,则进行下一步;否则返回第3步。
将中断状态置为已处理,并执行相应的处理操作。
以下是示例代码:
#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安生共同编写:
针对您的问题,可以考虑以下几个步骤来判断和过滤PIC单片机的无用中断:
下面是一些具体的实现细节:
首先需要配置定时器模块,选择一个计时器,使其在中断引脚低电平触发时开始计时,并在高电平触发时停止计时。可以使用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) {
// 执行有效中断处理程序
}
}
您可以利用定时器模块中的输入捕获功能来实现占空比的测量。首先需要配置定时器模块,将其设置为输入捕获模式,并连接到中断引脚。当中断引脚上出现一个脉冲信号时,定时器会自动记录下当前计数器的值,从而获取信号的高电平和低电平时间长度。然后可以根据占空比的计算公式计算出占空比值,并与设定阈值进行比较,以判断是否为有效中断。
示例代码如下:
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单片机的中断是有用中断和无用中断之分的。有用中断是指在程序执行过程中,中断请求的处理是必须的,否则程序无法正常运行。而无用中断则是指在程序执行过程中,中断请求的处理是可选的,不处理也不会影响程序的正常运行。外部中断可以对中断引脚用示波器调试
内部中断可以看中断表