SoftwareSerial Tx Issue

I'm using a Mega with a boatload of interrupts and trying to use softwareserial to send data to a data logger.
serial is for the monitor
serial1 pins used for left wheel encoder interrupts
seria2 used for GPS
serial3 sends commands to motor controller
I2C used with an IMU
pins 2 and 3 used for right wheel encoder
There are also timer interrupts set up for odometry

I can't get any data transmitted to the data logger. Before using Serial1 for the left
wheel encoder, it was used for the data logger, and that combination worked.

Since the code is long, I've posted to DropBox

Any assistance appreciated,
John-

If you want help...

No one wants to download your code from Dropbox.

Long code is fine... just post it here directly, using code tags (</> in the editor bar).

Using the Encoder library (available in the IDE library manager) you may be able to get away with only one external interrupt for each of the encoders. That is how I do the ones on my robot. 780 Pulse Per wheel rotation encoders. Right encoder uses pins 2 and 4, the left encoder uses pins 3 and 5. Works fine. I do not see any missed steps. That would get you back a hardware serial port.

Thanks.
There appear to be many Arduino encoder libraries. The one you specify seems to be for the Teensy,
which I may eventually use. Right now I'm using the Mega and I'm under the impression that pins
4 and 5 do not have interrupts associated with them, so I guess that the performance falls under the
only one pin has interrupt category. I'll consider migrating to the Teensy, although that will require
a lot of wiring changes.

John-

Sorry, I thought it would be more convenient that having to scan pages of code on the screen.
I'll try doing as you suggest.

John-=

Here's the entire code. I hope parts of it will be useful to others./


/*                2 January 2022
 *                 Rover Mega Code
 * 1.  IMU() - outputs current Yaw angle in degrees
 * 2.  Interrupts used to count right and left wheel encoder counts
 * 3.  Motor commands - MtrFwd(Speed), MtrRev(Speed), MtrRight(Speed), MtrLeft(Speed), MtrStop()
 */

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

Adafruit_BNO055 bno = Adafruit_BNO055(55);

#define rxPin 10      //SoftwareSerial rx not used
#define txPin 11
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);

volatile long right_cnt = 0;
volatile long left_cnt  = 0;

bool busy;

int rc_active = 6;                          //Signal from BX-24 indicating R/C Control when high
int horn_pin  =  7;
int leftDelta;
int rightDelta;

float pi = 3.1415926535;
float RadTDeg = 180.0/pi;
float x;
float y;
float U;
float theta;
float totX;
float totY;
float totU;
float totTheta;

long T0;
long lastLeft;
long lastRight;

void ai0() {
  if(digitalRead(3) == LOW) {
    left_cnt++;
  }
  else {
    left_cnt--;
  }
}

void ai1() {
  if(digitalRead(2) == LOW) {
    left_cnt--;
  }
  else {
    left_cnt++;
  }
}

void ai4() {
  if(digitalRead(18) == LOW) {
     right_cnt--;
  }
  else {
    right_cnt++;
  }
}

void ai5() {
  if(digitalRead(19) == LOW) {
    right_cnt++;
  }
  else {
    right_cnt--;
  }
}

void setup() {
  delay(500);
  InitializeVariables();
  SetPinModes();
  InitializeSerialPorts();  
  InterruptSetup();

  attachInterrupt(0, ai0,RISING);
  attachInterrupt(1, ai1,RISING);   
  attachInterrupt(4, ai4, RISING);
  attachInterrupt(5, ai5, RISING); 
  
// Initialize the IMU
if(!bno.begin())  {
      //There was a problem detecting the BNO055 .. check connections
      Serial.print("Ooops, no BNO055 detected ..  Check wiring or I2C address");
      while(1);
  }
  delay(1000);
  bno.setExtCrystalUse(true);
  delay(500);
}

void loop() {  
    busy = digitalRead(rc_active);       //busy = 0 when in Auto Mode
    if(busy == 0) {
      MtrFwd(20);
      MtrLeft(1);   

      PrintMonitor();
      PrintLogo();                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
      }          

   else {
    T0 = millis();
    left_cnt = 0;
    right_cnt = 0;
    }
}  

//***********************
// INTERRUPT FUNCTIONS 
// At the bottom of this page you will find the vector called by the timer interrupt
// this vector, as you can, see calls the function Odometry(left_cnt,right_cnt)
// nothing for you to do here.

// Timer 1 overflow interrupt service routine
ISR(TIMER1_OVF_vect){
  sei(); // enable interrupts  
  Odometry(left_cnt, right_cnt); 
} 

float IMU() {
float currentAngle;

// Get a new IMU sensor event 
  sensors_event_t event;
  bno.getEvent(&event);  
  currentAngle = event.orientation.x;  
  
// IMU angles measured positive CW from zero to 360
// Odometry angles measured positive CCW from zero to 180 
//  and negative CW zero to 180

  if((currentAngle  > 0) && (currentAngle < 180)) {
    currentAngle = - currentAngle;
  }
  
  else if((currentAngle > 180) && (currentAngle <= 360)) {
    currentAngle = 360 - currentAngle; 
  }

  return currentAngle;
}


void SetPinModes () {
  pinMode(rc_active, INPUT);            // = zero in Auto mode
  pinMode(2, INPUT);         //Right wheel encoders
  pinMode(3, INPUT);
  pinMode(rxPin, INPUT);     //logo rx - not used
  pinMode(txPin, OUTPUT);    //logo tx
  pinMode(18, INPUT);        //left wheel encoders
  pinMode(19, INPUT);
}
//--------------------------------------------

void InitializeSerialPorts(){
  Serial.begin(9600);      //  serial to monitor
  Serial3.begin(9600);     //  serial to Sabertooth motor controller
  mySerial.begin(9600);    //  serial to logomatic
}
//----------------------------------------------

void InitializeVariables() {
  T0 = millis();
  leftDelta  = 0;
  rightDelta = 0;
  lastLeft   = 0;
  lastRight  = 0;
  
  x     = 0.0;
  y     = 0.0;
  theta = 0.0;
  U     = 0.0;     

  totX = 0.0;
  totY = 0.0;
  totU = 0.0;
  totTheta = 0.0;
}

// this function sets up all the port interrupts and begins the timer interrupt

void InterruptSetup(){
  PORTA = 0x00;
  DDRA = 0x00;

  PORTB = 0x00;
  DDRB = 0x00;

  PORTC = 0x00;
  DDRC = 0x00;

  PORTD = 0x00;
  DDRD = 0x00;

  PORTE = 0x00;
  DDRE = 0x00;

  PORTK = 0x00;
  DDRK = 0x00;

  pinMode(13, OUTPUT);

TCCR1A = 0x03;   
TCCR1B = 0x05;    // 0x04: 32 ms;  0x05:  131 ms
TCNT1H = 0x00;
TCNT1L = 0x00;
ICR1H = 0x00;
ICR1L = 0x00;
OCR1AH = 0x00;
OCR1AL = 0x00;
OCR1BH = 0x00;
OCR1BL = 0x00;
OCR1CH = 0x00;
OCR1CL = 0x00;

// External Interrupt(s) initialization
EICRA = 0x00;
EICRB = 0x05;
EIMSK = 0x30;
EIFR = 0x30;
// Interrupt on PCINT
PCICR = 0x05;
PCIFR = 0x05;
PCMSK0 = 0x10;
PCMSK1 = 0x00;
PCMSK2 = 0x80;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK1 |= 0x01;
TIFR1 |= 0x01;
// Global enable interrupts
sei();
}


void MtrRev(byte MtrSpeed) {
byte cmd = 8;
byte address = 128;
 
  Serial3.write(address);
  Serial3.write(cmd);
  Serial3.write(MtrSpeed); 
  byte  cksum = ((address + cmd + MtrSpeed) & 0b01111111);
  Serial3.write(cksum);
}

void MtrFwd(byte MtrSpeed) { 
byte cmd = 9;
byte address = 128;
 
  Serial3.write(address);
  Serial3.write(cmd);
  Serial3.write(MtrSpeed);
  byte cksum = ((address + cmd + MtrSpeed) & 0b01111111);
  Serial3.write(cksum);
}

void MtrRight(byte MtrSpeed) { 
byte cmd = 10;
byte address = 128;
 
  Serial3.write(address);
  Serial3.write(cmd);
  Serial3.write(MtrSpeed);
  byte cksum = ((address + cmd + MtrSpeed) & 0b01111111);
  Serial3.write(cksum);
}

void MtrLeft(byte MtrSpeed) {
byte cmd = 11;
byte address = 128;
 
  Serial3.write(address);
  Serial3.write(cmd);
  Serial3.write(MtrSpeed);
  byte cksum = ((address + cmd + MtrSpeed) & 0b01111111);
  Serial3.write(cksum);
}

void MtrStop() {
byte address = 128;
byte cksum;
  
  Serial3.write(address);
  Serial3.write(8);    //Fwd speed
  Serial3.write(0);
  cksum = ((address + 8 + 0) & 0b01111111);
  Serial3.write(cksum);

  Serial3.write(address);
  Serial3.write(10);   //Turn Right
  Serial3.write(0);
  cksum = ((address + 10 + 0) & 0b01111111);
  Serial3.write(cksum);
}  

//---------------------------------------------------

byte Limits(byte rate) {
  if(rate > 127)
    rate = 127;
  if(rate < 0)
    rate = 0;  

  return rate;
 }

void Odometry(long left, long right) {
float delX;
float delY;
float delU; 
float delUleft;
float delUright;
float delTheta;

// (cnts/cm)  = (800 cnts/rev)*(rev/(pi*wheelDiam)) = 105.8 cnts/cm
//  CmStar value depends on which encoder transitions counted
float CmStar  = 9.45e-3;  // cm/cnt
  
  leftDelta  = (left - lastLeft);
  rightDelta = (right - lastRight);
  lastLeft   = left;
  lastRight  = right; 

  delUleft  = CmStar*leftDelta;
  delUright = CmStar*rightDelta;      
  delU = (delUleft + delUright)/2;
  
//  Odometry() uses angles in radians; IMU in degrees  
  theta = IMU()/RadTDeg;  
    
  delX  = delU*cos(theta);
  delY  = delU*sin(theta);
  x += delX;
  y += delY;
  U += delU;

  totX += delX;
  totY += delY;
  totU += delU;  
}


void PrintLogo() {
  mySerial.print(millis() - T0);
  mySerial.print("\t");
  mySerial.print(left_cnt);
  mySerial.print("\t");
  mySerial.println(right_cnt); 
}

void PrintMonitor() {
  Serial.print(millis() - T0);
  Serial.write(9);
  Serial.print(left_cnt);
  Serial.write(9);
  Serial.print(right_cnt); 
  Serial.write(9);
  Serial.print("x,y,theta   ");
  Serial.print(x,0);
  Serial.write(9);
  Serial.print(y,0);
  Serial.write(9);
  Serial.println(theta*RadTDeg,0);  
}

John-

If you have any of these pins available you can use pin change interrupts on them.

Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64),
           A11 (65), A12 (66), A13 (67), A14 (68), A15 (69)

I do have pins 10 and 11 available. Those are the pins I was trying unsuccessfully to use with SoftwareSerial. Is there another way?

John-

serial1 pins used for left wheel encoder interrupts
pins 2 and 3 used for right wheel encoder

Put the Serial1 pins(18,19) back to use as a UART and move the left wheel encoder to use pin change interrupts on pins 10 and 11.

As you are using external interrupts on pins 18 and 19 with attachInterrupt() syntax and quadrature encoder reading interrupt service routines the most simple thing to do is use Nico Hood's library PinChangeInterrupt.
This library is available from the library manager. The reference material is at

The syntax is similar to the external interrupt but in your case with the library syntax and your pin change interrupt pins 10 and 11

//attachInterrupt(4, ai4, RISING);//pin 19
//attachInterrupt(5, ai5, RISING);//pin 18 
attachPCINT(digitalPinToPCINT(10), ai4, RISING);
attachPCINT(digitalPinToPCINT(11), ai5, RISING);

Thanks - I'll try this tomorrow.

John-

This bit of code is setting all of your pins to INPUT. You call it after you call "SetPinModes()".

Yikes! That function was written for me by someone else. Previously I had used it, with some other code,
to handle the encoder inputs on pins 2, 3, 10, and A15. I'll talk to the code's author. So, perhaps I should
call that function, if needed, before I call SetPinModes. Then software serial may work. I'd never have
discovered that by myself.

Thanks,
John-

Thanks to all. The different suggests all worked. I'm grateful for the assistance.

John-

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