First of all you are expecting too much of SoftwareSerial
running it at 115200. Whilst the documentation states:
speeds up to 115200 bps.
you have to understand the consequences of being a software UART. If the CPU is busy being a UART, that is time not doing other work. Personally I doubt that 115200 could be be achieved on a Nano, and certainly not whist getting anything much else done.
I suggest either:
- using a PC to send the necessary command to set the baud rate to something reasonable like 9600 (start low and increase until it becomes unreliable, then back-off, though given you present a report at 300ms intervals in the code, faster data rate offers no real benefit), or
- using the hardware
Serial
port for the LiDAR, and SoftwareSerial
for the data output. There is no real need to run the text output at 115200 for the amount of text output at the rate of output you have.
Second SoftwareSerial::read()
returns -1 if no data was available, and the TFMini code does not check for that, so it is likely to produce erroneous results - it does not wait on a timeout. If it works at all, it will be because sufficient data happens to be buffered during the 300 millisecond delay, which is itself ill-advised.
Now given an appropriate serial port and/or baud rate, the TFMini uses the same message protocol as the TF02, so the code should "kind of" work if it already works for TFMini. Having said that it is not a great design, and inserting a delay()
in a Sketch loop()
is always best avoided. It is the software equivalent to spinning your wheels - a lot of power and no progress - the CPU could be doing useful stuff in that time. It is also probably prone to getting out of sync and missing or misinterpreting messages.
The Sketch loop()
architecture is most suited ot non-blocking statemachines. So given a serial port with a feasible chance of working and given it a sensible name, (e.g. TF01Port
rather than the meaningless Serial1
), then, you might implement a TFx acquisition function as a non-blocking (i.e. no delays or waiting) state-machine thus:
#include <stdint.h>
bool TFxAcquire( uint16_t& distance,
uint16_t& strength,
uint16_t& temperature )
{
static const HDR = 0x59 ;
static uint16_t d = 0u ;
static uint16_t s = 0u ;
static uint16_t t = 0u ;
static uint8_t checksum = 0 ;
enum
{
WAIT_HDR1,
WAIT_HDR2,
WAIT_DIST_L,
WAIT_DIST_H,
WAIT_STREN_L,
WAIT_STREN_H,
WAIT_TEMP_L,
WAIT_TEMP_H,
WAIT_CHKSM
} state = WAIT_HDR
bool new_value = false ;
int ch = TF01Port.read() ;
if( ch > 0 )
{
uint8_t rx = (uint8_t)ch ;
checksum += rx ;
switch( state )
{
case WAIT_HDR1 :
{
checksum = rx ;
if( rx == HDR ) state++ ;
}
break ;
case WAIT_HDR2 :
{
state = rx == HDR ? state + 1 : WAIT_HDR1 ;
}
break ;
case WAIT_DIST_L :
{
d = rx ;
state++ ;
}
break ;
case WAIT_DIST_H :
{
d |= rx << 8 ;
state++ ;
}
break ;
case WAIT_STREN_L :
{
s = rx ;
state++ ;
}
break ;
case WAIT_STREN_H :
{
s |= rx << 8 ;
state++ ;
}
break ;
case WAIT_TEMP_L :
{
t = rx ;
state++ ;
}
break ;
case WAIT_TEMP_H :
{
t |= rx << 8 ;
state++ ;
}
break ;
case WAIT_CHKSM :
{
if( rx = checksum )
{
distance = d ;
strength = s ;
temperature = t ;
new_value = true ;
}
state = WAIT_HDR1 ;
}
break ;
}
}
return new_value ;
}
If you use the default Serial
object for the LiDAR, I suggest you create an alias e.g.:
#define TF01Port Serial
but for a SoftwareSerial
instance, simply give it a useful name in the first instance:
SoftwareSerial TF01Port(2, 3);
Then in loop()
you would call that repeatedly. When the function returns true, the data has been updated.
In the following example, loop()
is also non-blocking, so the processor is available to do other work in real-time. By making the data static, the data once valid remains valid (TFxAcquire()
does not modify the data unless it has an update). When the data is updated, it is timestamped so that the data report only shows new data or none at all.
void loop()
{
static const unsigned long UPDATE_MILLIS = 300u ;
static unsigned long last_report_time = millis() ;
static unsigned long acquisition_time = millis() ;
static uint16_t distance, strength, temperature ;
unsigned long now = millis() ;
// If new data aquired...
if( TFxAquire( distance, strength, temperature ) )
{
// ... timestamp it
acquisition_time = now ;
}
// Determine age of current data
unsigned long data_age = now - acquisition_time ;
// If it is time to report, and data has been updated
// since last report...
if( now - last_report_time >= UPDATE_MILLIS &&
data_age <= UPDATE_MILLIS )
{
// ... timestamp the report
last_report_time = now ;
// ... print data here
}
// Do other real-time stuff here
}
Note that I have not compiled, tested or debugged this code - it is informed by the TF02 documentation. Treat as illustrative of a design rather then necessarily working code.