2017-11-11 109 views
0

我有一个Arduino Mega应用程序,我可以在各种占空比下读取低频脉冲(约10Hz)的时序。
我使用外部中断捕捉脉冲,将信号更改时间信息添加到我完成时读回的16位数组[320]中。
我通过将第一个上行更改的时间设置为时间0来标准化时间。 请参阅附加简化代码段(使用Arduino Mega进行工作测试,引脚D2)。
问题:复位后的第一个完整周期按预期读取时序,而每个后续周期只有第一个脉冲正常,而所有下一个脉冲的时序随机移动
我已经测试过,并尝试了很多选项,包括volatile和只在变化上中断,但总是得到相同的结果:第一次运行是OK,下一次运行被移位。
任何想法将不胜感激。ATMega AVR外部中断

/*Program reads input pulses at D2 and builds timing array of the up and 
    down going signals, using change interrupts on pin D2 of Mega 
    To run, send array size in hex. 
    by Sam Tal [email protected] Nov 9, 2017 
    */ 
    #define interruptPin 2 
    unsigned int dataArraySize; 
    unsigned int timeData[320]; 
    volatile byte state = LOW; 
    unsigned int counts = 0 ;  //Changes counter 
    unsigned long startTime;  //The first up going interrupt time. 
    //========================================================== 
    void setup() 
    { 
     Serial.begin(115200); 
     pinMode(interruptPin, INPUT); 
    } 
    //========================================================= 
    void loop() 
    { 
     if (Serial.available()) 
     { 
     dataArraySize = Serial.read(); 
     StartCycle(); 
     } 
    } 
    //======================================================== 
    void StartCycle(void) 
    { 
     Serial.println("Starting cycle..."); 
     //Reset the time array; 
     memset (timeData, 0, dataArraySize); 
     counts = 0 ; 
     state = LOW; 
     attachInterrupt(digitalPinToInterrupt(interruptPin), Step, RISING); 
    } 

    //======================================================== 
    void Step() 
    { 
     detachInterrupt (digitalPinToInterrupt (interruptPin)); 
     if (counts == 0) 
     { 
     startTime = millis(); // Start time of the first rising change. 
     } 
     if (counts < dataArraySize) 
     { 
     timeData[counts] = millis() - startTime ; 
     counts++; 
     attachInterrupt(digitalPinToInterrupt(interruptPin), Step, CHANGE); 
     } 
     else 
     { 
     detachInterrupt (digitalPinToInterrupt (interruptPin)); 
     SendData(timeData, dataArraySize); 
     } 
    } 
    //=========================================================== 
    void SendData(unsigned int data[] , unsigned int arraysize) 
    { 
     int f; 
     for (f = 0; f < arraysize ; f++) 
     { 
     Serial.print(f); 
     Serial.print(",") ; 
     Serial.println(data[f]); 
     } 
    } 
+0

Simillar to @aMike我也会从我个人的经验中推荐不要在中断处理程序中使用Serial.print()。通常,串行打印语句需要几毫秒才能执行。所以如果你运行时间约束算法,不要在中断处理程序中打印。 – Sma

+0

在这种情况下,中断处理程序(ISR)是Step()函数。该功能内没有打印。此外,每次输入ISR时都会禁止中断。 为什么你声称在ISR中有打印命令? – samtal

回答

0

memset()调用处理字节,但您给它一个双字节整数的计数。所以,它不会清除整个缓冲区。通常我们这样做:

memset(buf, 0, sizeof(buf)); 

我也害怕中断处理程序中的Serial.print()。也许在那里设置一个标志,然后从loop()调用Send()来代替。

+0

Thx aMike。我按照你的建议更正了memset,但没想到它会纠正这个问题,因为新数据总是覆盖旧的数据。至于Serial.print() - 处理程序中没有任何内容(void Step())。 我仍然对这个现象感到困惑。 – samtal

+0

我同意你的memset评论;它不应该重要;我想也许它是在收集之前存在的旧数据。但是'Step()'调用'SendData()',**不会调用'Serial.print',这可能会占用很多时间并导致您错过输入转换......也许? :-) – aMike