For suitable output, we recommend to use Google Chrome (15+) or Microsoft Edge (79+).
As of 2025-07-24Wire
Read/write as 2-wire serial (I2C) master (controller) (mwx::periph_wire)
Performs read/write operations as a 2-wire serial (I2C) master (controller).
Definition
Alias Definition
using TwoWire = mwx::periph_twowire<MWX_TWOWIRE_RCVBUFF>;
mwx::periph_wire<MWX_TWOWIRE_RCVBUFF>
can be referenced as TwoWire
.
Type Definitions
The following typedefs are used for argument and return types:
typedef uint8_t size_type;
typedef uint8_t value_type;
Notes
Some APIs do not strictly handle STOP bits.
In addition to this explanation, several argument types are defined for write()
and writer::operator()
:
- Fixed-size array type
uint8_t cmds[]={11,12};
...
Wire.write(cmds);
initializer_list<>
type
Wire.write({11,12})
Initialization and Termination
Creating a Wire
instance
The instance and necessary initialization are handled within the library. In user code, call Wire.begin()
to start using it.
When using the requestFrom()
method, you can specify the size of a FIFO queue for temporary data storage. At compile time, set the number of bytes via the macro MWX_TWOWIRE_BUFF
. The default is 32 bytes.
Example: -DMWX_TWOWIRE_BUFF=16
begin()
void begin(
const size_type u8mode = WIRE_100KHZ,
bool b_portalt = false)
Initializes the hardware.
If you operate Wire without initialization, the TWELITE wireless module will hang.
When waking from sleep, if Wire was active just before sleep, it will restore its previous state.
Parameter | Description |
---|
u8mode | Specifies the bus frequency. Default is 100KHz (WIRE_CONF::WIRE_100KHZ ). You can specify WIRE_CONF::WIRE_??KHZ where ?? can be 50 , 66 , 80 , 100 , 133 , 160 , 200 , 266 , 320 , 400 . |
b_portalt | Changes the hardware pin assignment. |
Example
void setup() {
...
Wire.begin();
...
}
void wakeup() {
...
Wire.begin();
...
}
Reading and Writing
There are two procedures for reading and writing. Use either as needed.
Others
Probe (Device Presence Check)
bool probe(uint8_t address)
Checks if the device specified by address
responds. Returns true
if the device exists.
setClock()
void setClock(uint32_t speed)
This is intended to change the bus frequency, but it performs no action.
1 - Wire (Member Function Version)
Wire (using member functions)
This method using member functions has relatively low abstraction and follows a general API structure similar to that provided by C language libraries. It offers a more intuitive procedure for operating a two-wire serial bus.
However, you need to explicitly manage the start and end of bus usage.
Reading
requestFrom()
size_type requestFrom(
uint8_t u8address,
size_type length,
bool b_send_stop = true)
Reads a specified number of bytes in one operation. The result is stored in a queue, so you should call the .read()
method repeatedly until the queue is empty immediately afterward.
Parameter | Description |
---|
u8address | I2C address to read from |
length | Number of bytes to read |
b_send_stop=true | If true , a STOP bit is issued at the end of reading |
Return type size_type | Number of bytes read. 0 indicates failure |
Code Example
int len = Wire.requestFrom(0x70, 6);
for (int i = 0; i < 6; i++) {
if (Wire.available()) {
au8data[i] = Wire.read();
Serial.print(buff[i], HEX);
}
}
// skip the rest (just in case)
// while (Wire.available()) Wire.read(); // normally, not necessary.
Writing
The writing process starts with beginTransmission()
, then proceeds with the write()
method. After the entire write operation is complete, call endTransmission()
.
#define DEV_ADDR (0x70)
const uint8_t msg[2] =
{SHTC3_SOFT_RST_H, SHTC3_SOFT_RST_L};
Wire.beginTransmission(DEV_ADDR);
Wire.write(msg, sizeof(msg));
Wire.endTransmission();
beginTransmission()
void beginTransmission(uint8_t address)
Initializes a write transfer. After the write process, call endTransmission()
promptly.
Parameter | Description |
---|
u8address | I2C address to write to |
write(value)
size_type write(const value_type value)
Writes a single byte.
Parameter | Description |
---|
value | Byte to write |
Return size_type | Number of bytes written. 0 indicates an error. |
write(*value, quantity)
size_type write(
const value_type* value,
size_type quantity)
Writes a sequence of bytes.
Parameter | Description |
---|
*value | Byte sequence to write |
size_type | Number of bytes |
Return size_type | Number of bytes written. 0 indicates an error. |
endTransmission()
uint8_t endTransmission(bool sendStop = true)
Finalizes the write operation.
Parameter | Description |
---|
sendStop = true | Issues a STOP bit |
Return uint8_t | 0: success, 4: failure |
2 - Wire (Helper Class Version)
Wire (How to use with helper classes)
The helper class version is a more abstract implementation. Generating objects 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 inside if(...)
. (The type is resolved as a universal reference auto&&
by type inference.) - The created
rdr
object defines operator bool ()
and is used for evaluation in the condition. If communication is possible with the specified ID, it returns true
. - The
rdr
object defines int 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 the if() { ... }
scope, issuing a STOP
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 inside if(...)
. (The type is resolved as auto to avoid long type names.) - The created
wrt
object defines operator bool ()
and is used for evaluation in the condition. If communication is possible with the specified ID, it returns true
. - The
wrt
object defines int 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 the if() { ... }
scope, issuing a STOP
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;