Convert 24-bit ADC serial read data from 3-byte format to signed integer (int32)
23 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
I am receiving EEG data from a 24 bit ADC over serial. The ADC data is transmitting in 3 bytes from MSB to LSB. The full packet is 21 bytes:
- The first byte is the start byte - 0xFF (255 in decimal)
- Then packet number byte.
- Then the next 3 bytes are the 24 bit ADC value broken into MSB LSB2 LSB1
I can parse the data fine, but re-constructing a 2's complement signed int32 number is causing issues. The values I am getting out certainly don't reflect what the ADC should be giving out.
Below are the lines to read and parse the 504 samples (which gives me 24 ADC values (504samples/21bytes = 24 values)). I have tried uint8 instead of uchar with similar results (when I try int8 I get a invalid specified precision error).
comEEGSMT = serial(com,'BaudRate',3000000);
fopen(comEEGSMT);
rawData(1:504) = fread(comEEGSMT, 504, 'uchar');
fclose(comEEGSMT);
startPackets = find(rawData == 255);
bytes = rawData([startpackets+2 startpackets+3 startpackets+4]);
I have tried the following method to reconstruct the value:
ADC_value = bytes(:,1)*256^2 + bytes(:,2)*256 + bytes(:,3);
and the following line is the formula to convert the above number to volts:
ADC_value_volts = ADC_value*(5/3)*(1/(2^32));
The values are in the range of 4000 - 8000 microvolts with large jumps in value. The values SHOULD be in the range of 200 - 600 microvolts with small changes.
I have found other questions relating to similar issues, but have had no success trying the proposed solutions such as in the link below: https://uk.mathworks.com/matlabcentral/answers/137965-concatenate-3-bytes-array-of-real-time-serial-data-into-single-precision
Any help would be very much appreciated as I've been stuck on this for quite long.
Thanks Mark
0 Kommentare
Antworten (2)
Jan
am 6 Dez. 2016
Isn't this insecure:
startPackets = find(rawData == 255);
What happens, if a 255 appears in the data?
This replies the wrong order, as far as I can see:
bytes = rawData([startpackets+2 startpackets+3 startpackets+4]);
Try:
ADC_value = rawData(startpackets+2)*256^2 + rawData(startpackets+3)*256 + ...
rawData(startpackets+4);
6 Kommentare
Jan
am 9 Dez. 2016
Perhaps:
ADC_value = typecast(uint32(rawData(startpackets+2)*16777216 + ...
rawData(startpackets+3)*131072 + ...
rawData(startpackets+4)*1024), 'int32');
David Mellinger
am 29 Jun. 2023
Bearbeitet: David Mellinger
am 29 Jun. 2023
There's an additional problem if the file has signed 3-byte numbers. After a LOT of trial and error, I ended up doing it like this.
ch = fread(fp, [3 n], 'uint8'); % n is the number of data values to read
val = int32(ch(3,:)*2^16 + ch(2,:)*2^8 + ch(1,:));
ix = (ch(3,:) >= 0x80); % indices of negative values
val(ix) = typecast(bitor(val(ix), -(2^24)), 'int32');
This is for little-endian data in the file (fp) being read from. For big-endian data, which the person asking the question has, use this:
ch = fread(fp, [3 n], 'uint8'); % n is the number of data values to read
val = int32(ch(1,:)*2^16 + ch(2,:)*2^8 + ch(3,:));
ix = (ch(1,:) >= 0x80); % indices of negative values
val(ix) = typecast(bitor(val(ix), -(2^24)), 'int32');
0 Kommentare
Siehe auch
Kategorien
Mehr zu Parametric Spectral Estimation finden Sie in Help Center und File Exchange
Produkte
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!