2016-06-17 194 views
1

我正在寫一些代碼來記錄來自多個傳感器的電壓測量值,通過SPI。我將所有數據保存在自定義數據結構中,然後在發生太多事件或用戶請求數據時將數據結構打印到終端。我發現的問題是,當我調用DataDump函數時,每個事件中的最後一個數據值是完全錯誤的。如果我在錄製後立即嘗試打印數據,它是正確的。我已經把我認爲是重要的代碼下面,但這裏是一個鏈接到整個程序http://pastebin.com/Y7kcntu3打印垃圾

我唯一想到的是,當我爲200個事件分配內存時,結構的範圍並未擴展到dumpData函數。但這並沒有什麼意義,因爲所有其他數據都是正確的。我的另一個想法是,從char-> Binary-> decimal轉換時存在一個錯誤,但只有單個值是錯誤的。

這第一塊代碼是我爲處理來自多個傳感器的數據而創建的數據結構。數據只是來自ADC的8位SPI數據,因此我使用無符號字符來最大限度地減少使用的內存量。我還爲200個事件分配了足夠的內存。

typedef struct    //event structure, containts a timestamp element and an array of 18 data points 
{ 
    unsigned long int timeStamp; 
    unsigned char data[SENSORS]; 
} Event; 

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 

Event eventLog[MAX_DATA];  //an array of structures representing 200 events, once the 200 events have been filled the data will be printed 

在Main「loop()」中,當引腳爲高電平時,會有數據收集過程。當偶發生時,第一個事件數據結構將記錄時間戳,然後是開始模數轉換並將數據存儲在當前事件的數據陣列中的過程。

eventLog[i].timeStamp = micros(); 

    for (j=0; j<=SENSORS; ++j) { 
     lockAndPop();       //lock digital value and reset conversion 
     selector = inputSelector(selector);  //increment the selector pin 
     PORTA = selector; 
     digitalWrite(RD, LOW);    //Start new conversion 

     digitalWrite(CLK_INH, LOW);    //Start the data transfer 
     eventLog[i].data[j] = SPI.transfer(0);  //read a single byte from the SPI line 
     digitalWrite(CLK_INH, HIGH);    //Inhibit clock 
     digitalWrite(LD, LOW); 
     while(digitalRead(INT1)){}    //wait for previous conversion to end    
     } 
    i++; 

數據轉儲函數被調用在兩種情況下,當200級的事件已經發生的第一個,使秒針是當外部按鈕被去按壓。該功能將創建一個打印緩衝區,以便事件數據可以格式化並以十進制值顯示。數據值從二進制轉換爲十進制而非ASCII。

void dataDump(){ 
    char buf[100], *pos = buf; //create a buffer of 100 charaters, anda pointer to the begining of that buffer 
    char *base = buf;    //create a base address to reset the buffer 
    unsigned char eventCount = i;    //how many events occured before dump command was called 
    unsigned char localCount;  
    unsigned char localData; 
    Serial.begin(115200); 
    for (localCount = 0; localCount<=eventCount; ++localCount){ 
    pos += sprintf(pos, "%lu", eventLog[localCount].timeStamp);   //sprintf will append the data to the pointer "pos", and return the number of byte append. 
    for (localData = 0; localData<=SENSORS; ++localData){ 
     pos += sprintf(pos, " %d", (unsigned int)(eventLog[localCount].data[localData])); 
    } 
    Serial.println(buf); 
    pos = base; 
    } 
    i=0; 
    j=0; 
    Serial.end(); 
    return; 

我面臨的問題是,當數據轉儲函數被調用,一切都打印精細除數組中的最後一個數據值。這裏是一個例子,打印什麼

539580840 171 149 120 152 
539581080 170 149 119 216 
539581912 170 149 120 196 
539582148 170 149 120 180 
539582388 170 149 120 168 
539582632 170 149 119 148 
539582868 170 148 119 128 
539583104 170 149 119 216 
539583704 170 149 120 196 
539583940 170 149 120 176 
539584176 170 149 120 160 
539584416 170 149 120 148 
539584660 170 149 120 128 
539584896 170 149 120 112 
539585136 170 149 120 92 
539585372 170 149 119 80 
539585616 170 149 120 60 
539585852 170 149 119 59 

最後一個值應該像它之前的三個一樣,因爲ADC正在讀取參考電壓。該數據在打印時是完全有效的

Serial.println(eventLog[i].data[3]) 

來自主「循環()」代碼。我試圖從數據轉儲功能運行相同的代碼,但我仍然得到垃圾。此外,我還使用邏輯分析儀監測SPI線路,並看到數據線上的數據。

**我只想到這可能是當我爲200個事件分配內存時,結構的範圍不會擴展到dumpData函數。但這並沒有什麼意義,因爲所有其他數據都存在。 **

+0

你在用什麼板子? SENSORS的價值是什麼? –

+0

傳感器= 3,所以我期望4個讀數。我正在使用一個大型的2560 – Lpaulson

回答

1

我一開始並沒有意識到,但是一旦你回答了我的問題,它就像拇指一樣突然出現。

如果SENSORS等於三,那麼unsigned char data[SENSORS];是一個由三個元素組成的數組。不是你所期待的。

數組與基於零的索引(0,1,2,3,...)一起使用,但是當您聲明它們時,需要將所需元素的實際數量。

要解決,我會使SENSORS等於四,然後調整您的循環從零到小於SENSORS(不小於或等於)。 MAX_DATA也是如此。你的循環使用的是比你實際擁有的更多的元素。

除非你需要一個索引,否則C++ 11有一個功能可以防止數組溢出。它是ranged-for循環。

您現在正在使用的循環:

for (localCount = 0; localCount<=eventCount; ++localCount){ 
    pos += sprintf(pos, "%lu", eventLog[localCount].timeStamp);   //sprintf will append the data to the pointer "pos", and return the number of byte append. 
    for (localData = 0; localData<=SENSORS; ++localData){ 
    pos += sprintf(pos, " %d", (unsigned int)(eventLog[localCount].data[localData])); 
    } 
    Serial.println(buf); 
    pos = base; 
} 

能成爲這樣的:

for(auto &entry : eventLog){ 
    pos += sprintf(pos, "%lu", entry.timeStamp); 
    for(char reading : entry.data){ 
    pos += sprintf(pos, " %d", (unsigned int)reading); 
    } 
    Serial.println(buf); 
    pos = base; 
} 

由於沒有涉及指數,你總是會使用元素的實際數量。首先,遠程循環可能相當混亂,但非常有用。

修復SENSORSMAX_DATA的使用可能無法解決所有問題,但是修復方法是,如果問題仍然存在,那麼我們可以查看其餘問題。如果還有更多問題,請在下面的評論中留下一些信息,我會更新我的答案。

+0

因此,如果我在寫入eventLog [i] .data [3]時正確理解這一點,我很可能會寫入eventLog [i + 1] .timeStamp的地址。這就是爲什麼當我嘗試打印eventLog [i] .data [3]時,它會工作,但下一次迭代會將數據寫入下一個事件的timeStamp?我會給它一個鏡頭,讓你知道。 – Lpaulson

+0

是的,這是正確的。 –

+0

現貨!我會一直在尋找那一個。 – Lpaulson