Wire (Helper Class Version)
reader, writer
that correspond to reading and writing marks the start of bus usage, and destroying the object performs the bus usage termination procedure.By creating objects inside the condition expression of an if statement, the object’s lifetime is limited to the scope of the if block. When exiting the if block, the object is destroyed, and at that time, the bus usage termination procedure is performed.
if (auto&& wrt = Wire.get_writer(...)) { // Object creation and device communication check
// The scope (curly braces) is the lifetime of wrt.
wrt << 0x00; // Write 0x00 using the mwx::stream interface
}
// wrt is destroyed when exiting the if block, and bus termination is performed
Also, since the read/write objects implement the mwx::stream
interface, operators like <<
can be used.
- Matching the start and end of bus usage with the object’s lifetime improves code readability and prevents omission of termination procedures.
- Unified reading and writing procedures via the
mwx::stream
interface.
Reading
This is a reading method using helper classes to perform reading and its termination procedure within a scope if() { ... }
.
const uint8_t DEV_ADDR = 0x70;
uint8_t au8data[6];
if (auto&& rdr = Wire.get_reader(DEV_ADDR, 6)) {
for (auto&& c: au8data) {
c = rdr();
}
}
// same above
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto&& rdr = Wire.get_reader(SHTC3_ADDRESS, 6)) {
rdr >> u16temp;
rdr >> u8temp_csum;
rdr >> u16humd;
rdr >> u8humd_csum;
}
Above, the rdr
object generated by the get_reader()
method is used to read one byte at a time. The method parameter specifies the two-wire serial ID to read.
- The
rdr
object is created insideif(...)
. (The type is resolved as a universal referenceauto&&
by type inference.) - The created
rdr
object definesoperator bool ()
and is used for evaluation in the condition. If communication is possible with the specified ID, it returnstrue
. - The
rdr
object definesint operator () (void)
, which reads one byte from the two-wire serial bus when called. Returns-1
on failure, or the read byte value on success. - The destructor of
rdr
is called at the end of theif() { ... }
scope, issuing aSTOP
on the two-wire serial bus.
get_reader(addr, read_count=0)
periphe_wire::reader
get_reader(uint8_t addr, uint8_t read_count = 0)
Obtains a worker object used for I2C reading.
Parameter | Description |
---|---|
addr | I2C address for reading |
read_count | Number of bytes to read (if specified, a STOP bit is issued at the end of the transfer). If 0 is specified, no STOP bit is issued (some devices may work without it). |
Writing (writer
)
This is a writing method using helper classes to perform writing and its termination procedure within a scope if() { ... }
.
const uint8_t DEV_ADDR = 0x70;
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) {
wrt(SHTC3_TRIG_H);
wrt(SHTC3_TRIG_L);
}
// same above
if (auto&& wrt = Wire.get_writer(DEV_ADDR)) {
wrt << SHTC3_TRIG_H; // int type is handled as uint8_t
wrt << SHTC3_TRIG_L;
}
Above, the wrt
object generated by the get_writer()
method is used to write one byte at a time. The method parameter specifies the two-wire serial ID to write.
- The
wrt
object is created insideif(...)
. (The type is resolved as auto to avoid long type names.) - The created
wrt
object definesoperator bool ()
and is used for evaluation in the condition. If communication is possible with the specified ID, it returnstrue
. - The
wrt
object definesint operator () (void)
, which writes one byte to the two-wire serial bus when called. Returns-1
on failure, or the written byte value on success. - The destructor of
wrt
is called at the end of theif() { ... }
scope, issuing aSTOP
on the two-wire serial bus.
get_writer()
periph_wire::writer
get_writer(uint8_t addr)
Obtains a worker object used for I2C writing.
Parameter | Description |
---|---|
addr | I2C address for writing |
Worker Object (writer)
<<
operator
operator << (int c)
operator << (uint8_t c)
operator << (uint16_t c)
operator << (uint32_t c)
int
and uint8_t
types transfer 8 bits. Data order is big-endian (higher byte transferred first).
()
operator
operator() (uint8_t val)
operator() (int val)
Writes one byte.
Worker Object (reader)
>>
operator
operator >> (uint8_t& c)
operator >> (uint16_t& c)
operator >> (uint32_t& c)
operator >> (uint8_t(&c)[N]) // fixed array of N bytes
Reads the size of each data type. Data order is big-endian (first transferred byte is stored in the higher byte).
()
operator
int operator() (bool b_stop = false)
// example
uint8_t dat[6];
if (auto&& rdr = Wire.get_reader(0x70)) {
for(uint8_t& x : dat) {
x = rdr();
}
}
Reads one byte. Returns -1 on error, or the read byte on success.
If b_stop
is set to true
, a STOP bit is issued on that read.
Example
The following example is a measurement example for the environmental sensor pal’s temperature and humidity sensor SHTC3.
Wire.begin();
// reset (may not necessary...)
if (auto&& wrt = Wire.get_writer(0x70)) {
wrt << 0x80; // SHTC3_SOFT_RST_H
wrt << 0x05; // SHTC3_SOFT_RST_L
}
delay(5); // wait some
// start read
if (auto&& wrt = Wire.get_writer(0x70)) {
wrt << 0x60; // SHTC3_TRIG_H
wrt << 0x9C; // SHTC3_TRIG_L
}
delay(10); // wait some
// read result
uint16_t u16temp, u16humd;
uint8_t u8temp_csum, u8humd_csum;
if (auto&& rdr = Wire.get_reader(0x70, 6)) {
rdr >> u16temp;
rdr >> u8temp_csum;
rdr >> u16humd;
rdr >> u8humd_csum;
}
// checksum 0x31, init=0xFF
if (CRC8_u8CalcU16(u16temp, 0xff) != u8temp_csum) {
Serial << format("{SHTC3 T CKSUM %x}", u8temp_csum); }
if (CRC8_u8CalcU16(u16humd, 0xff) != u8humd_csum) {
Serial << format("{SHTC3 H CKSUM %x}", u8humd_csum); }
// calc temp/humid (degC x 100, % x 100)
int16_t i16Temp = (int16_t)(-4500 + ((17500 * int32_t(u16temp)) >> 16));
int16_t i16Humd = (int16_t)((int32_t(u16humd) * 10000) >> 16);
Serial << "temp=" << int(i16Temp)
<< ",humid=" << int(i16Humd) << mwx::crlf;