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)
Related
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.
So I have to write a code that recognizes colour using a colour-detector.
The because the colourpalette is limited to just 6 colours I can be saved as an Integer (Red as 0, Green as 1 aso.).
Now I have problems transfering the Integer from the Arduino that handles the detector to the Arduino I have to write code on.
I tried using the analog (A0) pin but with that I only ended up with a 19-20 whenever I tried to transfer anything at all.
Is there a solution to transfer an Integer from 0-5?
Thanks in advance
Using the Analog is not a good solution. You should use the "Serial Connection". It only requires two cables - no other electronics - and the code is very simple (see below).
If you just want to transfer values in the range 0-255 or smaller (as in your case: 0-5), you can use the "byte"-type variable. One or multiple bytes can easily be transferred using a serial connection, using the "TX" (transmit) and "RX" (receive) pins of the Arduinos. You just connect the TX pin from Arduino #1 to the "RX" pin of Arduino #2 - and: connect the GND pins of the two.
In the setup code for both, you need to start the serial connection with the same baud rate, e.g.
void setup(){
Serial.begin(9600);
}
Arduino #1 is sending a byte using the following command:
byte color = 0; // declare the variable "color"
color = 3; // set the variable to any value in the range [0-255]
Serial.write(color); // transmit the byte-variable "color"
Arduino #2 is receiving the byte. Therefore it needs to continuously check for new serial data.
void loop() {
byte data = 0;
// - check for new serial data - and respond accordingly
if (Serial.available() > 0) {
int x = Serial.read(); // The "Serial.read" command returns integer-type
data = x; //
// - now: do something with "data"
if (data == 0) {
// "red" was received ... do something ...
} else if (data == 1) {
// "green" was received ... do something ...
} else if (data == 2) {
// ... and so on, and so on ...
}
}
// ... do other tasks
}
Make sure that in the "other tasks" you are not using the command "delay", as this would prevent your code from checking the serial for new data in a timely manner.
In exactly the same way, your Arduino #2 could also send data back to Arduino #1. In that case, you add one more cable connecting "TX" from #2 to "RX" of #1, and use the same code as above, on the respective other Arduino.
Serial is most universal, as you can test/simulate/use it by a broad variety of partners.
Here, you might code your possible values as human readable characters { '0' .. '5' } or
{'R', 'G', 'B', 'C', 'M', 'Y'} or whatever you like.
Eventually, I2C is a better way of serial communication.
Of course, an analog signal can be divided into 6 clearly distinguishable areas, if it's more about states than about events. You need electronics (low pass filter) to turn analogWrite PWM into analog constant values. And eventually, you have to handle the state transitions separately.
(Huh, sounds pretty complicated, doesn't it :) )
Examples of writing to a port seem to always use the port number as a constant, eg,
OCR2A = 180;
How do you write to the port when the port is unknown until run time. For example,
int port = (buttonPressed) ? 0x3b : 0x3c;
portWrite( port, 180 );
What I cannot find is the funtion portWrite(). Does something like that exist?
Robert's answer has some imprecise assertions and an incomplete answer.
Writing directly to port registers you can ruin other settings of the port and sometimes cause permanent damage to controller.
Can ruin other settings: true, you have to know what you are doing (for instance what pins are on the port you are manipulating, and know what are the functions you want to keep.
Can cause permanent damage: not really, or better not because of the port manipulation. If you wire a short circuit to ground and then set it as an output to 1, you can damage it whether you are using the port register or the digitalwrite. You have to be careful in both ways.
Now, returning to your problem, the enumeration is one way, but since the PORTB, PORTC, PORTD are just short name for values, you can set a variable and then use it to indirectly access it.
The type for this kind of variable is a volatile pointer to a byte (volatile means that write and read operations cannot be optimized by the compiler, since the value can change even between two operations):
volatile uint8_t *variablePortRegister;
You just have to load it with the address (so with the & symbol) of the register you want to change:
variablePortRegister = &PORTC;
then use the pointer to change the value
PORTC = 0x12;
becomes
(*variablePortRegister) = 0x12;
This is a short example. For it to work, connect a LED with resistor on arduino pin 5 (bit 5 of PORTD). The LED on the board (labeled L) is connected to pin 13 (bit 5 of PORTB).
The sketch will make one of the two leds blink for five times, then switch to the other. Only port manipulation instructions are used, and you can find that the way to read the port is the same as the one to write it.
volatile uint8_t *myportreg;
unsigned long lastTime;
uint8_t counter;
void setup() {
DDRB |= 0x20;
DDRD |= 0x20;
PORTB = 0;
PORTD = 0;
counter = 99; // trigger the register change immediately
}
void loop() {
if (counter >= 10)
{
counter = 0;
if (myportreg == &PORTD)
myportreg = &PORTB;
else
myportreg = &PORTD;
}
if ((millis() - lastTime) > 500)
{
lastTime = millis();
// change bit 5 of register
*myportreg = 0x20 ^ (*myportreg);
counter++;
}
}
EDIT: as Robert pointed out, it's much better to "use" just the pins you need (in this case, bit 5 of port B and D) rather than setting the whole port; this way you minimize the risk of screwing up something else. This edit is already included in the above code, so the code is correct
The port is a bit in one particular register. If you know the register and the position of the port in that particular register you can try this:
register = (1<<port) || register
to set the port to 1 and
register = (1<<port)^-1 && register
to set the port to 0.
Of course, you will need a switch somewhere to determine the register and the bit of the port in the register given the port name.
I'll go right to the point. My arduino reads values from the adc port and send them via serial port(values from 0 to 255). I save them in a byte type vector. After sending an specific signal to arduino, it starts to send to Qt app the data saved in the vector. Everything is working except that the arduino should send 800 values and the app receives less values than that. If I set the serial baud rate to 9600, I get 220 values. If, instead, I set the baud rate to 115200, I get only 20 values. Can you guys help me to fix this? I would like to use 115200 baud rate, because I need a good trasmision speed at this project(Real time linear CCD). I'll leave some code below:
Arduino code:
void sendData(void)
{
int x;
for (x = 0; x < 800; ++x)
{
Serial.print(buffer[x]);
}
}
This is the function that sends the values. I think is enough information, so I summarized it. If you need more code, please let me know.
Qt serial port setting code:
...
// QDialog windows private variables and constants
QSerialPort serial;
QSerialPortInfo serialInfo;
QList<QSerialPortInfo> listaPuertos;
bool estadoPuerto;
bool dataAvailable;
const QSerialPort::BaudRate BAUDRATE = QSerialPort::Baud9600;
const QSerialPort::DataBits DATABITS = QSerialPort::Data8;
const QSerialPort::Parity PARITY = QSerialPort::NoParity;
const QSerialPort::StopBits STOPBITS = QSerialPort::OneStop;
const QSerialPort::FlowControl FLOWCONTROL = QSerialPort::NoFlowControl;
const int pixels = 800;
QVector<double> data;
unsigned int dataIndex;
QByteArray values;
double maximo;
...
// Signal and slot connection.
QObject::connect(&serial, SIGNAL(readyRead()), this,SLOT(fillDataBuffer()));
...
// Method called when there's data available to read at the serial port.
void Ventana::fillDataBuffer()
{
dataIndex++;
data.append(QString::fromStdString(serial.readAll().toStdString()).toDouble());
if(data.at(dataIndex-1) > maximo) maximo = data.at(dataIndex-1);
/* The following qDebug is the one I use to test the recieved values,
* where I check that values. */
qDebug() << data.at(dataIndex-1);
}
Thanks and sorry if it's not so clear, it has been an exhausting day :P
Ok... I see two probelms here:
Arduino side: you send your data in a decimal form (so x = 100 will be sent as 3 characters - 1, 0 and 0. You have no delimiter between your data, so how your receiver will know that it received value 100 not three values 1, 0 and 0? Please see my answer here for further explanation on how to send ADC data from Arduino.
QT side: There is no guarantee on the moment when readyRead() signal will be triggered. It may be immediately after first sample arrives, but it may be raised after there are already couple of samples inside the serial port buffer. If that happens, your method fillDataBuffer() may process string 12303402 instead of four separate strings 123, 0, 340 and 2, because between two buffer reads four samples arrived. The bigger the baudrate, the more samples will arrive between the reads, which is why you observe less values with a bigger baud rate.
Solution for both of your problems is to append some delimiting byte for your data, and split the string in the buffer on that delimiting byte. If you don't want to have maximum data throughput, you can just do
Serial.print(buffer[x]);
Serial.print('\n');
and then, split incoming string on \n character.
Thank you very much! I did what you said about my arduino program and after solving that, I was still not getting the entire amount of data. So the the problem was in Qt. How you perfectly explain, the serial buffer was accumulating the values too fast, so the slot function "fillDataBuffer()" was too slow to process the arriving data. I simplified that function:
void Ventana::fillDataBuffer()
{
dataIndex++;
buffer.append(serial.readAll());
}
After saving all the values in the QByteArray buffer, I process the data separately.
Thanks again man. Your answer was really helpful.
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.