Hope you doing fine. I want you to help me out.
I had a nodemcu on my desk. and i thought it will feel lonely and connected an arduino to him with SoftwareSerial. Now, they both seem to have a good time but have a small issue...
I want arduino send 1s and 0s to nodemcu as integer (e.g 0101) and I want nodemcu to read it as 0101 as normal everyday integer number. But instead it thinks that it is in a binary system (while it looks like, it is not a byte) and converts it to a decimal one... And that ruins the whole relationship and delays my project...
How arduino sends:
int g=d1*1000 + d2*100 + d3*10 + d4;
ss.write((g));
Serial.println(g);
g is an integer that should be sent to nodemcu because he is a good guy. but currently not acting very good.
How nodemcu recieves:
if(ss.available()>2){
int f=(int)ss.read();
Serial.print("Look what arduino gave me :) ");
Serial.println(f);
sen1 = f/1000 %10;
sen2 = (f/100)%10;
sen3 = (f/10)%10;
sen4 = f%10;
}
The whole idea of using arduino, and not nodemcu alone is because arduino has couple of more pins than nodemcu. and while nodemcu is busy with transferring data, arduino can do some other stuff with other components.
Sorry for my childish question, I am just not leaving laboratory here in university and not leaving my home for a long time and haven't talked since... september, i guess...
Thank you for stopping by. Thanks in advance!
Since you are trying to send binary as text, I suggest a more practical approach:
// Sending:
Serial.write(d1 ? '1' : '0'); // Insures the integrity of
Serial.write(d2 ? '1' : '0'); // sent data.
Serial.write(d3 ? '1' : '0');
Serial.write(d4 ? '1' : '0');
You could receive the data in at least 2 ways, depending on what is more practical for you.
As a single integer, in binary format, this will allow for the usual boolean testing, i.e: flag2 = recv & 0x02.
int flags;
if (ss.available >= 4)
{
flags = 0;
for (int i = 0; i < 4; ++i)
flags = (flags << 1) + (ss.read() != '0');
d1 = flags & 0x08; // for example...
d2 = flags & 0x04;
d3 = flags & 0x02;
d4 = flags & 0x01;
}
As 4 different flags, this would match your input. It's almost the same code
if (ss.available >= 4)
{
d1 = (ss.read() != '0');
d2 = (ss.read() != '0');
d3 = (ss.read() != '0');
d4 = (ss.read() != '0');
}
Avoid divisions and modulo arithmetic operations when possible, they are the slowest arithmetic operations not only on Arduino, but on all CPUs. They are slower than other basic operations by a factor of around 20.
println sends text! That's fine because it's easily readable.
If your int variable contains 101 (decimal), it will send the text "101" and a Newline (4 characters in total)
Serial.read() reads a single byte (character). Formally, it returns an int, because it will return a -1, if there's nothing to read, else it will return a 0..255 for each available character.
So you have a couple of possible solutions:
Read each character until there's something outside the range '0'...'9' (Might be the Newline character) On each character multiply the previous intermediate value by 10 and add the decimal value of the received character
read the whole line into a buffer and parse it ( readBytesUntil, atoi )
Transfer 101 as a single byte ( ss.write instead of ss.print ) Not sure where's the problem with your 101, anything smaller than 256 should work.
Related
QtWebEngine uses a IPC mechanism to communicate between the C+ Qt world and the JavaScript work. This mechanism is used for QWebChannel, and it appears to be based on WebSockets. Is there a way to use the underlying IPC or WebSockets without using QWebChannel, as the latter seems restricted to strings or JSON-encoded data?
Background: I wrote an application QtDomTerm which is a JavaScript-based terminal emulator that uses QWebChannel to connect input/output from a PTY to QtWebEngine. This works fairly well, but there is a glitch relating to utf8/string conversion. Ideally, I'd like to send raw bytes from the PTY, and do byte-to-text conversion in JavaScript. But QWebChannel is too high-level and only handles strings or JSON-encoded data. It does not handle QByteArray.
Of course there are multiple ways to solve my problem. One is to manually create a WebSocket server, and have the JavaScript running in the QtWebEngine connect to it. But it appears that is what is going on behind the scene anyway, using qt.webChannelTransport. It seems like it would be most efficient and elegant if I could access the underlying transport (the class WebChannelIPCTransportHost seems to be relevant).
Anyone tried something like this? I.e. I would like to not use QWebChannel - unless there is an efficient way for it to pass a QByteArray.
(I rephrased the question. There was a comment about missing research, but I've browsed heavily though the Qt docuemntation, source code, and here, without finding a clear answer.)
What prevents you from sending QString::fromLatin1(data.toHex()), where data is of the QByteArray type? That's all you need, really. Use a reverse conversion on the javascript side, see e.g. this question.
Since there doesn't seem to be a way to go "below" the QWebChannel (without hacking Qt itself) there seemed to be three options:
Create a separate WebSockets connection. That would require bigger non-local changes, and possibly creating extra processes.
Do the byte-to-text decoding on the C++ side, maybe using QTextDecoder. That would probably be simplest. However, there are architectural reasons for preferring to do text decoding close to where we do escape sequence processing. That is certainly more traditional, and may better handle corner cases. Plus DomTerm needs to work with other front-ends than the QtDomTerm front-end.
Encode the bytestream to a sequence of strings, transmit the latter using QWebChannel, convert back to bytes on the JavaScript side, and then handle text-decoding in JavaScript.
I chose to implement the third option. There is some overhead in therms of converting back-end-forth. However, I designed and implemented an encoding that is quite efficient:
/** Encode an arbitrary sequence of bytes as an ASCII string.
* This is used because QWebChannel doesn't have a way to transmit
* data except as strings or JSON-encoded strings.
* We restrict the encoding to ASCII (i.e. codes less then 128)
* to avoid excess bytes if the result is UTF-8-encoded.
*
* The encoding optimizes UTF-8 data, with the following byte values:
* 0-3: 1st byte of a 2-byte sequence encoding an arbitrary 8-bit byte.
* 4-7: 1st byte of a 2-byte sequence encoding a 2-byte UTF8 Latin-1 character.
* 8-13: mean the same ASCII control character
* 14: special case for ESC
* 15: followed by 2 more bytes encodes a 2-byte UTF8 sequence.
* bytes 16-31: 1st byte of a 3-byte sequence encoding a 3-byte UTF8 sequence.
* 32-127: mean the same ASCII printable character
* The only times we generate extra bytes for a valid UTF8 sequence
* if for code-points 0-7, 14-26, 28-31, 0x100-0x7ff.
* A byte that is not part of a valid UTF9 sequence may need 2 bytes.
* (A character whose encoding is partial, may also need extra bytes.)
*/
static QString encodeAsAscii(const char * buf, int len)
{
QString str;
const unsigned char *ptr = (const unsigned char *) buf;
const unsigned char *end = ptr + len;
while (ptr < end) {
unsigned char ch = *ptr++;
if (ch >= 32 || (ch >= 8 && ch <= 13)) {
// Characters in the printable ascii range plus "standard C"
// control characters are encoded as-is
str.append(QChar(ch));
} else if (ch == 27) {
// Special case for ESC, encoded as '\016'
str.append(QChar(14));
} else if ((ch & 0xD0) == 0xC0 && end - ptr >= 1
&& (ptr[0] & 0xC0) == 0x80) {
// Optimization of 2-byte UTF-8 sequence
if ((ch & 0x1C) == 0) {
// If Latin-1 encode 110000aa,10bbbbbb as 1aa,0BBBBBBB
// where BBBBBBB=48+bbbbbb
str.append(4 + QChar(ch & 3));
} else {
// Else encode 110aaaaa,10bbbbbb as '\017',00AAAAA,0BBBBBBB
// where AAAAAA=48+aaaaa;BBBBBBB=48+bbbbbb
str.append(QChar(15));
str.append(QChar(48 + (ch & 0x3F)));
}
str.append(QChar(48 + (*ptr++ & 0x3F)));
} else if ((ch & 0xF0) == 0xE0 && end - ptr >= 2
&& (ptr[0] & 0xC0) == 0x80 && (ptr[1] & 0xC0) == 0x80) {
// Optimization of 3-byte UTF-8 sequence
// encode 1110aaaa,10bbbbbb,10cccccc as AAAA,0BBBBBBB,0CCCCCCC
// where AAAA=16+aaaa;BBBBBBB=48+bbbbbb;CCCCCCC=48+cccccc
str.append(QChar(16 + (ch & 0xF)));
str.append(QChar(48 + (*ptr++ & 0x3F)));
str.append(QChar(48 + (*ptr++ & 0x3F)));
} else {
// The fall-back case - use 2 bytes for 1:
// encode aabbbbbb as 000000aa,0BBBBBBB, where BBBBBBB=48+bbbbbb
str.append(QChar((ch >> 6) & 3));
str.append(QChar(48 + (ch & 0x3F)));
}
}
return str;
}
Yes, this is overkill and almost certainly premature optimization, but I can't help myself :-)
I need to send two separate integers from one arduino to another. There's no problem with the distance and communication, but I'm not sure how to do this.
I need to send the two integers, each from -15000 to 15000, in a matter of 0.2 seconds.
So one arduino is sending and another one is reading.
You can try with Serial.print(int)
look at this
sorry for my bad english
Assuming you have a serial link between the two items, you can
1) send it in a text-based way:
// Sender
Serial.print(value);
// Receiver
int value = Serial.parseInt();
2) send it in a binary-based way:
byte arr[4];
// Sender
for (i=0;i<4;i++)
arr[i] = (value >> (8*(3-i))) & 0xFF;
Serial.write(arr,4);
// Receiver
if (Serial.available() > 4)
{
Serial.readBytes(arr,4);
value = 0
for (i=0;i<4;i++)
value = (value << 8) | (((int)arr[i]) & 0xFF);
}
The first way is easier, the second is more optimized and can become more reliable if you add some controls.
If you are not using a serial communication, you will have to change these functions (but probably any interface lets you send and receive byte arrays, so the second can be applied in almost any case)
Basically I am looking to make an serial-like system that runs communication between IR LEDs on an arduino. Below the code gets to the point having an array with a collection of 1s and 0s in it. I need to convert this 8 bit array into a single character and output it. But I don't know how to do this. Help would be appreciated.
int IR_serial_read(){
int output_val;
int current_byte[7];
int counter = 0;
IR_serial_port = digitalRead(4);
if (IR_serial_port == HIGH){
output_val =1;
}
if (IR_serial_port == LOW){
output_val =0;
}
current_byte[counter] = output_val;
counter +=1
}
This would best be done with bitwise operators, I think the or function would be of best use here as it will set a bit if the input is 1 and not change it if it is 0, could use a loop to loop through your array and set the bits.
Looking at your code, are you sure you are receiving all 8 bits? You seem to be saving 7 bits.
As you are creating a byte array solely for the purpose of using only 1s and 0s, it suggest immediately setting the bits in the same loop.
Here is the code that I suggest:
byte inputByte = 0; // Result from IR transfer. Bits are set progressively.
for (byte bit = 0; bit < 8; bit++) { // Read the IR receiver once for each bit in the byte
byte mask = digitalRead(4); // digitalRead returns 1 or 0 for HIGH and LOW
mask <<= bit; // Shift that 1 or 0 into the bit of the byte we are on
inputByte |= mask; // Set the bit of the byte depending on receive
}
This would also be put inside a loop to read all the bytes in your data stream.
It is designed for readability and can be optimised further. It reads the least significant bit first.
You can also apply the same technique to your array if you wish to keep using an array of bytes just for 1s and 0s, just replace the digitalRead with the array location (current_byte[bit]).
I am programming Arduino and I am trying to Serial.print() bytes in hexadecimal format "the my way" (keep reading for more information).
That is, by using the following code
byte byte1 = 0xA2;
byte byte2 = 0x05;
byte byte3 = 0x00;
Serial.println(byte1, HEX);
Serial.println(byte2, HEX);
Serial.println(byte3, HEX);
I get the following output in the Serial Monitor:
A2
5
0
However I would like to output the following:
A2
05
00
In words, I would like to print the "full" hexadecimal value including 0s (05 instead of 0 and 00 instead of 0).
How can I make that?
Simple brute force method, is to write a routine as:
void p(char X) {
if (X < 16) {Serial.print("0");}
Serial.println(X, HEX);
}
And in the main code:
p(byte1); // etc.
sorry - not enough reputation to comment but found previous answer is not fully correct. Actually, the nice light way to code it should be :
void p(byte X) {
if (X < 10) {Serial.print("0");}
...
giving the code:
void p(byte X) {
if (X < 10) {Serial.print("0");}
Serial.println(X, HEX);
}
And in the main code:
p(byte1); // etc.
hope this helps
Use sprintf to print into a buffer (two chars per byte + null terminator):
byte byte1 = 0xA2;
byte byte2 = 0x05;
byte byte3 = 0x00;
char s[7];
sprintf(s, "%02x\n%02x\n%02x", byte1, byte2, byte3);
Serial.println(s);
Added new lines in between to get each on new line. About '%02x', the % means here comes formatting information, 0 means to pad with 0, 2 means pad input until 2 characters wide and x means give me this as hexadecimal.
For other formatting options see http://linux.die.net/man/3/sprintf
The lowest footprint in Memory, Code and runtime would be classic bit playing
byte b;
Serial.print(b>>4, HEX);
Serial.print(b&0x0F,HEX);
Which is working fine on any 8bit type. For any other mask also the first line to
Serial.print((b>>4)&0x0F, HEX);
Try this:
//Converts the upper nibble of a binary value to a hexadecimal ASCII byte.
//For example, btohexa_high(0xAE) will return 'A'.
unsigned char btohexa_high(unsigned char b)
{
b >>= 4;
return (b>0x9u) ? b+'A'-10:b+'0';
}
//Converts the lower nibble of a binary value to a hexadecimal ASCII byte.
// For example, btohexa_low(0xAE) will return 'E'.
unsigned char btohexa_low(unsigned char b)
{
b &= 0x0F;
return (b>9u) ? b+'A'-10:b+'0';
}
And in main code:
comand_mod=0xA1; //example variable
Serial.print(btohexa_high(comand_mod));
Serial.print(btohexa_low(comand_mod));
wow! 7 years ago and I felt here, my answer might be useful for you (hopefully not anymore) or others looking for the answers like me.
Use "Serial.write()" to send a hex byte over serial.
All Serial.print() eg. println, printf, sprint, print will "print" your value in ASCII.
I want to parse two integers that are sent from one arduino to another. The integers can be between 1 and 3 digits and they can be the same but still I must be able to tell which one is which.
Tried to search the already answerd questions regarding this but cannot find any good answear.
I have tried with this on the reciever (I print the inputstring2 on a LCD screen where I also reset the Inputstring2):
if(incomingByte == 'b'){
incomingByte = Serial.read();
while(incomingByte >= '0' && incomingByte <= '9'){
inputString2 += incomingByte;
incomingByte = Serial.read();
}
stringComplete2= true;//
The error is that I sometimes get only one of the digits if the integer is 25 I only get 2...
Sender:
Serial1.print('a');
Serial1.print(temp2);
Serial1.print('b');
Serial1.print(encoderValue);
Serial1.print('n');
When you send the value, also send a "tail character" to indicate to the receiver that the data characters has no more characters, i.e.:
Serial1.print('a');
Serial1.print(temp2);
Serial1.print('a');
Serial1.print('b');
Serial1.print(encoderValue);
Serial1.print('b');
In this way you enclose the data in a packet (a data a), so on the receiving end you test for the start of the packet, then read the remaining characters until you read the end of the packet.