Arduino外部中断使用问题,求助

2014-07-011.4万
AI 快速预览详细 收起
本文讨论了使用Arduino UNO进行温湿度采集并控制继电器的应用中遇到的外部中断问题。通过具体代码分析,发现中断处理函数中执行复杂的I2C读取操作会导致程序死机。建议简化中断处理函数,仅执行简单的串口打印和计数器更新。文章还提供了详细的故障排查方法,帮助用户解决中断处理中的常见问题,确保系统的稳定运行。


采用Arduino UNO制作一个温湿度采集并按照一定逻辑控制外部继电器动作的应用,采集到的温湿度要保存到本地的TF卡上,同时要上传至网络。

因为需要时间戳,所以增加了SD2405时钟模块,考虑到SD2405有比较灵活的中断输出,可以给主控板UNO提供稳定的外部中断,于是决定用中断来控制采样的上传,比如每间隔5分钟采用上传一次。

SD2405提供时钟查询和中断脉冲,中断信号接到了Arduino的D2口,并且编写了中断处理函数int0_ISR()
setup()中挂接了中断处理:attachInterrupt(0,int0_ISR,FALLING);(中断号0,下降沿触发)
目前还没有实际去接传感器,为测试中断工作在loop()中,每隔1秒去取时钟信息并串口打印,中断处理函数如果也去取时钟信息,运行必死。
后来简化处理,中断中只是串口打印中断次数计数器值,并且随意取了两个模拟口的值(没有接设备,值应该是随机的),此时,程序可以运行,但是跑不了几个中断就会死掉。
请教:外部中断应该怎么用,我的问题在哪里?
代码如下:
#include <Wire.h>        

#define RTC_Address   0x32  //RTC_Address

unsigned char   date[7];
unsigned int intNum = 0;

void int0_ISR(void)
{
  digitalWrite(13, HIGH);
    Serial.print("IntNum: ");
    Serial.print(intNum++);
    Serial.println("   Int......");

    Serial.print("A0 ");
    Serial.println(analogRead(0));
    Serial.print("A1 ");
    Serial.println(analogRead(1));

    //Read time from SD2405 and show in serial
    //I2CReadDate();
    //Data_process();
    //如果上面两句不注释掉,必死机。
}

void setup()
{

  Wire.begin();  //Open I2C as maste
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  Serial.println("Start...");

  attachInterrupt(0,int0_ISR,FALLING);
}

void loop()
{
    I2CReadDate(); //Read time
    Data_process(); //Show time
    delay(1000);

}

//Read the Real-time data register of SD2405
void I2CReadDate(void)
{
  unsigned char n=0;

  Wire.requestFrom(RTC_Address,7);
  while(Wire.available())
  {  
    date[n++]=Wire.read();
  }
  delayMicroseconds(1);
  Wire.endTransmission();
}

//Process the time_data
void Data_process(void)
{
  unsigned char i;

  for(i=0;i<7;i++)
  {
    if(i!=2)
      date=(((date&0xf0)>>4)*10)+(date&0x0f);
    else
    {
      date[2]=(date[2]&0x7f);
      date[2]=(((date[2]&0xf0)>>4)*10)+(date[2]&0x0f);
    }
  }
  // Use the serial monitor to see information being transmitted   

  Serial.print("Sec = ");//second
  Serial.print(date[0]);
  Serial.print("   Min = ");//minute
  Serial.print(date[1]);
  Serial.print("   H = ");//hour
  Serial.print(date[2]);
  Serial.print("   W = ");//week
  Serial.print(date[3]);
  Serial.print("   D = ");//day
  Serial.print(date[4]);
  Serial.print("   M = ");//month
  Serial.print(date[5]);
  Serial.print("   Y = ");//year
  Serial.print(date[6]);

  Serial.println();
}


创作许可协议

本项目采用 None(不开放任何权利,保留所有权利) 进行许可。

评论(2)
Angleo
Angleo
具体的原因是这个:
Serial串口的类里面有个用于发送的BUFFER,这个BUFFER大小是有限的。
当在运行Serial.print函数的时候,会做一个判断:如果发现Buffer已经满了,程序就会挂死在那边,等待串口发送完数据。
这时就有很痛苦的事情发生了,串口发送数据是基于中断的,它会在中断服务程序中读取Buffer中的值然后发送,
但是此时Serial.print却在中段中挂死了,串口中断服务程序无法进入,于是再也不会发送数据,程序就卡在那里了
其实不用设置标志位也可以,但是最好不要在中断中使用串口发送数据,毕竟串口发送只是调试的目的,实时性不需要很高。
可以读完RTC之后在主程序里面使用串口。
或者可以直接黑掉Serial.write函数,当发现buffer满了,直接return,但是这样就会丢失数据,不太推荐
Youyou
Youyou
中断程序里面不要放print之类的语句,也就是不要进行复杂的操作,不然很容易会卡死的,一般在中断程序里面设定标志位,然后在主程序里面进行判断,再进行相应的操作。因此,按照你的程序,很容易出现卡死等状况。
lilin16821
lilin16821
作者
回复Youyou
如果中断中只是设置标志位,在我看来中断的意义就不是特别大了,因为对标志位的判读还是要在主循环中进行,不一定能实现及时处理。
- 没有更多了 -