I am coding on Attiny85 with IRremote and SSD1306 libraries customized.
When receiving IR data the results are stored this way:
unsigned long value // Decoded value, max 32 bits
volatile unsigned int *rawbuf // Raw interval in 50uS ticks
int rawlen // Number of records in rawbuf
OLED display related functions are:
void printChar (char ch)
void printString (char* pText)
I am struggling with printing the received IR value to the OLED SSD1306 screen. User is able to review and save the received code to EEPROM and hence I have tried all different conversions but I am unable to print the results.value to the screen in a way that it would display the received HEX code (for example 0xE0E040BF which is Power on in Samsung television).
Due to lag of Serial in attiny85 I have no clue how I could debug this and get it working. Any help?
EDIT (adding relative code):
#include "SSD1306.h"
#include "IRremote.h"
...
if (irrecv.decode(&results)) {
dumpCode(&results);
irsend.sendRaw(buff, results.rawlen, 38);
oled.printString("Received IR");
// Print received hexadecimal IR code to the OLED screen
irrecv.enableIRIn();
irrecv.resume();
}
If I understand it correctly you just want to convert a unsigned long value into an hex string, you can use sprintf for this purpose (ideone):
const unsigned int BUFFER_LENGTH = 16;
char buffer[BUFFER_LENGTH];
unsigned long value = 0xE0E040BF;
sprintf(buffer, "0x%08X", value);
printf("%s\n", buffer); // printString(buffer)
so that you can pass buffer to the printString method of the oled screen.
The format specifier %08X instructs printf to format the value as an hexadecimal number, with capital letters always showing all 8 hex values for the 4 bytes and padding it with 0s.
You could do this:
int IR;
char hexadec_s[11];
sprintf(hexadec_s,"0x%08x",IR);
printString(hexadec_s);
I believe this should do the trick. Let me know if it worked.
Related
How to send data in hex on SerialPort?
I used this function, I receive the "yes, I can write to port" but I do not receive the data I entered
QByteArray send_data;
if(serialPort->isWritable())
{
qDebug()<<"Yes, I can write to port!";
int size = sizeof(send_data);
serialPort->write(send_data,size);
}
send_data += static_cast<char>(0xAA);
serialPort->write(send_data);
Data are transmitted in binary (essentially a sequence of 0 and 1). No matter what. Showing data in hexadecimal rather than a string of characters is just a choice.
In the following example, you can see that the array string_c is initialized with the same string that you are using in your code. Next, I print the data in both, as hex and as a string. You can see that the only difference is in the way I decided to print the data. The source data is the same for both.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
void printCharInHexadecimal(const char* str, int len)
{
for (int i = 0; i < len; ++ i) {
uint8_t val = str[i];
char tbl[] = "0123456789ABCDEF";
printf("0x");
printf("%c", tbl[val / 16]);
printf("%c", tbl[val % 16]);
printf(" ");
}
printf("\n");
}
int main()
{
char string_c[] = "Yes, i can write to port";
// string printed in hex
printCharInHexadecimal(string_c, 24);
// same string printed as "text"
printf("%s\n",string_c);
return 0;
}
You can see the above code running here: https://onlinegdb.com/Y7fwaMTDoq
Note: I got the function printCharInHexadecimal from here: https://helloacm.com/the-c-function-to-print-a-char-array-string-in-hexadecimal/
As suspected, your use of sizeof is wrong. It is not returning the size of the contained data, it is returning a non-zero constant that is the size of a QByteArray object itself. Since that object was freshly constructed it should be empty, and any size you use in the first write other than zero will lead to undefined behavior. Use:
int size = (int)send_data.size();
Skip the first write entirely, and use the above for your second write.
You need to be clear about what you expect. 0xAA in your source code is simply an integer value using hex representation. It complies to exactly the same code regardless of the source code presentation: 0xAA == 170 == 0263.
If you actually intended to output a string of characters at run time representing a value in hexadecimal, you need to convert that value from an integer to a string. For example;
char hexbyte[3] ;
sprintf( hexbyte, "%02X", 170 ) ;
serialPort->write(send_data) ;
will output ASCII characters AA, whilst demonstrating the equivalence of 170 to 0xAA. That is the hex notation in the source does not affect the value or how it is stored or represented in the compiled machine code.
I'm writing code to do monitoring, I'm having trouble transforming the calculated distance values into const char* to publish it in mqtt. What can I do to solve my problem? I've already tried using sprintf but got no results.
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <PubSubClient.h>
#define TOPICO_SUBSCRIBE "..."
#define TOPICO_PUBLISH "..."
#define ID_MQTT "..."
const char* ssid = "...";
char* password = "...";
char* BROKER_MQTT = "broker.hivemq.com";
int BROKER_PORT = 1883;
WiFiClient espClient;
PubSubClient MQTT(espClient);
const int trigPin = 2; //D4
const int echoPin = 0; //D3
long duration;
int distance;
void setup()
{
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
init_serial();
init_wifi();
init_mqtt();
}
Here starts my problems (I cut snippets of code to be able to publish)
void loop()
{
verifica_conexoes_wifi_mqtt();
MQTT.publish(TOPICO_PUBLISH, "ESP32 se comunicando com MQTT");
MQTT.loop();
delay(1000);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
distance= duration*0.034/2;
char msgDistance;
msgDistance = distance;
sprintf(msgDistance,"A distância lida é: ", distance);
MQTT.publish(TOPICO_PUBLISH, msgDistance);
}
The problems with this code are how it stores the result of the distance calculation and how it uses sprintf to format the message you want to transmit.
First, you defined distance as an int, which really isn't going to work with this line:
distance= duration*0.034/2;
You're doing floating point math. If you store the result in an int, you'll lose any fractional value of the result. If the result was less than 1, it would end up being 0.
You also declared it to be a global variable but there appears to be no need for it to be global. It's better to limit its scope by only making it available where it's needed. In this case it looks like you can move both distance and duration inside loop(), so you'd remove their definitions before setup() and write them inside loop():
void loop() {
long duration;
float distance;
Your sprintf() code currently looks like this:
char msgDistance;
msgDistance = distance;
sprintf(msgDistance,"A distância lida é: ", distance);
There are several problems with this:
sprintf() needs to take a character array pointer as its first argument. Instead, you're passing it a single character variable. This makes no sense and is generating the compiler error you're seeing.
sprintf() needs a format string to tell it what to print (written as %X where X is a character indicating the type of data being printed. You included some text but no format string.
sprintf() can very easily overflow the char array it's printing into; you should use snprintf() instead
To solve the first problem, we need msgDistance to be an array of characters: char [].
Your code needs to look more like this:
char msgDistance[32];
snprintf(msgDistance, sizeof(msgDistance), "A distância lida é: %0.2f", distance);
The changes are:
msgDistance is now a character array that snprintf() can use
deleted the unnecessary assign to msgDistance, which would cause an error now that it's a char array
snprintf() is the safer form of sprintf() - it takes the length of the character array as an argument so that it can't accidentally overflow the array
sizeof() is a built-in function which returns the size of a variable at compile-time; it's an easy way to use the size of the array here but beware it may not do what you expect if you don't really understand C/C++ arrays and pointers and strings
%0.2f in the snprintf() format string - this tells snprintf() to print a float variable (that's the f), with a leading zero if needed (that's the 0 part and two decimal places of precision (that's the 2 part - if you wanted one decimal place you'd write it as %0.1f)
You can learn more about printf() format strings using a search engine; there are many good tutorials and references for them available online.
I am trying to convert uint8_t readData[10] = "123456789" ; to unsigned long to do some math on this value, in Arduino. I'm using strtoul function. strtoul works fine if I define above array by my self and it converts this array to unsigned long successfully. But if I put some values in this array by reading DS1307 NVRAM, then strtoul fails to convert the array into unsigned long and gives 0 answer. I checked values in readData array, after reading NVRAM, using for loop, and found that values are same that i have saved in the NVRAM.
I am using NodeMCU board along with DS1307. My code and its Output is given below.
// Example of using the non-volatile RAM storage on the DS1307.
// You can write up to 56 bytes from address 0 to 55.
// Data will be persisted as long as the DS1307 has battery power.
#include "RTClib.h"
RTC_DS1307 rtc;
uint8_t readData[9] = "0"; //**this will store integer values from DS1307 NVRAM.
unsigned long convertedL1 = 0; //this will store converted value
uint8_t savedData[10] = "123456789"; //I have already filled this array for testing strtoul function.
unsigned long convertedL2 = 0; //this will store converted value of savedData array
void setup () {
Serial.begin(9600);
delay(3000);
#ifndef ESP8266
while (!Serial); // wait for serial port to connect. Needed for native USB
#endif
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
delay(3000);
while(1);
}
rtc.readnvram(readData,9,2); //Read NVRAM from address 2 to 11.
delay(20);
Serial.println("Prinitng values( using loop) stored in readData array, after reading NVRAM :");
for (int i = 0; i <9; i++) {
Serial.print(readData[i]);
}
Serial.println();
//Converting both arrays of same type using stroul
convertedL1 = (unsigned long)strtoul((char *)&readData[0],NULL,10);
convertedL2 = (unsigned long)strtoul((char *)&savedData[0],NULL,10);
Serial.print("converted value of readData array = ");
Serial.println(convertedL1);
Serial.println();
Serial.print("converted value of savedData array = ");
Serial.println(convertedL2);
}//setup end
void loop () {
// Do nothing in the loop.
}
the Output on Serial Monitor is:
Prinitng values( using loop) stored in readData array, after reading NVRAM :
123456789
converted value of readData array = 0
converted value of savedData array = 123456789
Why strtoul function works with one array and not with other.I searched many forums but couldn't find any solution.
Can anyone, please have a look at my code and kindly suggest me the solution. Any help will be highly appreciated.
Seems likely the reason for the difference is that your savedData array is null terminated but your readData array is not. strtoul requires that the array be null terminated.
Change your code like this
uint8_t readData[10] = "0"; // one extra byte for null terminator
...
rtc.readnvram(readData,9,2); //Read NVRAM from address 2 to 11.
readData[9] = '\0'; // add the null terminator
I'm trying to display an integer on an LCD-Display. The way the Lcd works is that you send an 8-Bit ASCII-Character to it and it displays the character.
The code I have so far is:
unsigned char text[17] = "ABCDEFGHIJKLMNOP";
int32_t n = 123456;
lcd.printInteger(text, n);
//-----------------------------------------
void LCD::printInteger(unsigned char headLine[17], int32_t number)
{
//......
int8_t str[17];
itoa(number,(char*)str,10);
for(int i = 0; i < 16; i++)
{
if(str[i] == 0x0)
break;
this->sendCharacter(str[i]);
_delay_ms(2);
}
}
void LCD::sendCharacter(uint8_t character)
{
//....
*this->cOutputPort = character;
//...
}
So if I try to display 123456 on the LCD, it actually displays -7616, which obviously is not the correct integer.
I know that there is probably a problem because I convert the characters to signed int8_t and then output them as unsigned uint8_t. But I have to output them in unsigned format. I don't know how I can convert the int32_t input integer to an ASCII uint8_t-String.
On your architecture, int is an int16_t, not int32_t. Thus, itoa treats 123456 as -7616, because:
123456 = 0x0001_E240
-7616 = 0xFFFF_E240
They are the same if you truncate them down to 16 bits - so that's what your code is doing. Instead of using itoa, you have following options:
calculate the ASCII representation yourself;
use ltoa(long value, char * buffer, int radix), if available, or
leverage s[n]printf if available.
For the last option you can use the following, "mostly" portable code:
void LCD::printInteger(unsigned char headLine[17], int32_t number) {
...
char str[17];
if (sizeof(int) == sizeof(int32_t))
snprintf(str, sizeof(str), "%d", num);
else if (sizeof(long int) == sizeof(int32_t))
snprintf(str, sizeof(str), "%ld", num);
else if (sizeof(long long int) == sizeof(int32_t))
snprintf(str, sizeof(str), "%lld", num);
...
}
If, and only if, your platform doesn't have snprintf, you can use sprintf and remove the 2nd argument (sizeof(str)). Your go-to function should always be the n variant, as it gives you one less bullet to shoot your foot with :)
Since you're compiling with a C++ compiler that is, I assume, at least half-decent, the above should do "the right thing" in a portable way, without emitting all the unnecessary code. The test conditions passed to if are compile-time constant expressions. Even some fairly old C compilers could deal with such properly.
Nitpick: Don't use int8_t where a char would do. itoa, s[n]printf, etc. expect char buffers, not int8_t buffers.
I will briefly explain what I want to do and help appreciated.
I have a hex number which is formatted as 16 byte number like this:
1: std::string myhex = "00000000000000000000000000000FFD";
Then I want to convert it to int. Which I think I successfully do using this:
// convert hex to int
unsigned int x = strtoul(myhex.c_str(), NULL, 16);
printf("x = %d\n", x); // prints 4093 as needed
Now, I want to convert this integer back to hex. Which I think I also successfully do using this:
// Convert int back to hex
char buff[50];
string hexval;
sprintf(buff,"%x",x);
hexval = buff;
cout << hexval.c_str(); // prints "ffd".
But my problem is that now, I want to convert the "ffd" string as above back to the format it was before, e.g., 16 byte number padded with zeros like this:
00000000000000000000000000000FFD
I want to convert the string not only print it.
Any help how to do this?
Also any corrections if anything I was achieving above is wrong or not OK are welcome.
Preferably I would like this to compile on Linux also.
Use the 0 flag (prefix) for zero-padding and field width specification in a printf:
printf("%032X", x);
Use snprintf to store it in your string:
snprintf(buff, sizeof(buff), "%032X", x);
Or use asprintf to store it in a newly-allocated string, to be certain that the memory available for the string is sufficient (since it's allocated by asprintf):
char *as_string = NULL;
asprintf(&as_string, "%032X", x);