3.3.7
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
|
||||
This Sketch demonstrates how to use onReceive(callbackFunc) with HardwareSerial
|
||||
|
||||
void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout = false)
|
||||
|
||||
It is possible to register an UART callback function that will be called
|
||||
every time that UART receives data and an associated UART interrupt is generated.
|
||||
|
||||
In summary, HardwareSerial::onReceive() works like an RX Interrupt callback, that
|
||||
can be adjusted using HardwareSerial::setRxFIFOFull() and HardwareSerial::setRxTimeout().
|
||||
|
||||
In case that <onlyOnTimeout> is not changed or it is set to <false>, the callback function is
|
||||
executed whenever any event happens first (FIFO Full or RX Timeout).
|
||||
OnReceive will be called when every 120 bytes are received(default FIFO Full),
|
||||
or when RX Timeout occurs after 1 UART symbol by default.
|
||||
|
||||
This example demonstrates a way to create a String with all data received from UART0 only
|
||||
after RX Timeout. This example uses an RX timeout of about 3.5 Symbols as a way to know
|
||||
when the reception of data has finished.
|
||||
In order to achieve it, the sketch sets <onlyOnTimeout> to <true>.
|
||||
|
||||
The onReceive() callback is called whenever the RX ISR is triggered.
|
||||
It can occur because of two possible events:
|
||||
|
||||
1- UART FIFO FULL: it happens when internal UART FIFO reaches a certain number of bytes.
|
||||
Its full capacity is 127 bytes. The FIFO Full threshold for the interrupt can be changed
|
||||
using HardwareSerial::setRxFIFOFull(uint8_t fifoFull).
|
||||
Default FIFO Full Threshold is set in the UART initialization using HardwareSerial::begin()
|
||||
This will depend on the baud rate used when begin() is executed.
|
||||
For a baud rate of 115200 or lower, it it just 1 byte, mimicking original Arduino UART driver.
|
||||
For a baud rate over 115200 it will be 120 bytes for higher performance.
|
||||
Anyway, it can be changed by the application at any time.
|
||||
|
||||
2- UART RX Timeout: it happens, based on a timeout equivalent to a number of symbols at
|
||||
the current baud rate. If the UART line is idle for this timeout, it will raise an interrupt.
|
||||
This time can be changed by HardwareSerial::setRxTimeout(uint8_t rxTimeout).
|
||||
<rxTimeout> is bound to the clock source.
|
||||
In order to use it properly, ESP32 and ESP32-S2 shall set the UART Clock Source to APB.
|
||||
|
||||
When any of those two interrupts occur, IDF UART driver will copy FIFO data to its internal
|
||||
RingBuffer and then Arduino can read such data. At the same time, Arduino Layer will execute
|
||||
the callback function defined with HardwareSerial::onReceive().
|
||||
|
||||
<bool onlyOnTimeout> parameter can be used by the application to tell Arduino to only execute
|
||||
the callback when Rx Timeout happens, by setting it to <true>.
|
||||
At this time all received data will be available to be read by the Arduino application.
|
||||
The application shall set an appropriate RX buffer size using
|
||||
HardwareSerial::setRxBufferSize(size_t new_size) before executing begin() for the Serial port.
|
||||
|
||||
MODBUS timeout of 3.5 symbol is based on these documents:
|
||||
https://www.automation.com/en-us/articles/2012-1/introduction-to-modbus
|
||||
https://minimalmodbus.readthedocs.io/en/stable/serialcommunication.html
|
||||
*/
|
||||
|
||||
// global variable to keep the results from onReceive()
|
||||
String uart_buffer = "";
|
||||
// The Modbus RTU standard prescribes a silent period corresponding to 3.5 characters between each
|
||||
// message, to be able to figure out where one message ends and the next one starts.
|
||||
const uint32_t modbusRxTimeoutLimit = 4;
|
||||
const uint32_t baudrate = 19200;
|
||||
|
||||
// UART_RX_IRQ will be executed as soon as data is received by the UART and an RX Timeout occurs
|
||||
// This is a callback function executed from a high priority monitor task
|
||||
// All data will be buffered into RX Buffer, which may have its size set to whatever necessary
|
||||
void UART0_RX_CB() {
|
||||
while (Serial0.available()) {
|
||||
uart_buffer += (char)Serial0.read();
|
||||
}
|
||||
}
|
||||
|
||||
// setup() and loop() are functions executed by a low priority task
|
||||
// Therefore, there are 2 tasks running when using onReceive()
|
||||
void setup() {
|
||||
// Using Serial0 will work in any case (using or not USB CDC on Boot)
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
// UART_CLK_SRC_APB will allow higher values of RX Timeout
|
||||
// default for ESP32 and ESP32-S2 is REF_TICK which limits the RX Timeout to 1
|
||||
// setClockSource() must be called before begin()
|
||||
Serial0.setClockSource(UART_CLK_SRC_APB);
|
||||
#endif
|
||||
// the amount of data received or waiting to be proessed shall not exceed this limit of 1024 bytes
|
||||
Serial0.setRxBufferSize(1024); // default is 256 bytes
|
||||
Serial0.begin(baudrate); // default pins and default mode 8N1 (8 bits data, no parity bit, 1 stopbit)
|
||||
// set RX Timeout based on UART symbols ~ 3.5 symbols of 11 bits (MODBUS standard) ~= 2 ms at 19200
|
||||
Serial0.setRxTimeout(modbusRxTimeoutLimit); // 4 symbols at 19200 8N1 is about 2.08 ms (40 bits)
|
||||
// sets the callback function that will be executed only after RX Timeout
|
||||
Serial0.onReceive(UART0_RX_CB, true);
|
||||
Serial0.println("Send data using Serial Monitor in order to activate the RX callback");
|
||||
}
|
||||
|
||||
uint32_t counter = 0;
|
||||
void loop() {
|
||||
// String <uart_buffer> is filled by the UART Callback whenever data is received and RX Timeout occurs
|
||||
if (uart_buffer.length() > 0) {
|
||||
// process the received data from Serial - example, just print it beside a counter
|
||||
Serial0.print("[");
|
||||
Serial0.print(counter++);
|
||||
Serial0.print("] [");
|
||||
Serial0.print(uart_buffer.length());
|
||||
Serial0.print(" bytes] ");
|
||||
Serial0.println(uart_buffer);
|
||||
uart_buffer = ""; // reset uart_buffer for the next UART reading
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
Reference in New Issue
Block a user