我正在编写一些代码来记录来自多个传感器的电压测量值。我将所有数据保存在自定义数据结构中,然后在发生太多事件或用户请求数据时将数据结构打印到终端。我发现的问题是,当我调用DataDump函数时,每个事件中的最后一个数据值都是完全错误的。如果我在录制后立即尝试打印数据,那么它是正确的。我已经把我认为重要的代码spinets放在下面了,但这里有一个指向整个程序http://pastebin.com/Y7kcntu3的链接。
我唯一想到的是,当我为200个事件分配内存时,结构的范围不会扩展到dumpData函数。但这并没有多大意义,因为所有其他数据都存在且正确。我的另一个想法是,从char-> Binary->十进制转换时存在一个错误,但是再次只有单个值是错误的。
第一块代码是我创建的用于处理来自多个传感器的数据的数据结构。数据只是来自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])
来自主“loop()”代码。我试过从数据转储函数运行相同的代码,但我仍然得到垃圾。我还使用逻辑分析仪监控SPI线,我在数据线上看到了数据。
**我唯一想到的是,当我为200个事件分配内存时,结构的范围不会扩展到dumpData函数。但这并不合理,因为所有其他数据都存在。 **
答案 0 :(得分:1)
我一开始并没有意识到这一点,但是一旦你回答了我的问题,它就会像拇指一样疼痛。
如果SENSORS
等于3,则unsigned char data[SENSORS];
是包含三个元素的数组。不是你期望的四个。
数组与基于零的索引(0,1,2,3,...)一起使用,但是当你声明它们时,你需要输入所需元素的实际数量。
要修复,我将SENSORS
等于4,然后调整循环以从零开始,到小于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;
}
由于没有涉及索引,您将始终使用实际的元素数。远程循环最初可能非常混乱,但非常有用。
修复SENSORS
和MAX_DATA
的使用可能无法解决所有问题,但要解决这个问题,如果问题仍然存在,我们可以查看剩下的问题。如果有更多问题,请在下面的评论中留下一些信息,我会更新我的答案。