I have the following code (I'm using Arduino IDE and a NodeMCU with a MAX3232):
#include <SoftwareSerial.h>
SoftwareSerial RS232Serial(D1, D2); // RX | TX
void setup() {
Serial.begin(9600);
while (!Serial);
RS232Serial.begin(9600);
while (!RS232Serial);
}
void loop() {
Serial.println("Sending msg...");
char msg[] = {0x7E, 0x00, 0x78, 0xF0, 0x7E};
RS232Serial.write(msg, sizeof(msg));
Serial.println("Waiting incomming message:");
while(RS232Serial.available() <= 0) {
delay(1);
}
while(RS232Serial.available() > 0) {
Serial.print(RS232Serial.read(), HEX);
}
Serial.println("");
Serial.println("------------ END -----------");
}
I'm using Docklight to test the communication. So far I'm able to receive the HEX that the NodeMCU boards sends first char msg[] = {0x7E, 0x00, 0x78, 0xF0, 0x7E};. But I'm unable to receive the data properly from Docklight.
The HEX I'm trying to send from Docklight is 7E 00 00 70 15 7E. Debugging with serial monitor, sometimes I receive just 7E and sometimes 0FF, never the complete message. Baud rate, start/stop bits and parity are set to default.
What's wrong with my code?
One reason for not working as expected is:
You are processing the answer as soon as one byte has appeared in the receive buffer.
There is a related example in the Docklight Application Note Arduino Serial Communication - check the code listing on page 5. It makes use of the Arduino SerialEvent() function to collect the incoming telegram byte-per-byte. Only after receiving the end of telegram mark (here: a line feed "\n" character), it sets a flag that tells the code in the main loop() to do something with the accumulated data telegram.
The SerialEvent approach used in the Docklight exampleis not a must. You can solve this inside loop() alone, too. But you certainly need to change the
while(RS232Serial.available() <= 0) {
...
while(RS232Serial.available() > 0) {
parts to something that will wait until a full telegram has been received (or a timeout has occurred).
Now what irritates me still is that you write you sometimes receive "0FF" even though you never send it from Docklight. This could indicate still a second problem on the actual RS232 communication, but it's hard to guess without extra information.
But re-working the telegram receiving part as described above should already make things much clearer and then the source of the "0FF" is probably more obvious.
while(RS232Serial.available() <= 0) {
delay(1);
}
You are only waiting for the serial buffer to have at least 1 byte, but you are not guaranteed that your full message (6 bytes) will be present, when you call RS232Serial.available().
You should wait for the serial buffer to accumulate at least 6 bytes, before you try to read them.
while(RS232Serial.available() < 6) {
delay(1);
}
They you can read the full buffer with:
while(RS232Serial.available() > 0) {
Serial.print(RS232Serial.read(), HEX);
}
or only 6 bytes with:
for (int i=0; i<6; i++) {
Serial.print(RS232Serial.read(), HEX);
}
I don't know about your 0FF, but Serial.print(RS232Serial.read(), HEX) doesn't zero pad the hex string and this could actually be 00 0F 0F or 00 FF.
You should print out the bytes with:
byte b = RS232Serial.read();
if (b < 16) Serial.print('0'); // zero pad
Serial.print(b, HEX);
Serial.print(' '); // add space after each byte
Related
Following this tutorial:
Arduino LED Dimmer Example
I added the Serial.println(brightness); at the bottom to see what gets written to the brightness variable and only get back 48 no matter the value sent by serial to the arduino.
As you can see the value of brightness goes from 50 to 48 where it settles. The sent data is in pink and the black data is the response from the arduino.
What else could I try.
Thanks
Using the Hercules utility to establish a serial link to the arduino.
Hercules Utility Showing communication with Arduino
The oscilloscope sees this:
PWM signal from oscilloscope
const int ledPin = 9; // the pin that the LED is attached to
void setup() {
// initialize the serial communication:
Serial.begin(9600);
// initialize the ledPin as an output:
pinMode(ledPin, OUTPUT);
}
void loop() {
byte brightness;
// check if data has been sent from the computer:
if (Serial.available()) {
// read the most recent byte (which will be from 0 to 255):
brightness = Serial.read();
// set the brightness of the LED:
analogWrite(ledPin, brightness);
Serial.println(brightness);
}
}
your problem is obvious in the image you provided , for example in the image it shows
when send 100 , the arduino responded with 49 , 48 , 48 which is the ascii representation of the 100 , refer to ascii table where
'1' is equivalent to 49
'0' is equivalent to 48
which means that you send to the arduino the number 100 not as a number but as a string where your terminal sends 1 first in its ascii representation which is 49 then it sends 0 in its ascii representation which is 48 then it sends another 0 in its ascii representation which is 48.
to solve this problem:
in your pc side , try to change that in your terminal settings
or
in your arduino code , instead of brightness = Serial.read(); write brightness = Serial.parseInt(); , refer to Serial.parseInt() docs where it says that :
Looks for the next valid integer in the incoming serial. The function terminates if it times out
meaning that it will convert "100" (string) into 100 (number) in your arduino side .
also change byte brightness; into int brightness; as Serial.parseInt() returns the next valid int
Thank you abdo salm, your suggestion educated me and resolved my problem at the same time. Answer updated for anyone who stumbles across the same rookie issue (see snippet below).
So in conclusion, the example code expected a number in the range of
00000000 to 11111111 (0 to 255 as a single binary byte)
I was instead sending multiple bytes that represented One, Zero and Zero on the ASCII table
11000100 (49)
11000000 (48)
11000000 (48)
erroneously thinking I was sending 100 which is 110010000 in binary.
I altered the code with brightness = Serial.parseInt(); as abdo salm suggested.
Here is the Hercules (or similar) friendly version of the Arduino Dimmer Example.
const int ledPin = 9; // the pin that the LED is attached to
int brightness;
void setup() {
// initialize the serial communication:
Serial.begin(9600);
// initialize the ledPin as an output:
pinMode(ledPin, OUTPUT);
}
void loop() {
// check if data has been sent from the computer:
if (Serial.available()) {
// read the most recent byte (which will be from 0 to 255):
brightness = Serial.parseInt();
// set the brightness of the LED:
analogWrite(ledPin, brightness);
Serial.println(brightness);
}
}
Im trying to read the pressure from a sensor using I2C. Per the datasheet, I am writing a start command (0xAA) and then reading the data in the pressure registers as bytes. (Reference picture below):
Registers of Pressure Data
Here is the code that I am using:
#include <Adafruit_I2CDevice.h>
#define I2C_ADDRESS 0x29
Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS);
void setup() {
while (!Serial) { delay(10); }
Serial.begin(115200);
Serial.println("I2C device read and write test");
if (!i2c_dev.begin()) {
Serial.print("Did not find device at 0x");
Serial.println(i2c_dev.address(), HEX);
while (1);
}
Serial.print("Device found on address 0x");
Serial.println(i2c_dev.address(), HEX);
}
void loop(){
uint8_t buffer[7];
buffer[0] = 0xAA;
i2c_dev.write_then_read(buffer, 1, buffer, 2, false);
Serial.println();
Serial.print(buffer[0], HEX);
Serial.print(" ");
Serial.print(buffer[1]);
Serial.print(" ");
Serial.print(buffer[2]);
Serial.print(" ");
Serial.print(buffer[3]);
Serial.println();
delay(500);
}
The first Register (buffer[0]) is the status register, which is supposed to return 0x40 if the operation succeeded without any errors. However, I am getting 0x60 when I read the first register. Is my code incorrect?
Here is the datasheet for the pressure sensor: https://www.farnell.com/datasheets/3208001.pdf
0x40 is completed reading without error.
In datasheet you can read that "When the Busy bit in the Status byte is zero, this indicate that valid data is ready, and a full Data Read of all 7 bytes may be performed"
So i think you just need to wait some time (and poll status bit) and then read data.
Hi Stephen are you aware the 0x40 is written out in binary 01000000 and 0x60 01100000?
If you look at table 3 you can find the relevant bits in that return byte. The first 0 is bit 7. The first 1 bit 6 etc to bit 0 (the utmost right 0)
Bit 5 (the second 1 from the left) is 1, so that means the device is busy.
Sometimes i use a binary to hex calculator.
You could read out the value per x time and check if it will become 0x40 and then process the other data bytes.
I'm a newbie to both Arduino programming and I2C in general. I'm using an Arduino Micro to extract data from the capacitance sensor AD7150.
Now in trying to answer my question myself, I've seen the basic setup of the Wire I2C communication a lot, and I feel like I have it down. But for some reason, Wire.read() only ever returns 7-bit bytes to me when it should be 8 bits from all that I see and understand. Another problem is that even if I read out a register that should be stable, i.e. the Chip ID register, the output "wobbles" over time. Google hasn't helped so far. Maybe one of you has the magic answer?
#include <Wire.h>
#define AD 0x48
#define ID 0x17
byte data1;
byte data2;
uint16_t data_combined;
void setup() {
analogReference(EXTERNAL);
Wire.begin();
Serial.begin(9600);
}
void loop()
{
Wire.beginTransmission(AD);
Wire.write(ID);
Wire.endTransmission(); // I checked the output; is successful
delay(10);
Wire.requestFrom(0x48,2); // Unsure whether to ask for 1 or 2 bytes here; the ChipID, as far as I understand, should only be one byte, but I've been told that I2C transmissions always include at least 2 bytes
data1 = Wire.read(); // so I just save both bytes separately here.
data2 = Wire.read();
data_combined = word(data1,data2);
Serial.print("First byte from Chip ID register: ");
Serial.print(data1,BIN);
Serial.print(" | Second byte from Chip ID register: ");
Serial.print(data2,BIN);
Serial.print(" | Combined to make: ");
Serial.println(data_combined,BIN);
Serial.println("---");
delay( 200);
}
I'm experiencing unexpected results using wiringPi's wiringPiI2CWriteReg16() function, and I'm not sure if it's due to incorrect usage, or something else. This is the declaration for the function:
extern int wiringPiI2CWriteReg16 (int fd, int reg, int data);
There are notes within the wiringPiI2C.c file that state it resembles Linux's SMBus code, if that helps.
On my Arduino (both an Uno R3 and a Trinket Pro), I am running this pared-down sketch:
#include <Wire.h>
#define SLAVE_ADDR 0x04
void receive_data (int num_bytes){
Serial.print("bytes in: ");
Serial.println(num_bytes);
while(Wire.available()){
int data = Wire.read(); // tried char, uint8_t etc
Serial.println(data);
}
Serial.print("\n");
}
void setup() {
Serial.begin(9600);
Wire.begin(SLAVE_ADDR);
Wire.onReceive(receive_data);
}
void loop() {
delay(500);
}
I would think that Wire.read() would break things apart at the byte boundary, but that's not occurring in my case. Perhaps this is my issue... a misunderstanding.
Nonetheless, I have this C code (requires wiringPi v2.36+ to be installed):
// word.c
#include <wiringPiI2C.h>
void main (){
int fd = wiringPiI2CSetup(0x04);
wiringPiI2CWriteReg16(fd, 0x00, 255);
wiringPiI2CWriteReg16(fd, 0x01, 256);
}
Compiled like this:
gcc -o word word.c -lwiringPi
When run, ./word, I receive the following on my Arduino's serial output:
bytes in: 3
0
255
0
bytes in: 3
1
0
1
In the first call to wiringPiI2CWriteReg16(), I expect the first byte in the output to be zero (0x00) as that's the register address I'm requesting. The second byte (255) is also correct. The third byte (0) is meaningless from what I can tell (as I'm only sending in one byte as data).
However, in the second call to that function, I do get the correct output for the register (first byte as 0x01 == 1), but the second byte is zero, and the third byte has what appears to be the correct remainder (255 == one byte, + 1). The problem is, is that the second byte is 0.
The exact same effect happens if I pass in 511 or for that matter, any number as the data in the call.
My question is whether I'm missing something glaringly obvious (I'm relatively new to C and Arduino), and/or if I can get some pointers on how to troubleshoot this more thoroughly.
I found that the problem was in my Arduino code. In the official Raspi forums, Gordon tipped me off that the bytes are read in separately, LSB first. Throughout all of my searching, I hadn't come across that, and really didn't quite understand what was happening. After changing my I2C read loop code in my Arduino sketch to this:
while(Wire.available()){
Wire.read(); // throw away register byte
int16_t data = Wire.read(); // LSB
data += Wire.read() << 8; // MSB
Serial.print("data: ");
Serial.println(data);
}
...everything works. In effect, that's at least one way to read two-byte values over I2C on the Arduino and put the bytes back together.
I trying to read SD card image from arduino (20KB - JPEG -using SD library) and transfer through Xbee (series 2) Due to limitation on xbee, have to break to 60 bytes and send until the complete file send. I think, the image stored in ASCII character.
void setup() {
Serial.begin(115200);
if (!SD.begin()) {
Serial.println("begin failed");
return;
}
file = SD.open("PIC00.JPG");
}
void loop() {
Serial.flush();
char buf[64];
if(file) {
while (file.position() < file.size())
{
while (file.read(buf, sizeof(buf)) == sizeof(buf)) // read chunk of 64bytes
{
Serial.write(buf); // Send to xbee via serial
delay(50);
}
}
file.close();
} }
But this method, i can not see complete image transfer at Serial Write. After a while, i came to know the start of image is Y (ascii chracter) and U (end character). I can see only end start character Y can not see the proper end character.
Please advise...trying hard solve this issue. Big Thanks...
The JPEG is actually binary data. To send it, use the version of Serial.write() that includes a length parameter for the number of bytes to send. Otherwise, it thinks you're trying to send a null-terminated string.
(Declare bytesread as a byte at the top of your function.)
while ((bytesread = file.read(buf, sizeof(buf))) > 0)
{
Serial.write(buf, bytesread); // Send to xbee via serial
delay(50);
}
Also note that the delay might not be sufficient -- you should really be using a serial port with hardware flow control (monitoring /CTS from the XBee module) so you know when it's clear to send data to it.