Software Serial and DFrobot laser, can't figure out what I am doing wrong!

Hello,

Created a working board a few months back. Returned to it. The board was working but the code had been lost.
Trying to use the given code by the manufacturer of the laser finder (below), I get errors I can't understand.

Any help or suggestions greatly appreciated.

the errors I get are :

C:\Users\admin\AppData\Local\Temp\arduino-sketch-81756FE4643AEBE6A39C8CFA7216334F\sketch\sketch_1.ino.cpp.o: In function `__static_initialization_and_destruction_0':
C:\Users\admin\Documents\Arduino\sketch_1/sketch_1.ino:13: undefined reference to `SoftwareSerial::SoftwareSerial(unsigned char, unsigned char, bool)'
C:\Users\admin\AppData\Local\Temp\arduino-sketch-81756FE4643AEBE6A39C8CFA7216334F\sketch\sketch_1.ino.cpp.o: In function `_GLOBAL__sub_I_mySerial':
C:\Users\admin\Documents\Arduino\sketch_1/sketch_1.ino:62: undefined reference to `SoftwareSerial::~SoftwareSerial()'
C:\Users\admin\AppData\Local\Temp\arduino-sketch-81756FE4643AEBE6A39C8CFA7216334F\sketch\sketch_1.ino.cpp.o: In function `setup':
C:\Users\admin\Documents\Arduino\sketch_1/sketch_1.ino:19: undefined reference to `SoftwareSerial::begin(long)'
C:\Users\admin\AppData\Local\Temp\arduino-sketch-81756FE4643AEBE6A39C8CFA7216334F\sketch\sketch_1.ino.cpp.o: In function `loop':
C:\Users\admin\Documents\Arduino\sketch_1/sketch_1.ino:27: undefined reference to `SoftwareSerial::available()'
C:\Users\admin\Documents\Arduino\sketch_1/sketch_1.ino:32: undefined reference to `SoftwareSerial::read()'
collect2.exe: error: ld returned 1 exit status

exit status 1

Compilation error: exit status 1

Here is the code as given on the website ..I've only changed the library include method because it doesn't find it otherwise.



/*!
 * @File  DFRobot_Iraser_Sensor.ino
 * @brief  In this example, the infrared laser ranging sensor is used to measure the distance, and the sensor data is processed to obtain the measured distance
 * @copyright  Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
 * @licence  The MIT License (MIT)
 * @author  [liunian](nian.liu@dfrobot.com)
 * @version  V1.0
 * @date  2020-08-13
 */
//#include <SoftwareSerial.h>  it doesn't find the library with this one
#include"SoftwareSerial.h" //finds the library with this one

SoftwareSerial mySerial(2,3);//Define software serial, 3 is TX, 2 is RX
char buff[4]={0x80,0x06,0x03,0x77};
unsigned char data[11]={0};
void setup()
{
 Serial.begin(115200);
 mySerial.begin(9600);
}

void loop()
{
  mySerial.print(buff);
  while(1)
  {
    if(mySerial.available()>0)//Determine whether there is data to read on the serial 
    {
      delay(50);
      for(int i=0;i<11;i++)
      {
        data[i]=mySerial.read();
      }
      unsigned char Check=0;
      for(int i=0;i<10;i++)
      {
        Check=Check+data[i];
      }
      Check=~Check+1;
      if(data[10]==Check)
      {
        if(data[3]=='E'&&data[4]=='R'&&data[5]=='R')
        {
          Serial.println("Out of range");
        }
        else
        {
          float distance=0;
          distance=(data[3]-0x30)*100+(data[4]-0x30)*10+(data[5]-0x30)*1+(data[7]-0x30)*0.1+(data[8]-0x30)*0.01+(data[9]-0x30)*0.001;
          Serial.print("Distance = ");
          Serial.print(distance,3);
          Serial.println(" M");
        }
      }
      else
      {
        Serial.println("Invalid Data!");
      }
    }
    delay(20);
  }
}

and here is the library as i found it online on github. I don't even know if it is the right one, but it seems like it is and I can' t find it anywhere else.

#ifndef SoftwareSerial_h
#define SoftwareSerial_h

#include <inttypes.h>
#include <Stream.h>
#include <HardwareSerial.h>

/******************************************************************************
* Definitions
******************************************************************************/

#define _SS_MAX_RX_BUFF 64 // RX buffer size
#ifndef GCC_VERSION
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#endif

#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1052__) || defined(__IMXRT1062__)

class SoftwareSerial : public Stream
{
public:
	SoftwareSerial(uint8_t rxPin, uint8_t txPin, bool inverse_logic = false);
	~SoftwareSerial() { end(); }
	void begin(unsigned long speed);
	void end();
	bool listen() { return true; }
	bool isListening() { return true; }
	bool overflow() { bool ret = buffer_overflow; buffer_overflow = false; return ret; }
	virtual int available();
	virtual int read();
	int peek();
	virtual void flush();
	virtual size_t write(uint8_t byte);
	operator bool() { return true; }
	using Print::write;
private:
	HardwareSerial *port;
	uint32_t cycles_per_bit;
	#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
	volatile uint32_t *txreg;
	volatile uint32_t *rxreg;
	#else
	volatile uint8_t *txreg;
	volatile uint8_t *rxreg;
	#endif
	bool buffer_overflow;
	uint8_t txpin;
	uint8_t rxpin;
};

#else
class SoftwareSerial : public Stream
{
private:
  // per object data
  uint8_t _receivePin;
  uint8_t _receiveBitMask;
  volatile uint8_t *_receivePortRegister;
  uint8_t _transmitBitMask;
  volatile uint8_t *_transmitPortRegister;

  uint16_t _rx_delay_centering;
  uint16_t _rx_delay_intrabit;
  uint16_t _rx_delay_stopbit;
  uint16_t _tx_delay;

  uint16_t _buffer_overflow:1;
  uint16_t _inverse_logic:1;

  // static data
  static char _receive_buffer[_SS_MAX_RX_BUFF]; 
  static volatile uint8_t _receive_buffer_tail;
  static volatile uint8_t _receive_buffer_head;
  static SoftwareSerial *active_object;

  // private methods
  void recv();
  uint8_t rx_pin_read();
  void tx_pin_write(uint8_t pin_state);
  void setTX(uint8_t transmitPin);
  void setRX(uint8_t receivePin);

  // private static method for timing
  static inline void tunedDelay(uint16_t delay);


public:
  // public methods
  SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false);
  ~SoftwareSerial();
  void begin(long speed);
  bool listen();
  void end();
  bool isListening() { return this == active_object; }
  bool overflow() { bool ret = _buffer_overflow; _buffer_overflow = false; return ret; }
  int peek();

  virtual size_t write(uint8_t byte);
  virtual int read();
  virtual int available();
  virtual void flush();
  operator bool() { return true; }
  
  using Print::write;

  // public only for easy access by interrupt handlers
  static inline void handle_interrupt();
};

#endif

#endif

What board do you have selected?

Here I can see a difference between unsigned char vs. uint8_t arguments in your library. If these are compatible then check for

which should be defined if the header has been included.

Hello both, thanks for the answers,

I am using the Arduino MKR WiFi 1010

I have since found, that apparently it does not use (nor need) SoftwareSerial.h as it addresses the internal serial as Serial1.

The issue now is, that I get no response from the laser sensor, nor does the sensor indeed turn on.

here is the code I use now:

char buff[4]={0x80,0x06,0x03,0x77};
unsigned char data[11]={0};
void setup()
{
 Serial.begin(9600);
 while(!Serial)
 Serial1.begin(9600);
}

void loop()
{
  Serial1.print(buff);
  while(1)
  {
    if(Serial1.available()>0)//Determine whether there is data to read on the serial 
    {
      delay(50);
      for(int i=0;i<11;i++)
      {
        data[i]=Serial1.read();
      }
      unsigned char Check=0;
      for(int i=0;i<10;i++)
      {
        Check=Check+data[i];
      }
      Check=~Check+1;
      if(data[10]==Check)
      {
        if(data[3]=='E'&&data[4]=='R'&&data[5]=='R')
        {
          Serial.println("Out of range");
        }
        else
        {
          float distance=0;
          distance=(data[3]-0x30)*100+(data[4]-0x30)*10+(data[5]-0x30)*1+(data[7]-0x30)*0.1+(data[8]-0x30)*0.01+(data[9]-0x30)*0.001;
          Serial.print("Distance = ");
          Serial.print(distance,3);
          Serial.println(" M");
        }
      }
      else
      {
        Serial.println("Invalid Data!");
      }
    }
    delay(20);
  }
}

check the Serial1 connections against Arduino MKR 1010 pinout
could upload a schematic showing the wiring ?

I used this program to test Serial1 on a MKRFOX

// Arduino MKRFOX hardware serial1 port Serial1 on Tx pin 14 Rx pin 13

// on the MKRFOX Serial is used for USB communications and Serial1 is a hardware serial port on Tx pin 14 Rx pin 13

// NOTE: MKRFOX uses 3.3V logic 
// - if commected to UNO 5V logic use a voltage divider 2.2K to ground 1K to UNO Tx

// MKRFOX pin 14 is TX
// MKRFOX pin 13 is Rx
// for loopback test connect pin 13 to pin 14

void setup() {
  Serial.begin(115200);   // initialise serial monitor port
  while (!Serial) {
      ; // wait for serial port to connect. Needed for native USB port only
    }  
  Serial1.begin(57600);  // initialise Serial1
  Serial.println();
  Serial.write("Arduino MKRFOX Serial1 test -  for loopback test connect pin 13 to pin 14\n");
}

void loop() {
  if (Serial1.available())        // read from Serial1 output to Serial
    Serial.write(Serial1.read());
  if (Serial.available()) {       // read from Serial outut to Serial1
    int inByte = Serial.read();
    Serial.write(inByte);     // local echo if required
    Serial1.write(inByte);
  }
}

Hello, thanks for the help, I appreciate it.

Your code didn't work either. I took the plunge and cracked open the sensor case/box.

The laser sensor seems to be connected to pa 22/d0 and pa23/d1... for whatever reason.

I have no clue how to point the serial to these pins. I only assume there is a reason why these pins were selected and set, and therefore I'd like to use the same pins, rather than trying the pins 14,13 as they may introduce more problems.
Any suggestions greatly welcome.

see schematic below

you can do a Serial1 loopback test of the code of post 5 by connecting pins 13 and 14 together
characaters enter on the serial monitor are echoback to the display

I have no idea how to change the Serial1 pins to PA22 and PA23
where did you get the diagram of post 6 from showing the connection to pins PA22 and PA23

don't know if it helps but have a look at Laser_Ranging_Sensor_UART_4m_SKU_SEN0491

Hello,
Once again, thanks for the help.

I've braved connecting the sensor to pins 13 and 14 and it works! Both pieces of code, yours and mine work now.

The issue is, we have another 30 of these sensors deployed on site and we cannot open them up to reconnect the sensors to pins 13 and 14.
Plus the mystery of why the sensor was connected to 22 and 23 still remains. I suspect there was some issue down the line.

I made the diagram on post 6 by opening up the case and looking at the wiring.

if anyone has any idea on how to set the serial to point at pins 22 and 23, please let me know.

been having a read thru adding-more-sercom-ports-for-samd-boards
getting lots of errors!

Hello Horace, great find !

Maybe it will be the answer. I know the previous code that was running on the board worked, so somehow pins 22 and 23 were allocated to Serial. Just need to find how.

thanks a lot!

have a look at this which is using pins 0 (PA22) Tx and 1 (PA23) Rx
Edit: note original had pins 0 and 1 incorrect

// Arduino MKRFOX hardware creating serial port on Rx pin 1 Tx pin 0

// on the MKRFOX Serial is used for USB communications and Serial1 is a hardware seria port on Tx pin 14 Rx pin 13

// NOTE: MKRFOX uses 3.3V logic

#include "wiring_private.h"

Uart mySerial(&sercom3, 0, 1, SERCOM_RX_PAD_1, UART_TX_PAD_0);  // Create the new UART instance assigning it to pin 0 and 1

void SERCOM3_Handler() {
  mySerial.IrqHandler();
}

void setup() {
  Serial.begin(115200);  // initialise serial monitor port
  while (!Serial) {
    ;  // wait for serial port to connect. Needed for native USB port only
  }
  mySerial.begin(115200);         // initialise mySerial
  pinPeripheral(0, PIO_SERCOM);  //Assign TX function to pin 0
  pinPeripheral(1, PIO_SERCOM);  //Assign RX function to pin 1
  Serial.println();
  Serial.write("Arduino MKRFOX mySerial test -  for loopback test connect pin 0 Tx to pin 1 Rx\n");
}

void loop() {
  if (mySerial.available())  // read from mySerial output to Serial
    Serial.write(mySerial.read());
  if (Serial.available()) {  // read from Serial outut to mySerial
    int inByte = Serial.read();
    // Serial.write(inByte);     // local echo if required
    mySerial.write(inByte);
  }
}

you also need wiring_private.h (put in same directory as above .ino file)
```cpp
/*
  Copyright (c) 2015 Arduino LLC.  All right reserved.
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU Lesser General Public License for more details.
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#pragma once

#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>

#ifdef __cplusplus
extern "C" {
#endif

// Includes Atmel CMSIS
#include <samd.h>

int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral );

#ifdef __cplusplus
} // extern "C"

#endif

and wiring_private.cpp (put in same directory as above .h and .ino file)

/*
  Copyright (c) 2015 Arduino LLC.  All right reserved.
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU Lesser General Public License for more details.
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "Arduino.h"
#include "wiring_private.h"

int pinPeripheral( uint32_t ulPin, EPioType ulPeripheral )
{
  // Handle the case the pin isn't usable as PIO
  if ( g_APinDescription[ulPin].ulPinType == PIO_NOT_A_PIN )
  {
    return -1 ;
  }

  switch ( ulPeripheral )
  {
    case PIO_DIGITAL:
    case PIO_INPUT:
    case PIO_INPUT_PULLUP:
    case PIO_OUTPUT:
      // Disable peripheral muxing, done in pinMode
//			PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].bit.PMUXEN = 0 ;

      // Configure pin mode, if requested
      if ( ulPeripheral == PIO_INPUT )
      {
        pinMode( ulPin, INPUT ) ;
      }
      else
      {
        if ( ulPeripheral == PIO_INPUT_PULLUP )
        {
          pinMode( ulPin, INPUT_PULLUP ) ;
        }
        else
        {
          if ( ulPeripheral == PIO_OUTPUT )
          {
            pinMode( ulPin, OUTPUT ) ;
          }
          else
          {
            // PIO_DIGITAL, do we have to do something as all cases are covered?
          }
        }
      }
    break ;

    case PIO_ANALOG:
    case PIO_SERCOM:
    case PIO_SERCOM_ALT:
    case PIO_TIMER:
    case PIO_TIMER_ALT:
    case PIO_EXTINT:
    case PIO_COM:
    case PIO_AC_CLK:
#if 0
      // Is the pio pin in the lower 16 ones?
      // The WRCONFIG register allows update of only 16 pin max out of 32
      if ( g_APinDescription[ulPin].ulPin < 16 )
      {
        PORT->Group[g_APinDescription[ulPin].ulPort].WRCONFIG.reg = PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_PMUXEN | PORT_WRCONFIG_PMUX( ulPeripheral ) |
                                                                    PORT_WRCONFIG_WRPINCFG |
                                                                    PORT_WRCONFIG_PINMASK( g_APinDescription[ulPin].ulPin ) ;
      }
      else
      {
        PORT->Group[g_APinDescription[ulPin].ulPort].WRCONFIG.reg = PORT_WRCONFIG_HWSEL |
                                                                    PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_PMUXEN | PORT_WRCONFIG_PMUX( ulPeripheral ) |
                                                                    PORT_WRCONFIG_WRPINCFG |
                                                                    PORT_WRCONFIG_PINMASK( g_APinDescription[ulPin].ulPin - 16 ) ;
      }
#else
      if ( g_APinDescription[ulPin].ulPin & 1 ) // is pin odd?
      {
        uint32_t temp ;

        // Get whole current setup for both odd and even pins and remove odd one
        temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXE( 0xF ) ;
        // Set new muxing
        PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXO( ulPeripheral ) ;
        // Enable port mux
        PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ;
      }
      else // even pin
      {
        uint32_t temp ;

        temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXO( 0xF ) ;
        PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXE( ulPeripheral ) ;
        PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ; // Enable port mux
      }
#endif
    break ;

    case PIO_NOT_A_PIN:
      return -1l ;
    break ;
  }

  return 0l ;
}

if I connect pins 0 and 1 the loopback test works - characters entered into serial monior appear on the display

Edit: MKRFOX connected to an ESP32
MKRFOX serial monitor

Arduino MKRFOX mySerial test -  for loopback test connect pin 0 Tx to pin 1 Rx
test 1 - text from ESP32 
test 2  from ESP32 - 1234567890

ESP32 serial mionitor

serial1  test Rx pin 14 Tx pin 15
test 1 - text from MKRFOX 
TEST2 from MKRFOX 1234567890 abcdefgh

photo
image

1 Like

Use the expected byte count instead of 0. Remember that bytes are arriving much slower than your code expects. Serial.read() returns -1 if no more bytes have been received yet

Thank you!
This was very helpful.
I am in your debt sir !!!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.