Sending 0x00 using I2C - c++

I am using the Wire class to have two Arduino Unos communicate using I2C. It seems that the Wire class ends transmission on a value of 0. So if I send bytes 0x01, 0x02, 0x00, and 0x04, the master receives: 0x01, 0x02, 0xFF, 0xFF.
It seems odd that a communication network designed for processor communication cannot send a 0x00. All the examples for I2C that I have seen use ASCII only. Inter-processor communication restricted to ASCII does not seem to make any sense. Am I missing something with I2C or is this just an implementation limitation of the Arduino Wire class?
Master
void loop() {
Wire.requestFrom(2, 4);
while(Wire.available()) {
byte b = (byte) Wire.read();
Serial.println(b);
}
delay(1000);
}
Slave
void requestEvent() {
char bytes[4] = {0x01,0x02,0x00,0x04};
Wire.write(bytes);
}
The results are: 1 2 255 255.
When that 0x00 was 0x03 I got the expected: 1 2 3 4.

You are passing an array of chars to Wire.write()... This makes Wire treat the argument as a null-terminated string, and therefore the NULL byte terminates the transmission. If you want to send bytes, call the write() function once for each byte, passing it byte types.
Alternatively, you can call the write(const uint8_t *, size_t); version: you pass it a pointer to / array of bytes, but you also have to give it a size of your data array.

Do you have Wire.begin() and Wire.beginTransmission() (with correct address) happening before calling Wire.write()?

Related

Read consecutive memory blocks smartcard Mifare 1k

I'm using a Mifare 1k card and the acr1252 reader; I'm developing using visual c++ and the Winscard library.
I've successful achieved to read the single block using the following code:
// Read binary blocks
// Class: FF
// INS: B0
// P1: 00
// P2: the starting block number
// Le: length to read (multiple of 16)
BYTE ReadBinary[] = { 0xFF, 0xB0, 0x00, 0x00, 0x10 };
BYTE readRes[256] = { 0 };
DWORD lenRead = sizeof(readRes);
SCardTransmit(hCard, SCARD_PCI_T1, ReadBinary, sizeof(ReadBinary), NULL, readRes, &lenRead)
This function call returns SCARD_S_SUCCESS and readRes contains the block value + SW1 and SW2 with values 0x90 0x00 (success)
What i'm trying to do is reading 2 consecutive memory blocks (i.e. the block 0 and the block 1 of sector 0) using the same function only changing the apdu command with:
ReadBinary[] = { 0xFF, 0xB0, 0x00, 0x00, 0x20 };
// Last byte changed to read 2 blocks
But is not working: the return status still SCARD_S_SUCCESS but the data read contains only SW1 and SW2 with values 0x63 0x00 (error).
AFAIK with Mifare 1k cards is possible to read the first 3 blocks of a sector but all the reading tests that try to read more than a sector fail with that error.
Am i missing something?

Reading value with I2C protocol from magnetoscope

I'm pretty new still to all this. So please excuse me if there is something obvious.
I have been struggling with the included datasheet for a magnetoscope. For some reason it seems like everything is working, but when I wave a magnet at it, I'm not really getting any response in the serial.
So here is some information.
#include <Wire.h>
void setup() {
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial communication at 9600bps
}
void loop() {
int reading = 0;
int Address = 30;
Wire.beginTransmission(Address);
Wire.write(byte(0x03));
Wire.write(byte(0x04));
Wire.endTransmission();
Wire.requestFrom(Address, 2);
delay(10);
if (2 <= Wire.available()) {
reading = Wire.read();
reading = reading << 8;
reading |= Wire.read();
Serial.println(int(reading));
}
delay(250); // wait a bit since people have to read the output :)
}
With this code, I receive a number.
-5637
-5637
-5637
-5637
-5637
But then if I remove the following line Wire.write(byte(0x03));, my output does not change. The value from the device is supposed to be expressed as two's complement.
So at first I thought I didn't know how to send multiple bytes to the device, but after some research I found that I was doing it right (I think).
Then if I only put Wire.write(byte(0x03)); I receive "0" as response. Reading the datasheet I see that response 0 means that the command is invalid.
I included the datasheet to this post. Can someone point me in the right dirrection? The IC I'm using is an LSM303DLHC and I'm using it from this "sheild".
Here is the datasheet.
The following picture is a picture of the communication of the bus.
I believe the following code does this, which is like Table 11 in the datasheet:
Wire.beginTransmission(Address); // START and write to device address 0x1E
Wire.write(byte(0x03)); // Set the register pointer to sub-address 0x03
Wire.write(byte(0x04)); // Write a value of 0x04 to sub-address 0x3
Wire.endTransmission(); // STOP.
Then I suspect the device's register pointer gets automatically incremented from register 0x03 to 0x04. And then the rest of your code maybe reads two bytes from sub-address 0x04 and 0x05.
You didn't express your intention for your code but I suspect the above is NOT what you intended. My guess is that you intend to read two bytes from device address 0x1E, sub-address 0x03 and sub-address 0x04. Is that right?
You should be doing an operation like what is described in Table 13.
Wire.beginTransmission(Address); // START and write to device address 0x1E
Wire.write(byte(0x03)); // Set the register pointer to sub-address 0x03
Wire.requestFrom(Address, 2); // REPEAT-START and read 2 bytes from sub-address 0x03 and 0x04

QSerialPort reads hex values sepereatly

I'm using Qt's QSerialPort library to communicate with RS232. I connected ReadyRead signal to my readData() slot;
connect(comms,SIGNAL(readyRead()),this,SLOT(readData()));
When i send a string like "Hello World!" I can read all of data with comms.readAll() and comms.bytesAvailable() returns 12.
But when i send "Hello World!\n\r" it reads "Hello World!" and "\n\r" parts sepereatly and comms.bytesAvailable() returns 12 first, then 2.
And it's getting worse when i send hex bytes like (with no spaces)
0x0F 0x00 0x43 0x11 0x00 0x04 0x11 0x00 0x02 0x70
It reads values correctly but 1 or 2 bytes at a time. I tried waitForRead() but that doesn't help.
How can i read all incoming bytes at a time even it's not standart letter?
Try reading from the port while bytes are available:
if (f_port->bytesAvailable()) { // If there are bytes available
QByteArray f_data; // data container
f_data.clear();
if (f_port->open(QIODevice::ReadWrite)) { // Try to open the port
while(f_port->bytesAvailable()) { // Reading loop
f_data.append(f_port->readAll());
}
f_port->flush();
f_port->close();
}
qDebug() << f_data; // Check the result
}
Unfortunately you cannot be sure to have read all data.
You have to collect incoming data in some intermediate buffer and analyse it for commands complying to your protocol definition. That is, is must meet certain requirements like fixed length or particular starting byte (0x02 for instance) or ending byte (\r comes to mind) or a combination of those.
One way to do it is accumulating a buffer with the bytes you obtain.
Then verify if it's a correct command(that is up to you decide what is correct) and trigger the command you wanna do.
Also you should have a timer to remove trash from the buffer.
Let's see with an small pseudocode
static QByteArrray s_vBuffer;
readData()
{
s_vBuffer.append(....);
bool bValidCommand=VerifyCommand(s_vBuffer);
if(bValidCommand)
{
QByteArray vCommand=ExtractCommand(s_vBuffer);//also removing the part of the command
ExecuteCommand(vCommand);
}
else
{
//if timeout clear s_vBuffer
}
}
Other techniques involves checksums , CRC etc at the end of your command.etc

QT Serial send a Byte

Is there a way to send a byte to serial with QT.
I only found a function for sending chars.
serialport->write(const QByteArray &data)
I want to send a array with these three bytes in Hex: 0xF0 0x02 0x0D
Do you have something like
serialport->write(QByteArray::fromHex("F0020D"));
in mind ?
You send 8-bit values. "Hexadecimal" is just a form of notation of integer values.
QByteArray ba;
ba.resize(3);
ba[0] = 0xF0;
ba[1] = 0x02;
ba[2] = 0x0D;
serialport->write(ba);
or:
char arr[3] = {0xF0, 0x02, 0x0D};
QByteArray ba(arr, 3);
serialport->write(ba);

Append quint16/unsigned short to QByteArray quickly

In my project I'm working with QByteArrays appending data to them as the program goes. Most of the time, a simple quint8 gets appended just fine using QByteArray::append(). But when a quint16 gets appended, only 1 byte gets appended instead of 2.
QByteArray ba = QByteArray::fromHex("010203");
quint number(300);//300 in hex is 012c
ba.append(number);//What should be appended instead of just number?
//the current incorrect result is
ba.toHex() == "0102032c"
//the desired result is
ba.toHex() == "010203012c"
I've already tried this, but it just inserts the value as a string (4 bytes):
ba.append(QByteArray::number(number, 16));
What should I append to the QByteArray so both bytes of "number" get appended instead of just one byte? Also, the fastest method possible is preferred since this program needs to have great performance times. So absolutely no converting to QStrings.
Thanks for your time.
On its own, QByteArray only supports appending bytes; to append a big-endian representation of fixed-size integer types you can build your own operator<< (or what you prefer) overloads using the appropriate bit shifts:
QByteArray &operator<<(QByteArray &l, quint8 r)
{
l.append(r);
return l;
}
QByteArray &operator<<(QByteArray &l, quint16 r)
{
return l<<quint8(r>>8)<<quint8(r);
}
QByteArray &operator<<(QByteArray &l, quint32 r)
{
return l<<quint16(r>>16)<<quint16(r);
}
This allows you to write code like:
QByteArray b;
b<<quint16(300); // appends 0x01 0x2c
b<<quint8(4); // appends 0x04
b<<quint16(4); // appends 0x00 0x04
b<<quint32(123456); // appends 0x00 0x01 0xe2 0x40
b<<quint8(1)<<quin16(2)<<quint32(3); // appends 0x01 0x00 0x02 0x00 0x00 0x00 0x03
You should probably avoid writing
QByteArray b;
b<<1;
because in theory the output depends on the size of the current platform integer (although AFAIK on all platforms supported by Qt int is 32 bit).