Hello All,
I am new to arduino and coding and I have had some help from people on this forum already and i am very grateful, so here is an outline of my project so far:
I have a geiger counter that has a port on the side that outputs RS232-esque data (not true RS232) giving information about device name, dose rate and units of measurement. I am attempting to make a data logger that will take this data, convert it into a readable format, add GPS and log it to an SD card as a CSV for later review on a laptop and mapping software.
My plan is to
-
get the meter communicating with the arduino correctly and displaying in the serial monitor (achieved with software serial)
-
get the data from the meter decoding correctly into human readable format in the serial monitor (not achieved!)
-
get a GPS module and attaching the GPS data to the data received from the geiger counter (no where near achieved!)
-
get the whole lot logging to an SD card as a CSV comma file that can be opened in excel, or google maps etc
The manufacturer has been helpful and given me data and details on the device. So far i have been helped to get the data displaying on the serial monitor correctly, as raw data. The thread is here Serial Data received from Commercial Geiger Counter - feasible arduino logger? - Project Guidance - Arduino Forum
The code used to do this is below
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3, true); // RX, TX, invert signal //connect Automess GND and TERM to GND and Pin 2 - RS232 - TTL Converter not needed
const unsigned long delayBetweenPackets = 1000u; //packet spacing in milliSeconds
const byte bytesInPacket = 5;
byte receivedBytes[bytesInPacket]; //changed data type to byte from char as byte is unsigned integer
boolean newData = false;
void setup() {
Serial.begin(9600); //arduino to IDE monitor can be different baud rate than automess to arduino
mySerial.begin(4800);
Serial.println("<Automess Ready>");
}
void loop() {
recvWithStartMarker();
showNewData();
}
void recvWithStartMarker() {
static unsigned long lastByteReceived = 0;
unsigned long currentByteReceived;
static boolean recvInProgress = false;
static byte ndx = 0;
byte startMarker = 0x02;// ASCII STX Start of Text
byte rb;
while (mySerial.available() > 0 && newData == false) {
rb = mySerial.read();
currentByteReceived = millis();
if ((currentByteReceived - lastByteReceived) > (delayBetweenPackets / 2)) {
//resync input if packet is not completed within allotted time
recvInProgress = false;
ndx = 0;
}
if (recvInProgress == true) {
receivedBytes[ndx] = rb;
ndx++;
if (ndx == bytesInPacket) {
recvInProgress = false;
ndx = 0;
byte checksum = 0;
for (byte i = 0; i < bytesInPacket; i++) {
checksum ^= receivedBytes[i];
}
if (checksum == 0) {
newData = true;
Serial.println(F("Receiving"));
} else {
Serial.println(F("Checksum Error"));
}
}
} else {
if (rb == startMarker) {
recvInProgress = true;
}
}
lastByteReceived = currentByteReceived;
}
}
void showNewData() {
if (newData == true) {
Serial.print(F("Data Received:"));
for (byte i = 0; i < bytesInPacket; i++) {
Serial.print(' ');
Serial.print((receivedBytes[i] >> 4) & 0x0F, HEX);
Serial.print(receivedBytes[i] & 0x0F, HEX);
}
Serial.println();
newData = false;
}
}
which works really well for displaying the correct format of data, in terms of raw data, in the serial monitor.
I sent screen grabs to the manufacturer who confirmed that the data is being received correctly, and they sent me some QBASIC code so that the data could be decoded, this is the QBASIC code below
' Variable Types
DEFINT A-W
DEFSNG X-Z
' Constant Expressions
CONST STX = 2
CONST DEVERR = 57
'---------------------------------------------------------------------
'Main Program '---------------------------------------------------------------------
' Open COM: 4800 Bd, no parity, 8 data bits, 1 stop, no handshake ' OPEN "com1:4800,n,8,1,rs,cs,ds,cd" FOR INPUT AS #1
ON ERROR GOTO RecvErr
' Main Loop: read and decode string (6 characters including STX),
' display result, exit on any key.
MainLoop:
DO
WHILE ASC(INPUT$(1, #1)) <> STX: WEND 'wait for STX
sonde = ASC(INPUT$(1, #1)) 'type of detector/6150AD
bc = sonde
mantlo = ASC(INPUT$(1, #1)) 'low order mantissa
bc = bc XOR mantlo
manthi = ASC(INPUT$(1, #1)) 'high order mantissa
bc = bc XOR manthi
expon = ASC(INPUT$(1, #1)) 'exponent
bc = bc XOR expon
IF expon > 127 THEN expon = expon - 256
bc = bc XOR ASC(INPUT$(1, #1)) 'block check
IF bc <> 0 THEN ERROR DEVERR 'block check error
mant = manthi * 256 + mantlo '16 bit mantissa
xdl=mant*2 ^ (expon - 15) 'dose rate as floating point number
GOSUB GetProbe 'set ger$, det$ and unit$
PRINT TIME$; " Device: 6150"; ger$; " Detector: "; det$;
PRINT USING " Reading=########.### "; xdl;
PRINT unit$
LOOP WHILE LEN(INKEY$) = 0 'exit on any key
PRINT "End."
END
'---------------------------------------------------------------------
'set ger$ / det$ / unit$ according to 'sonde' '---------------------------------------------------------------------
GetProbe:
flag$ = ""
IF sonde >= 128 THEN flag$ = "/E": sonde = sonde - 128
ger$ = "AD2/4/6" + flag$
IF sonde >= 64 THEN ger$ = "AD1/3/5" + flag$: sonde = sonde - 64
det$ = "unknown"
unit$ = "μSv/h"
SELECT CASE sonde
CASE 0
det$ = "Probe AD-0"
unit$ = "cps"
CASE 7
det$ = "Probe AD-b"
CASE 15
det$ = "Probe AD-15"
CASE 17
det$ = "Probe AD-17"
unit$ = "cps"
CASE 18
det$ = "Probe AD-18"
CASE 19
det$ = "Probe AD-19"
unit$ = "cps"
CASE 20
det$ = "internal GM"
CASE 21
det$ = "AD-t low DR"
CASE 22
det$ = "AD-t high DR"
END SELECT
RETURN
' ---------------------------------------------------------------------
' Handler for transmission errors
' ---------------------------------------------------------------------
RecvErr:
IF ERR = DEVERR THEN PRINT TIME$; " Transmission Error": RESUME MainLoop
ON ERROR GOTO 0
A friend re-wrote it for me in C (as thats beyond me), see below
void AutomessHandler(char* AMSTRING){
int MHI, MLO;
double MANT,DL, EXP1;
//float EXP1 ;
// Data From Automess.
MLO = AMSTRING[2] ;
MHI = AMstring[3] ;
EXP1 = AMstring[4];
DL = 0;
MANT = 0;
Check = 0;
ChecksumGood = 0;
if(EXP1 > 127){
EXP1 = EXP1 - 256;
}
MANT = (MHI * 256) + MLO;
EXP1 = EXP1 - 15;
DL = MANT * pow(2.0,EXP1);
AUTOMESSUSV = DL;
for(i=0;i<4;i++){
Check = Check ^ AMSTRING[1+i]; //EXOR up all bytes
}
if(check == AMSTRING[5]){ //Compare to Checksum
Checksumgood = 1;
}
}
So my issue is i have no idea how to incorporate the code to decode the raw data from the geiger counter into the sketch that displays the raw data on the serial monitor so that i can read in clear text the output from the geiger counter. I would really appreciate any help. I have tried following guides on designing sketches, writing C and so on but am unsure how to proceed....
I have also attached a file that lists the manufacturers communication protocols, in case thats of use.
thank you for reading
Ed
ADBUCHSE.pdf (132 KB)