I encountered an issue while having fun with Arduino. I am currently using the first version of Arduino IDE (v 1.18.49.0).
Problem is that I can't figure out how to convert float value to hex. I am trying to use various solutions that occurred earlier on StackOverflow, but none of them seemed to work for me. My best attempt is:
char data[9];
float a = 3.141592654;
sprintf(data, "%x", *(unsigned int*)&a);
Serial.println(data);
Expected Result: 40490fdb
Actual Result: fdb
What's surprising using the same code, yet slightly modified, compiled by g++ gives the expected result.
#include <stdio.h>
int main(int argc, char** argv)
{
char data[9];
float a = 3.141592654;
sprintf(data, "%x", *(unsigned int*)&a);
printf(data);
return 0;
}
Why do the results differ? Maybe there is a better way to do that?
Thanks in advance!
If you are sure you want to see the bit pattern of a 4 byte variable, you should prefer a conversion like this:
sprintf(data, "%08lx", *(uint32_t*)&a);
(Here it's irrelevant, but in general, leading zeros help readability)
[edited to include #timemage's hint]
Related
EDIT:
The issue is only on STM32CubeIDE, on Keil-MDK it works.
I have been trying to send a message using the USART port of STM32F411 MCU. I wrote a function which takes char* and ellipsis as input. Ideally you would convert the numbers into a string/character and put into a char buffer and send a charater at a time to the USART->DR. Here is the function:
void Serial::write_byte(int data)
{
Serial::port->DR = (data & 0xff);
while (!(Serial::port->SR & (1 << 7))); //wait for Tx buff to get empty
}
void Serial::write(char *msg, ...)
{
char buff[256];
va_list args;
va_start(args, msg);
vsprintf(buff, msg, args);
for (unsigned int i = 0; i < strlen(buff); i++)
{
Serial::write_byte(buff[i]);
}
}
The above function works with integer numbers and characters. But when I do the following:
float R = (int16_t(raw[0] << 8 | raw[1]))/4096.0;
Debug.write("XG : %f\n",R);
The output on the serial terminal is : XG : (No number)
To note that I tried various ways available in C & C++ :
Using sprintf
int16_t R = int16_t(raw[0] << 8 | raw[1]);
char str[10];
sprintf(str,"%f",(R/4096.0));
Debug.write("XG : %s\n",str);
The output is : XG : 0, Even with %.4f it shows 0.
Using std::string
int16_t R = int16_t(raw[0] << 8 | raw[1]);
// goes into unknow state , mcu stops
std::string msg = "Roll : " + std::to_string(R/4096.0) + "\n";
Debug.write_string(msg);
sleep_ms(1000);
In this case there is no output. I checked with the debugger and this is the place where it gets stuck:
Apart from the code I also changed the FPU settings in STM32CubeIDE, here are the current settings:
So far I referred to various SO questions and tutorials, but It has never worked for me.
I would appreciate your help and guidance!
Okay so digging up the issue from all the available QAs and all, I found out the intimated settings are not working for me, and that my code has no issues in implementations! Note that this is not an issue on Keil MDK, it is only on STM32CubeIDE.
So just for the folks who might face similar issues with float in STM32CubeIDE, there are forums which say to add a linker-flag -u _printf_float, other say to change the _estack value in linker files (which says end address as 2001ffffH, but it should be 20020000H), unfortunately none of them worked for me.
What worked for me was to change the MCU-Settings; where I changed the Floating-poin ABI to Software Implementation and checked the Use float with printf(incase you are using newlib-nano, for standard C/C++ it would be disabled anyway). Here is how:
I am trying to publish a float to an MQTT channel in C++, within the Arduino IDE.
The following code does appear to work, but it seems to be a bit long-winded. I cobbled it together from stuff I found online. Is all this really necessary (the conversion to an array via a string), or is there a better way?
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <SparkFunBME280.h>
BME280 atmosSensor;
String tStr;
String pStr;
String hStr;
char tArr[4];
char pArr[4];
char hArr[4];
void setup() {
Setup wifi, mqtt, etc.
}
void loop() {
float tempReading = atmosSensor.readTempC();
float pressureReading = atmosSensor.readFloatPressure();
float humidityReading = atmosSensor.readFloatHumidity();
tStr = String(tempReading);
pStr = String(pressureReading);
hStr = String(humidityReading);
tStr.toCharArray(tArr, tStr.length()+1);
pStr.toCharArray(pArr, pStr.length()+1);
hStr.toCharArray(hArr, hStr.length()+1);
client.publish("atmos1/temperature", tArr);
client.publish("atmos1/pressure", pArr);
client.publish("atmos1/humidity", hArr);
}
N.B. I have pruned this code down considerably, to just the relevant bit. I'm really just asking whether the conversion to a String, and then to an array etc, is necessary.
You can use dtostrf to do the conversion in fewer steps.
char* dtostrf(double __val, signed char __width, unsigned char __prec, char * __s )
It would look something like this:
void loop()
{
float humidityReading = atmosSensor.readFloatHumidity();
constexpr size_t BUFFER_SIZE = 7; //1 char for the sign, 1 char for the decimal dot, 4 chars for the value & 1 char for null termination
char buffer[BUFFER_SIZE];
dtostrf(humidityReading, BUFFER_SIZE - 1 /*width, including the decimal dot and minus sign*/, 2 /*precision*/, buffer);
client.publish("atmos1/humidity", buffer, BUFFER_SIZE); //notice we're using the overload where you specify the length of the buffer, as we know it and it saves a call to strlen
}
A cursory glance at the MQTT source code shows that the data is stored in an internal buffer after a call to publish(), so you should be safe in reusing the same buffer for multiple calls to publish(). But be sure to check more thoroughly than I did ;)
Im using VS2008 for compiling and developing my application. Im required to take Adc input and serial print it through RS232 in a WinCE6 OS over some termianl like putty or hyperterminal. The problem is when I use the WriteFile function it gives me the following error.
Error 3 error C2440: '=' : cannot convert from 'double' to 'char [32]' c:\Users\Sohan\Downloads\uartdemo\uartdemo\src\main.c 137 Sohan_1
I want to take the input from ADC channel and then after converting it to voltage i have to transmitt. I have tried using a constant char string and it works but when i take the input from the channel and then try it doesnt work.
HANDLE portHandle;
DWORD noOfBytesRead = 0;
DWORD bytesTransmitted = 0;
DWORD firstChoice = 0;
BOOL retVal = FALSE;
char c="hello";
char transmit2Buffer[BUFFER_SIZE] = "7.8888v";
char volt[BUFFER_SIZE];
WriteFile(portHandle, transmit2Buffer, strlen(transmit2Buffer), &bytesTransmitted, NULL);
WriteFile(portHandle, volt, strlen(volt), &bytesTransmitted, NULL);
the first write function works but the second doesnt. variable volt will keep on changing so how should i write it.please help..
After searching i have got an answer for my question.
this worked for me..
You can use sprintf() as you have done to convert a double to a string, but I would actually recommend using _snprintf() instead simply because sprintf() has no regard for the fact that strings are fixed length devices in memory and will overflow if you don't watch it. _snprintf() allows you to specify the length of the out string, just be sure to specify the size as one less than the actual allocated memory block, because _snprintf() does not store the terminating null character if it has to cut the output short.
An example us using _snprintf() is:
void ToString(char * outStr, int length, double val)
{
_snprintf(outStr,length,"%f",val);
}
Got this answer on some website!!!
Sorry in advance for what I feel is going to be a really simple problem, but I've been stuck on it for hours and I haven't been able to work out how to fix it based on the stuff I've found here or on google.
I've got an arduino hooked up to a GPS and a radio and am trying to broadcast the GPS signal to my radio. What I am trying to do now is get the NMEA sentence from the GPS into the variable 'text', but am getting confused by this error, which I think is due to arrays.
My error is occurring on this line:
sprintf(text, char(c));
I've tried a few different things but this is where I'm stuck at the moment. Any help would be really appreciated.
#define RADIOPIN 13
#include <string.h>
#include <util/crc16.h>
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 2);
#define GPSECHO true
Adafruit_GPS GPS(&mySerial);
char datastring[80];
char text[80];
void setup() {
Serial.begin(115200);
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ);
delay(3000);
pinMode(RADIOPIN,OUTPUT);
}
void loop(){
gpscheck();
}
void gpscheck(){
char c = GPS.read();
if (c) {
// Serial.print(c);
sprintf(text, char*(c));
Serial.print(text);
}
}
You might want to read a reference of sprintf. Then you will see that the second argument is a string.
So the following would be fine:
sprintf(text, "%c", c);
To be on the safe side, you might want to use snprintf instead, to lessesn the risk of buffer overflows.
Of course, for a single character, you might as well do e.g.
text[0] = c;
text[1] = '\0'; /* Terminate string */
sprintf(text, char*(c));
If you want to print character
simply use printf("%c",c);
if you want to copy that into text
sprintf(text,"%c", c);
This is my C++ Code where i'm trying to encode the received file path to utf-8.
#include <string>
#include <iostream>
using namespace std;
void latin1_to_utf8(unsigned char *in, unsigned char *out);
string encodeToUTF8(string _strToEncode);
int main(int argc,char* argv[])
{
// Code to receive fileName from Sockets
cout << "recvd ::: " << recvdFName << "\n";
string encStr = encodeToUTF8(recvdFName);
cout << "encoded :::" << encStr << "\n";
}
void latin1_to_utf8(unsigned char *in, unsigned char *out)
{
while (*in)
{
if (*in<128)
{
*out++=*in++;
}
else
{
*out++=0xc2+(*in>0xbf);
*out++=(*in++&0x3f)+0x80;
}
}
*out = '\0';
}
string encodeToUTF8(string _strToEncode)
{
int len= _strToEncode.length();
unsigned char* inpChar = new unsigned char[len+1];
unsigned char* outChar = new unsigned char[2*(len+1)];
memset(inpChar,'\0',len+1);
memset(outChar,'\0',2*(len+1));
memcpy(inpChar,_strToEncode.c_str(),len);
latin1_to_utf8(inpChar,outChar);
string _toRet = (const char*)(outChar);
delete[] inpChar;
delete[] outChar;
return _toRet;
}
And the OutPut is
recvd ::: /Users/zeus/ÄÈÊÑ.txt
encoded ::: /Users/zeus/AÌEÌEÌNÌ.txt
The above function latin1_to_utf8 is provided as an solution Convert ISO-8859-1 strings to UTF-8 in C/C++ , Looks like it works.[Answer is accepted]. So i think i must be making some mistake, but i'm not able to identify what it is. Can someone help me out with this , Please.
I have first posted this question in Codereview,but i'm not getting any answers out there. So sorry for the duplication.
Do you use any platform or you build it on the top of std? I am sure that many people use such convertions and therefore there is library. I strongly recommend you to use the libraray, because the library is tested and usually the best know way is used.
A library which I found doing this is boost locale
This is standard. If you use QT I will recommend you to use the QT conversion library for this (it is platform independant)
QT
In case you want to do it yourself (you want to see how it works or for any other reason)
1. Make sure that you allocate memory ! - this is very important in C,C++ . Since you use iostream use new to allocate memory and delete to release it (this is also important C++ won't figure out when to release it for sure. This is developer's job here - C++ is hardcore :D )
2. Check that you allocate the right size of memory. I expect unicode to be larger memory (it encodes more symbols and sometimes uses large numbers).
3. As already mentioned above read from somewhere (terminal or file) but output in new file. After that when you open the file with text editor make sure you set the encoding to be utf-8 ( your text editor has to know how to interpretate the data)
I hope that helps.
You are first outputting the original Latin-1 string to a terminal expecting a certain encoding, probably Latin-1. You then transcode to UTF-8 and output it to the same terminal, which interprets it differently. Classic mojibake. Try the following with the output instead:
for(size_t i=0, len=strlen(outChar); i!=len; ++i)
std::cout << static_cast<unsigned>(static_cast<unsigned char>(outChar[i])) << ' ';
Note that the two casts are to first get the unsigned byte value and then to get the unsigned value to keep the stream from treating it as a char. Note that your char might already be unsigned, but that's compile-dependent.