I'm playing around with some code where I read incoming data from an digital level which is all working great and receives all the data.
But What I would like or trying to convert this data if possible to HEX format like this RAW BUFF: [ XX XX XX XX 0C 36 ], Where the last 2 hex values contain say this value 32.70 (without the decimal point), so i could send the data to an M5 Stack unit that running code that receives the data via Bluetooth coming from the OWON B35 meter so I can just use the one unit as a display fro the both. I may be able then to work out send the decimal and +/- sign which is contained in the other bits.
This is my code, I've tried to convert to float/int using atof/atoi but the value remains 0
/*********
#### TX CODE ####
Wireless SPI-TRONIC Pro 3600 Digital Protractor
General Information
The Pro 3600 has an ASCII-format RS-232 compatible serial port for remote angle readout.
The T&B Ansley 609-1027 connector on the back of the Pro3600 mates with industry
standard cables. Angles are calculated and transmitted every 8/15 second (533 msec)
Angle Output Format:
The ASCII angle output may be read by a computer, or may directly drive a printer. Measured
angles cover a full 360° range and the readout is between -180.00° and +180.00°.
Format:
<sign> XXX.XX <carriage return><line feed>
examples:
+ 124.50
+ 32.70
+ 9.38
- 4.32
- 179.9
[
RAW BUFF: [ XX XX XX XX C0 09 ]
*********/
#include <SoftwareSerial.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display
//##########################
//# SET UP VARIABLES #
//##########################
SoftwareSerial ESPserial(4, 3); // RX | TX
const byte numChars = 9; //Number of bits to get
char receivedChars[numChars];//store the value of incoming data
boolean newData = false;
unsigned long NO_Data_in = 0;
#define ECHO_TO_SERIAL 1//change to zero = no serial output
// constants won't change:
const long interval = 1000; // interval at which to blink (milliseconds)
//##########################
//# SET UP STRUCT FOR DATA #
//##########################
typedef struct Data_struct {
int PRO3600_Disconnected = 10;
boolean No_data;// = true;
char receivedChars[9];
} Data_struct;
Data_struct Data;
//###########################################
//# PRINT DATA TO SERIAL MONITOR IF ENABLED #
//###########################################
void printRecord(Print* pr, char sep = ',') {
// pr->print("0,1,2,3,4,5,6,7,8,"); // Print btye 0
// pr->println();
pr->print(Data.receivedChars[0]); // Print btye 0
pr->print(sep);
pr->print(Data.receivedChars[1]); // Print btye 1
pr->print(sep);
pr->print(Data.receivedChars[2] ); // Print btye 2
pr->print(sep);
pr->print(Data.receivedChars[3]); // Print btye 3
pr->print(sep);
pr->print(Data.receivedChars[4]); // Print btye 4
pr->print(sep);
pr->print(Data.receivedChars[5]); // Print btye 5
pr->print(sep);
pr->print(Data.receivedChars[6] ); // Print btye 6
pr->print(sep);
pr->print(Data.receivedChars[7]); // Print btye 7
pr->print(sep);
pr->print(Data.receivedChars[8]); // Print btye 7
pr->print(sep);
pr->print(Data.PRO3600_Disconnected);
pr->print(sep);
pr->print(Data.No_data); // PData.PRO3600_Disconnected
pr->println();
}
void setup() {
lcd.init();
lcd.backlight();
Serial.begin(115200);
ESPserial.begin(9600);
Serial.println("READY TO GO");
Serial.println("<Arduino is ready>");
}
void loop() {
recvWithEndMarker();
if (newData ) { //new data received from eLevel
newData = false;
Data.PRO3600_Disconnected = 10;
Data.No_data = true;
}
unsigned long currentMillis = millis();
if (currentMillis - NO_Data_in >= interval) { // one second is more than enough
// save the last time you blinked the LED
NO_Data_in = currentMillis;
Data.PRO3600_Disconnected = 20;
Data.No_data = false;
Data.receivedChars[0] = '0';
Data.receivedChars[2] = '0';
Data.receivedChars[3] = '.';
Data.receivedChars[4] = '0';
Data.receivedChars[5] = '0';
Data.receivedChars[6] = '0';
Data.receivedChars[7] = ' ';
Data.receivedChars[8] = ' ';
}
float dVal = atof(Data.receivedChars);
lcd.setCursor(0, 0);
lcd.print(Data.receivedChars[0]);
lcd.setCursor(1, 0);
lcd.print(Data.receivedChars[2]);
lcd.setCursor(2, 0);
lcd.print(Data.receivedChars[3]);
lcd.setCursor(3, 0);
lcd.print(Data.receivedChars[4]);
lcd.setCursor(4, 0);
lcd.print(Data.receivedChars[5]);
lcd.setCursor(5, 0);
lcd.print(Data.receivedChars[6]);
lcd.print(" ");
#if ECHO_TO_SERIAL // Send debug to serial port if enabled
printRecord(&Serial);
#endif //ECHO_TO_SERIAL
}
void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = '\n';
char rc;
if (ESPserial.available() > 0 && newData == false) { // Tried this
// while (gtSerial.available() > 0 && newData == false) { //tried this
NO_Data_in = millis();
rc = ESPserial.read();
if (rc != endMarker) {
Data.receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
Data.receivedChars[ndx] = '\0'; // terminate the string
ndx = 0;
newData = true;
// receiveUntilTimeout = true; //tried here
}
}
}
This is what is shown and been held in the Data.receivedChars variable.
on the SPI level it diaplys -15.74 and If I move it to the opssipte side it displays +15.74
Data.receivedChars[0] = holds the +/- sign
Data.receivedChars[1] = not needed
Data.receivedChars[2] = 1
Data.receivedChars[2] = 5
Data.receivedChars[3] = .
Data.receivedChars[5] = 7
Data.receivedChars[6] = 4
Hex Format output example is what I'm trying to do.(NC = no change)
0 1 2 3 4 5
NC NC . NC 15 74 (decimal)
23 F0 04 00 06 26 (output in hex format)
The 04 in the meter code is the decimal point place so this would not need to move.
So when I use a dec to hex calculator 1574 = 0626 and would like to send 0x06 and 0x26 has the receiver then converts this to a value
to display 1574 the decimal does not need to be moved but the receiver places it depending on the value of bit
Do I understand correct - you need first convert char array "15.74" to float and second convert the float to HEX 0x0626 ?
Where did you experienced problems?
First of all I'd like to say thank you for taking time to reply.
This would be the hex format I'd like to achieve.
The Data.receivedChars is where the incoming value is stored from the Mitutoyo pro3600 digital level. I would like to convert the Char value "-15.74" direct to HEX format like above. Not to worried about the +/- sign at the moment that can come after I've masted sending the hex value out just for the level reading
So this how I would like to send the HEX format 23 F0 04 00 06 26 so that it can be sent out
23 = NC value will not change
F0 = NC value will not change
04 = NC value will not change
00 = NC value will not change
06 = value will change depending on the angle of the digital level
26 = value will change depending on the angle of the digital level
15.74 is just an example of the reading in degrees.
Sorry, but it is not an answer to my last question in the message #7
How your float should be encoded - as a single number 1574 (0x0626 in hex) or as two - separately integer part 15 (0xf) and a fraction 74 (0x4a) ?
Your example presents a second variant.
sorry as two - separately hex bits to add to the other 4 bits of hex like the example.
The ASCII format comes in from the digital level like this Format: XXX.XX So I make that 9 as I use the line feed to detect the end of the incoming data and ready for the next lot coming in.
I have a OWON B35+ meter that I use and use the M5Stack in the link below to make it wireless https://github.com/reaper7/M5Stack_BLE_client_Owon_B35T
My idea is to use the same M5Stack unit to display my digital level data, So basically I'm trying duplicate the data format that the OWON 35 meter is sending out.
This is the example for the meter displaying 2.496V
[ 23 F0 04 00 C0 09 ] =so the reading wold be 2496
the hexadecimal values in the frame are swapped in the M5Stack and these two bytes do not contain information about the decimal place. the Decimal place is controlled by bit 2 (04) of the 6 bits of the hex data and only bits 4&5 need to change when the level is moved
hopefully I've answered your question ?
On how to convert 1574 to the HEX value and put it in the format as I've laid out above, I've seen people say convert to float or int but then not sure how to convert to hex or like the format as above. Once I've done that I can then hopefully work on the part to send via bluetooth from an ESP32 that's reading the Serial data coming in. but I just thought I need to workout and just display the hex values on the LCD to start with
You don't need to convert to hex because the difference between hex, decimal and binary exists only in the sketch, for the compiler they are the same thing.
All you need to do is represent the integer 2496 as two bytes and swap them around:
int x = 2496;
byte b1 = x & 0xff; // low byte
byte b2 = (x >> 8) & 0xff; // high byte
Serial.print( b1, HEX);
Serial.print(" ");
Serail.println(b2, HEX);
Your terminology is a bit confusing. The date is made up of 6 bytes of data:
byte 0 = 0x23
byte 1 = 0xF0
byte 2 = 0x04
byte 3 = 0x00
byte 4 = 0xC0
byte 5 = 0x09
From your discription, it seems byte 2 contains the position of the decimal point, in this case after the 4th digit, and bytes 4 & 5 contain the value.
The value is not a float, it is a 2-byte integer, in little-endian format (the lower 8 bits in byte 4, the upper 8 bits in byte 5). Written as hexidecimal, the value is 0x09C0, which is 2496 in decimal.
The data from the digital protractor comes in as ASCII data, which you are converting to a float with the atof() function.
You will need to determine how many decimal places are present in the number from the digital protractor, so you can convert the float to an integer. That is probably the most complex part of the code.
Also, it is not clear whether the integer is signed or unsigned.
Sorry jremington i deleted by mistake.
The OWON B35+ digital meter send the data out in this format there is no manual on the data format other than bits I found . It sends it to an M5Stack which uses the code from the github link I posted above by a clever guy. I want to create the same ouput format as the OWOn B35+ meter.
This link is what I also read up on. https://github.com/DeanCording/owonb35#protocol
Sorry, but it still not clear for me what are you doing and what is your problem.
Converting "15.74" from ascii string to two bytes is relatively easy task if you correctly described the data format.
Since you even have a ready code from github guy - what prevent you from using it in your sketch?
If you tried to do this, show YOUR code and describe what doesn’t work in it
I've been studying an playing with the M5Stack code and used some false meter test code and worked out the layout of the format the owon b35+ meter sends. sorry I got the wrong byte for the decimal place
byte 0 = 0x22 // This sets the decimal place 00.00
byte 1 = 0xF0 // not sure yet
byte 2 = 0x04//sets the function
byte 3 = 0x00 //not sure yet
byte 4 = 0x26 ;//part of voltage reading
byte 5 = 0x06 ;//part of voltage reading
This is part of the false meter so I can display the values without using a meter for testing.
#ifdef FALSEMETER
static void notifyTest() {
uint8_t _pData[replySizePlus];
_pData[0] = 0x22;//0x22 decimal places0x23 = 0.00 0x22 = 00.00 0x21 = 000.0 401Fbe77
_pData[1] = 0xF0;// not sure yet
_pData[2] = 0x04;//function
_pData[3] = 0x00;//not sure yet
_pData[4] = 0x26;//part of voltage reading
_pData[5] = 0x06;//part voltage readings,showing .
//c009 is 2.496v
//c089 is -2.496v
voltage = (_pData[4] << 8) + _pData[5];
voltageFloat = voltage * 0.01;
if (memcmp(rawvalbuf, _pData, replySizePlus) != 0) { // if new data <> old data
if (newBleData == false) { // and if old data are displayed then copy new data
memcpy(rawvalbuf, _pData, replySizePlus);
#ifdef MYDEBUG
DEBUG_MSG("D: RAW BUFF: [ ");
for (uint8_t i = 0; i < replySizePlus; i++) {
DEBUG_MSG(" %02X ", rawvalbuf[i]);
}
DEBUG_MSG("]\n");
DEBUG_MSG("Volts:%02d ", voltageFloat);
#endif
if (meterIsPlus == false) {
meterIsPlus = true;
}
}
newBleData = true;
}
lastBleNotify = millis();
}
#endif```
and this is the output of the raw buffer and if I change the values of the bytes 4&5 I can see the human readable value format. so I think it's a Hex signed 2's complement (4 digits).
The trouble is I don't know or understand how to convert from ASCII (char format) to the raw buffer Hex format