12363浏览
查看: 12363|回复: 3

[常见问题] Arduino外部中断使用问题,求助

[复制链接]
本帖最后由 lilin16821 于 2014-7-1 17:41 编辑

采用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();
}


Youyou  初级技匠

发表于 2014-7-3 13:01:53

中断程序里面不要放print之类的语句,也就是不要进行复杂的操作,不然很容易会卡死的,一般在中断程序里面设定标志位,然后在主程序里面进行判断,再进行相应的操作。因此,按照你的程序,很容易出现卡死等状况。
回复

使用道具 举报

lilin16821  见习技师
 楼主|

发表于 2014-7-5 00:26:51

Youyou 发表于 2014-7-3 13:01
中断程序里面不要放print之类的语句,也就是不要进行复杂的操作,不然很容易会卡死的,一般在中断程序里面 ...

如果中断中只是设置标志位,在我看来中断的意义就不是特别大了,因为对标志位的判读还是要在主循环中进行,不一定能实现及时处理。
回复

使用道具 举报

Angelo  初级技匠

发表于 2014-7-6 21:06:47

本帖最后由 Angelo 于 2014-7-6 21:13 编辑

具体的原因是这个:
Serial串口的类里面有个用于发送的BUFFER,这个BUFFER大小是有限的。
当在运行Serial.print函数的时候,会做一个判断:如果发现Buffer已经满了,程序就会挂死在那边,等待串口发送完数据。
这时就有很痛苦的事情发生了,串口发送数据是基于中断的,它会在中断服务程序中读取Buffer中的值然后发送,
但是此时Serial.print却在中段中挂死了,串口中断服务程序无法进入,于是再也不会发送数据,程序就卡在那里了

其实不用设置标志位也可以,但是最好不要在中断中使用串口发送数据,毕竟串口发送只是调试的目的,实时性不需要很高。
可以读完RTC之后在主程序里面使用串口。


或者可以直接黑掉Serial.write函数,当发现buffer满了,直接return,但是这样就会丢失数据,不太推荐

回复

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies |上传

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail