SoftwareSerial

Hi all,

I'm trying to use the BNO055 magnetometer/gyroscope/accelerometer with an ATTINY85.

I cannot for the life of me get the simplest BNO055 example sketch to compile with SoftwareSerial, every change I make to try and get it to work seems to return a littany of errors, the one that seems to recur the most is "mySerial not declared in this scope".

My question is, will the BNO055 even work with the ATTINY85? Or am I barking up a wrong tree?

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <SoftwareSerial.h>


#define rxPin 3
#define txPin 4

SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);
/* This driver reads raw data from the BNO055

   Connections
   ===========
   Connect SCL to analog 5
   Connect SDA to analog 4
   Connect VDD to 3.3V DC
   Connect GROUND to common ground

   History
   =======
   2015/MAR/03  - First release (KTOWN)
*/

/* Set the delay between fresh samples */
#define BNO055_SAMPLERATE_DELAY_MS (100)

Adafruit_BNO055 bno = Adafruit_BNO055();

/**************************************************************************/
/*
    Arduino setup function (automatically called at startup)
*/
/**************************************************************************/
void setup(void)
{

  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  
  mySerial.begin(9600);
  mySerial.println("Orientation Sensor Raw Data Test"); mySerial.println("");

  /* Initialise the sensor */
  if(!bno.begin())
  {
    /* There was a problem detecting the BNO055 ... check your connections */
    mySerial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
    while(1);
  }

  delay(1000);

  /* Display the current temperature */
  int8_t temp = bno.getTemp();
  mySerial.print("Current Temperature: ");
  mySerial.print(temp);
  mySerial.println(" C");
  mySerial.println("");

  bno.setExtCrystalUse(true);

  mySerial.println("Calibration status values: 0=uncalibrated, 3=fully calibrated");
}

/**************************************************************************/
/*
    Arduino loop function, called once 'setup' is complete (your own code
    should go here)
*/
/**************************************************************************/
void loop(void)
{
  // Possible vector values can be:
  // - VECTOR_ACCELEROMETER - m/s^2
  // - VECTOR_MAGNETOMETER  - uT
  // - VECTOR_GYROSCOPE     - rad/s
  // - VECTOR_EULER         - degrees
  // - VECTOR_LINEARACCEL   - m/s^2
  // - VECTOR_GRAVITY       - m/s^2
  imu::Vector<3> euler = bno.getVector(Adafruit_BNO055::VECTOR_EULER);

  /* Display the floating point data */
  mySerial.print("X: ");
  mySerial.print(euler.x());
  mySerial.print(" Y: ");
  mySerial.print(euler.y());
  mySerial.print(" Z: ");
  mySerial.print(euler.z());
  mySerial.print("\t\t");

  /*
  // Quaternion data
  imu::Quaternion quat = bno.getQuat();
  Serial.print("qW: ");
  Serial.print(quat.w(), 4);
  Serial.print(" qX: ");
  Serial.print(quat.y(), 4);
  Serial.print(" qY: ");
  Serial.print(quat.x(), 4);
  Serial.print(" qZ: ");
  Serial.print(quat.z(), 4);
  Serial.print("\t\t");
  */

  /* Display calibration status for each sensor. */
  uint8_t system, gyro, accel, mag = 0;
  bno.getCalibration(&system, &gyro, &accel, &mag);
  mySerial.print("CALIBRATION: Sys=");
  mySerial.print(system, DEC);
  mySerial.print(" Gyro=");
  mySerial.print(gyro, DEC);
  mySerial.print(" Accel=");
  mySerial.print(accel, DEC);
  mySerial.print(" Mag=");
  mySerial.println(mag, DEC);

  delay(BNO055_SAMPLERATE_DELAY_MS);
}

SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);Should that = be there .......

The "Wire" library doesn't work with a 'tiny85, (no hardware I2C, only a Universal Serial Interface). You'll need an alternative library, perhaps "TinyWireM".

Regarding "SoftwareSerial", this compiles fine for me with a 'tiny85 as the target:-

#include <SoftwareSerial.h>

#define rxPin 3
#define txPin 4

SoftwareSerial mySerial(rxPin, txPin);

void setup()
{
    mySerial.begin(9600);
}

void loop(){}

UKHeliBob:
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);Should that = be there .......

That will work fine Bob, as he/she did it, but the method I showed is more usual.

Regarding "SoftwareSerial", this compiles fine for me with a 'tiny85 as the target:-

But, it won't work with those pins. Only pins 0 and 1 can be used on the 85 (as far as I know, anyway).

PaulS:
But, it won't work with those pins. Only pins 0 and 1 can be used on the 85 (as far as I know, anyway).

Not so.
Here are two examples using pins 3 and 4:-
ATtiny85 & ATtiny84 Analog Pins, Serial Communication, etc.

Serial Communication on a ATtiny85 with the SoftwareSerial Library.

And in this article, half-way down the page:- Is SoftwareSerial left out for the ATTiny85/84?

Since two of those linked pages were so crappy, I just did a quick test myself to be sure.
This works fine:-

UNO code:-

// UNO code:-

#include <SoftwareSerial.h>

const byte rxPin = 2;
const byte txPin = 3;

SoftwareSerial mySerial(rxPin, txPin);

void setup()
{
    Serial.begin(115200);
    mySerial.begin(9600);
    mySerial.print('A');
}

void loop()
{
    if (mySerial.available())
        Serial.write(mySerial.read());
}

ATTiny85 code:-

// ATTiny85 code:-

#include <SoftwareSerial.h>

const byte rxPin = 3;         // Physical pin 2
const byte txPin = 4;         // Physical pin 3

SoftwareSerial mySerial(rxPin, txPin);

void setup()
{
    mySerial.begin(9600);
}

void loop()
{
    if(mySerial.available())
    {
        char c = mySerial.read();
        if(c=='A')
            mySerial.println("'A' received");
    }
    mySerial.println(F("Hi there from 'tiny85"));
    delay(1000);
}

Result:-

'A' received
Hi there from 'tiny85
Hi there from 'tiny85
Hi there from 'tiny85
Hi there from 'tiny85
Hi there from 'tiny85
Hi there from 'tiny85
Hi there from 'tiny85
Hi there from 'tiny85
Hi there from 'tiny85

Y'all might be interested in using NeoSWSerial instead of SoftwareSerial, if the baud rate is 9600, 19200 or 38400. It doesn't block interrupts for the entire time a character is being received. And unlike SoftwareSerial, NeoSWSerial can transmit and receive at the same time.

There is software to use the USI as a serial port here. That would be much better than any software serial library, but it can only use pins 0 and 1.

Cheers,
/dev

/dev:
There is software to use the USI as a serial port here. That would be much better than any software serial library, but it can only use pins 0 and 1.

Cheers,
/dev

That's clearly why PaulS thought "SoftwareSerial" could only use pins 0 and 1.
Looks a bit trickier to use though.

Generally, I use I2C for communication with tiny84 and tiny85 chips, since distances are usually short in my creations.

Still handy to be aware of what's available, though. I just downloaded the "NeoSWSerial" lib, and will give it a spin when I get a chance.

Thanks for the info. :slight_smile:

Hi guys, just wanted to express my gratitude for helping me figure this all out and show my solutions to any future searchers.

Oldsteve, your suggestions got the SoftwareSerial working for me, seems I just had to tweak a few things to be closer to your suggestions.

TinyWireM was not working for me at first, but upon finding that I had an old version of Adafruit_BNO055.h, I downloaded the more recent from github and was up and running right away!

Here is a simplified version of the code I came up with that will return euler angles over Softwareserial.

#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <SoftwareSerial.h>


const byte rxPin = 3;         // Physical pin 2
const byte txPin = 4;         // Physical pin 3

SoftwareSerial mySerial (rxPin, txPin);

/* This driver reads raw data from the BNO055

   Connections
   ===========
   Connect SCL to analog 5
   Connect SDA to analog 4
   Connect VDD to 3.3V DC
   Connect GROUND to common ground

   History
   =======
   2015/MAR/03  - First release (KTOWN)
*/

Adafruit_BNO055 bno = Adafruit_BNO055();

void setup(void)
{

  mySerial.begin(9600);

  /* Initialise the sensor */
    if(!bno.begin())

    delay(1000);
    bno.setExtCrystalUse(true);
  }

  void loop(void)
  {
    imu::Vector<3> euler = bno.getVector(Adafruit_BNO055::VECTOR_EULER);

    /* Display the floating point data */
    mySerial.print(" X: ");
    mySerial.print(euler.x());
    mySerial.print(" Y: ");
    mySerial.print(euler.y());
    mySerial.print(" Z: ");
    mySerial.print(euler.z());
    mySerial.println("\t\t");

    delay(100);
  }

I'm glad it's now working, but just one point that might come back to bite you.
Is this really what you intended here:-

if (!bno.begin())
    delay(1000);
bno.setExtCrystalUse(true);

If 'bno.begin()' fails, wait one second, then continue as if it had succeeded?

You know what, I wasn't really sure what that was, but when I tried to remove it, the sketch quit working. There was some code after that that serial prints "BNO055 not connected" or something to that effect. I removed it since there's such limited memory on the ATTINY85.

I assumed it was necessary, what precisely is that there to do?

zakelectric:
You know what, I wasn't really sure what that was, but when I tried to remove it, the sketch quit working. There was some code after that that serial prints "BNO055 not connected" or something to that effect. I removed it since there's such limited memory on the ATTINY85.

I assumed it was necessary, what precisely is that there to do?

'bno.begin()' is absolutely necessary, to initialise the sensor. What I was querying was the fact that the code still continues on to use the sensor even if 'begin()' fails.

I think you changed the intent of the code when you removed the print line etc.

I'd be more likely to write something like:-

if (!bno.begin())
{
    mySerial.print(F("Failed to initialise the BNO055 sensor - cannot continue!"));
    while(true);    // Loop forever, (stop code execution).
}

so that you're informed of the problem if the sensor can't be initialised, then code execution stops.