I have been involved in a project where I need to extract some data from a device and display it on a PC to be checked. The device I am recieving data from sends a string which includes the device ID, current mode, temperature reading and battery reading. For ease, these are separated by a comma. An example of a string would be:
01,03,66661242,28
so this would bean the device ID is 1, the mode is mode 3, a temperature reading of 36.6 (this is in ASCII little endian format), and battery level is 4.0V (sent in ASCII and divided by 10)
I have no control over the format the data is sent
I am using an STM32F091RC Nucleo board for this and the code I have is:
#include "mbed.h"
Serial pc(PA_2, PA_3);
Serial Unit (PA_9, PA_10, 9600); // 9600 baud rate - no parity - 1 stop bit
//Input pins
DigitalIn START(PB_8, PullUp);
void GetData();
void CheckData();
char Data[100];
int deviceId;
int Mode;
float TempReading;
float battReading;
unsigned char Ascii2Hex (unsigned char data)
{
if (data > '9')data += 9; // add offset if value > 9
return (data &= 0x0F);
}
unsigned char Ascii2Char(unsigned char Offset)
{
unsigned char Ans;
Ans = Ascii2Hex(Data[Offset]);
Ans = Ans<<4;
Ans += Ascii2Hex(Data[Offset+1]);
return(Ans);
}
float Ascii2Float(unsigned char Offset)
{
float Bob;
unsigned char Ans;
Ans = Ascii2Hex(Data[Offset+6]);
Ans = Ans<<4;
Ans += Ascii2Hex(Data[Offset+7]);
((unsigned char*)&Bob)[3]= Ans;
Ans = Ascii2Hex(Data[Offset+4]);
Ans = Ans<<4;
Ans += Ascii2Hex(Data[Offset+5]);
((unsigned char*)&Bob)[2]= Ans;
Ans = Ascii2Hex(Data[Offset+2]);
Ans = Ans<<4;
Ans += Ascii2Hex(Data[Offset+3]);
((unsigned char*)&Bob)[1]= Ans;
Ans = Ascii2Hex(Data[Offset]);
Ans = Ans<<4;
Ans += Ascii2Hex(Data[Offset+1]);
((unsigned char*)&Bob)[0]= Ans;
return(Bob);
}
void DecodeString()
{
char x;
//numbers in brackets is where the data starts in the string
deviceId = Ascii2Char(0);
Mode = Ascii2Char(3);
TempReading = Ascii2Float(6);
x = Ascii2Char(15);
battReading = (float)x/10;
GetData();
}
void GetData()
{
Unit.scanf("%s,",Data); // scan the incoming data on the RX line
pc.printf("%s,\n\r",Data);
pc.printf("Device ID = %i\n\r", deviceId);
pc.printf("Mode = %i\n\r", Mode);
pc.printf("Temp = %.1f\n\r", TempReading);
pc.printf("Bat = %.1f\n\n\r", battReading);
}
int main()
{
while(1) {
if(START == 0) {
wait(0.1);
DecodeString();
}
}
}
When I first start up and press the button to get the data, the string I recieve has an extra 0 at the front: 001,03,66661242,28
This then means the data is incorrect as the data has shifted, however, if I press it again, it then gives the correct string but the printed data is incorrect Another press and everything works fine and will continue working until the Nucleo board is reset. An example of the recieved string and displayed data from my serial monitor is:
001,03,33331342,28,
Device ID = 0
Mode = 0
Temp = 0.0
Bat = 0.0
01,03,CDCC1242,28,
Device ID = 0
Mode = 192
Temp = 0.0
Bat = 19.4
01,03,CDCC1242,28,
Device ID = 1
Mode = 3
Temp = 36.7
Bat = 4.0
I am not an expert coder, I am very much a beginner. The bit of code that decodes the string was given to me by the engineer who designed the device that sends the data string. I have for assistance but because of working from home and people being very busy with other things, this isn't a pressing issue so help is limited.
I have tried adding some delays in various places (such as after the original scanf and before printing) and I have also tried the scanf function 3 times just as an experiment to see if I can bypass the incorrect data but none of these have helped. I have tried using different UART pins (the STM32F091RC 64 pin device has 6 available) but I still get the same result. I have also changed the data byte length from 100 to 17 as that is the amount I am expecting to recieve but it still makes no difference.
I have made sure that all devices are sharing a common GND and double checked all the hardware connections.
All I want to do is recieve the correct data first time and display the correct result first time, but I can't seem to get it working.
EDIT
I have now tried adding in an extra few lines. I am using strlen to count the number of bytes in the string. If it is more than 17, I then retry. This has eliminated the first issue, but the first set of decoded data is still displayed incorrectly:
String Length = 18
String Length = 17
01,03,66661242,28,
Device ID = 0
Mode = 192
Temp = 0.0
Bat = 19.4
String Length = 17
01,03,66661242,28,
Device ID = 1
Mode = 3
Temp = 36.6
Bat = 4.0
Is there any way first to make sure the data is decoded correctly first time, or that the data is read correctly first time instead of needing a workaround?