Go Down

Topic: SoftwareSerial only rx Pin cause no more pins left (Read 2067 times) previous topic - next topic

Robohac

Dec 20, 2012, 11:56 pm Last Edit: Dec 20, 2012, 11:57 pm by Robohac Reason: 1
Hi there,

im in the middle of a small project. For that project i have a stepper unit consisting out of two steppers, one uln2803, and two Attiny45. (ofcourse an arduino :D)

My problem is: I wanna drive one stepper with one attiny. This uses 4 pins. So scratch 4 of the five pins. Theres only one pin left for commuication from the arduino to the attiny. I wanned to use the softwareserial library for that on the attiny. But theres a problem, i have to declare a RX and a TX pin, but i only have room for my RX pin.

I found a version of the SoftwareSerial library, which only uses a TX pin, but not one that only recieves. (librarie can be fund in THIS post.)

Sadly i cant moddify the library myself, because i dont fully understand how those work.

Has anyone some tipps / a solution for me?

- Robohac

robtillaart


IIRC, you can use the standard SoftSerial library and declare the pin you do not want to use as pin -1.

give it a try.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Robohac

Ok so i wrote the first bit of code. One problem though: It dosnt work :D but im tired and just wanna show what ive done so far (ill correct the mistakes tomorrow) I think the mistake is in the function stringtonumber().

Code: [Select]
// Modes:
// R (Rotate)   format: R<Ticks>;<Speed>;
// S (Spinn)    format: S<Speed>;<Time>;
// C (Constant) format: C<r/l>;<Speed>;

#include <SoftwareSerial.h>

//declare variables for the motor pins
int motorPin1 = 3; // Blue   - 28BYJ48 pin 1
int motorPin2 = 4; // Pink   - 28BYJ48 pin 2
int motorPin3 = 2; // Yellow - 28BYJ48 pin 3
int motorPin4 = 1; // Orange - 28BYJ48 pin 4
                        // Red    - 28BYJ48 pin 5 (VCC)
                       
int rxPin = 0;         //Serial recieve pin 
                       
int motorSpeed = 0;     //variable to set stepper speed

SoftwareSerial mySerial(rxPin, -1); // RX, TX

String cue = "";

void setup() {
  //declare the motor pins as outputs
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(motorPin4, OUTPUT);

}

void loop() {
  while (mySerial.available()>0) {
    cue = cue + getData();
  }
  switch (cue.charAt(0)) {
    case 'R':
      rotate();
      break;
    case 'S':
      spinn();
      break;
    case 'C':
      constant();
      break;     
  }
 
}

void counterclockwise (){
  // 1
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, LOW);
  delay(motorSpeed);
  // 2
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, LOW);
  delay (motorSpeed);
  // 3
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, LOW);
  delay(motorSpeed);
  // 4
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, LOW);
  delay(motorSpeed);
  // 5
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, LOW);
  delay(motorSpeed);
  // 6
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, HIGH);
  delay (motorSpeed);
  // 7
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, HIGH);
  delay(motorSpeed);
  // 8
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, HIGH);
  delay(motorSpeed);
}

void clockwise(){
  // 1
  digitalWrite(motorPin4, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin1, LOW);
  delay(motorSpeed);
  // 2
  digitalWrite(motorPin4, HIGH);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin1, LOW);
  delay (motorSpeed);
  // 3
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin1, LOW);
  delay(motorSpeed);
  // 4
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin1, LOW);
  delay(motorSpeed);
  // 5
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin1, LOW);
  delay(motorSpeed);
  // 6
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin1, HIGH);
  delay (motorSpeed);
  // 7
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin1, HIGH);
  delay(motorSpeed);
  // 8
  digitalWrite(motorPin4, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin1, HIGH);
  delay(motorSpeed);
}

String getData() {
  String input = "";
  while(mySerial.available()>0) {
    input = input + mySerial.read();
  }
  return input;
}

void deleteOld() {
  if(cue.length() != 0) {
    int n = 1;
    for (n = 1; n < cue.length(); n++) {
      if (cue.charAt(n) == ';') {
        break;
      }
    }
    cue = cue.substring(n + 1);
  }
}

void rotate() {
}

void spinn() {
}

void constant() {
  char direct = cue.charAt(1);
  int paramlength = 0;
  for (paramlength = 3; paramlength < cue.length(); paramlength++) {
    if (cue.charAt(paramlength) == ';') {
      break;
    }
  }
  paramlength = paramlength - 3;
  motorSpeed = stringtonumber(cue.substring(3, paramlength + 3));
  if (direct == 'r') {
    while (mySerial.available()==0) {
      clockwise();
    }
  } else {
    while (mySerial.available()==0) {
      counterclockwise();
    }
  }
  deleteOld();
}

int stringtonumber(String snumber) {
  int number = 0;
  for (int z = 0; z < snumber.length(); z++) {
    number = (number*10) + (snumber.charAt(z) - 48);
  }
  return number;
}

PeterH

You don't say what's wrong, but the way you're receiving the command string looks unsafe to me.

Firstly, you using the String class, which isn't giving you any benefit here and introduces the possibility of memory leaks and resulting stability problems.

Secondly, you aren't waiting until the whole command string is available before you try to parse it.

It would make far more sense to accumulate the incoming chars in a char array until you recognise the terminating ';' and then process the whole command.

As far as SoftwareSerial goes, you need to arrange for the SoftwareSerial to have a zero value for _transmitBitMask. This value is looked up in a board-specific way from the pin number you supply and I don't know whether there are any pin numbers that translate to zero. You could always call digitalPinToBitMask() with a few pin numbers and see whether any came back with zero. If you find any that do, you could use that as your TX pin. Otherwise, I suppose you could modify SoftwareSerial::setTX() and SoftwareSerial::setRX() to test the supplied pin number and set the port and bitmask properties to zero if an out-of-range value was supplied.
I only provide help via the forum - please do not contact me for private consultancy.

HazardsMind

#4
Dec 21, 2012, 06:19 pm Last Edit: Dec 21, 2012, 06:27 pm by HazardsMind Reason: 1
Do you need to use pins 0 and 1 or can you possibly move somethings around. The easiest way of solving your problem is to see what goes in and what comes out. However, you would need the serial monitor for that, meaning the Tx pin.

Code: [Select]
int stringtonumber(String snumber) {
  int number = 0;
  for (int z = 0; z < snumber.length(); z++) {
    number = (number*10) + (snumber.charAt(z) - 48);
    Serial.print(snumber);
    Serial.print(", ");
    Serial.println(number);
  }
  return number;
}
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

HazardsMind

#5
Dec 21, 2012, 06:24 pm Last Edit: Dec 21, 2012, 06:32 pm by HazardsMind Reason: 1
Mine is quite simular to yours, in function, but much more simpler. Look at how I get my data, and split it.
Code: [Select]
/*
control test
*/
#include<string.h>
int DRV1,DRV2,STRR,STRL;
int x = 0;
int y = 0;
int s = 0;
void move(int x = 0,int y = 0,int s = 0);
//double z;
String val = "";
String  X= "";
String  Y= "";
String  state = "";
//int state = 0;
int currentCommand = 0;

int ledpin = 13;
byte Mopen = 4;
byte Mclosed = 2;
byte M1L = 3;// PWM
byte M2L = 5;// PWM
byte M1R = 9;// PWM
byte M2R = 6;// PWM

void setup()
{
  pinMode(ledpin, OUTPUT);  // pin 13 (on-board LED) as OUTPUT
  pinMode(Mopen, OUTPUT);                               
  pinMode(Mclosed, OUTPUT);
  pinMode(M1L, OUTPUT);                               
  pinMode(M1R, OUTPUT);
  pinMode(M2L, OUTPUT);                               
  pinMode(M2R, OUTPUT);
  Serial.begin(9600);       // start serial communication at 115200bps

}

void loop() {
  if( Serial.available())       // if data is available to read
  {
    digitalWrite(ledpin, HIGH);
    char c= Serial.read();
    if (c == ','){    //look at the incoming chars, if it is a ',' then switch the case
      currentCommand++;
    }
    else {   //if it is not ',' then store chars in string
      val += c;
      //Serial.println(val);
      switch (currentCommand) {

      case 0:
        X += val;
        val = "";
        break;

      case 1:
        Y += val;
        val = "";
        break;

      case 2:
      //Serial.println("X: "+X);
      //Serial.println("Y: "+Y);   
        state = val;   // this will only receive 1 value
        currentCommand = 0;
        val = "";
        //Serial.println("state: "+state);
        //Serial.println();
        x=X.toInt();  //string to int
        y=Y.toInt();  //string to int
        s=state.toInt();  //string to int
        X=""; Y=""; state="";
        move(x, y, s);
        break;
      }
    }
  }
}
   
  void move(int x, int y, int s)
  { 
      x=constrain(x, -90, 90);
      y=constrain(y, -90, 90);

  //Movement varibles
 
  int DRV2 = map(x, -90, 0, 255, 0);
  int DRV1 = map(x, 0, 90, 0, 255);
  int STRR = map(y, -90, 0, 255, 0);
  int STRL = map(y, 0, 90, 0, 255); 

  if(x > 0)//forwards               
  {
    //Serial.println("Driving");
    analogWrite(M1L, abs(DRV1 - STRL)); analogWrite(M1R, abs(DRV1 - STRR));   
    analogWrite(M2L, 0); analogWrite(M2R, 0);   
  }
  else if(x < 0)//backwards               
  {
    //Serial.println("Driving");
    analogWrite(M1L, 0); analogWrite(M1R, 0);   
    analogWrite(M2L, abs(DRV2 - STRR)); analogWrite(M2R, abs(DRV2 - STRL));   
  }
  else if(x == 0 && y >0)//right             
  {
    //Serial.println("Driving");
    analogWrite(M1L, STRL); analogWrite(M1R, 0);   
    analogWrite(M2L, 0); analogWrite(M2R, STRL);   
  }
  else if(x == 0 && y < 0)//left             
  {
    //Serial.println("Driving");
    analogWrite(M1L, 0); analogWrite(M1R, STRR);   
    analogWrite(M2L, STRR); analogWrite(M2R, 0);   
  }

  else //full stop
  {
    digitalWrite(M1L, LOW); digitalWrite(M1R, LOW);       
    digitalWrite(M2L, LOW); digitalWrite(M2R, LOW);   
  }

   if(s == 1)
    {
      //Serial.println("Claw Opening");
      digitalWrite(Mopen, HIGH); digitalWrite(Mclosed, LOW);
    }
    if(s == 2)
    {
      //Serial.println("Claw Closing");
      digitalWrite(Mopen, LOW); digitalWrite(Mclosed, HIGH);
    }
    if(s == 0)
    {
      digitalWrite(Mopen, LOW);  digitalWrite(Mclosed, LOW);
    }
   else{
    digitalWrite(ledpin, LOW);
    x=0; y=0; s=0;
  }
}


Your more than welcome to modify this and use it.
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

PaulS

Quote
My problem is: I wanna drive one stepper with one attiny. This uses 4 pins. So scratch 4 of the five pins.

Using a stepper driver board to do the hard work only requires two pins - one to set the direction and one to cause a step. Save two pins.

Robohac

Wow, thank you for your response :D

@HazardsMind Ill read trough your code shortly, and see how i can optimize mine

@PeterH I use strings because it was the first thing which came in my mind. Thank you for your hint, that i wasnt wayting for the whole string. I fixet that.

Current state of the programm (The functions wor now, i testet them on an arduino but not all are finished, because i want to test them one by one to prevent mistakes)

Code: [Select]
// Modes:
// R (Rotate)   format: R<Ticks>,<Speed>;
// S (Spinn)    format: S<Speed>,<Time>;
// C (Constant) format: C<r/l><Speed>;

#include <SoftwareSerial.h>

//declare variables for the motor pins
int motorPin1 = 3; // Blue   - 28BYJ48 pin 1
int motorPin2 = 4; // Pink   - 28BYJ48 pin 2
int motorPin3 = 2; // Yellow - 28BYJ48 pin 3
int motorPin4 = 1; // Orange - 28BYJ48 pin 4
// Red    - 28BYJ48 pin 5 (VCC)

int rxPin = 0;         //Serial recieve pin

int motorSpeed = 0;     //variable to set stepper speed

SoftwareSerial mySerial(rxPin, -1); // RX, TX

String cue = "";

void setup() {
  //declare the motor pins as outputs
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(motorPin4, OUTPUT);

}

void loop() {
  getData();
  switch (cue.charAt(0)) {
    case 'R':
      rotate();
      break;
    case 'S':
      spinn();
      break;
    case 'C':
      constant();
      break;     
  }
}

void rotate() { // R (Rotate)   format: R<Ticks>,<Speed>;
}

void spinn() { // S (Spinn)    format: S<Speed>,<Time>;
}

void constant() { // C (Constant) format: C<r/l><Speed>;
  String smotorSpeed;
  for (int i = 0; i < cue.length(); i++) {
    if (cue.charAt(i) == ';') {
      break;
    } else {
      smotorSpeed.concat(cue.charAt(i));
    }
  }
  motorSpeed = stringtonumber(smotorSpeed);
  if(cue.charAt(1) == 'r') {
    while(true) {
      clockwise();
      if(mySerial.available()) {
        break;
      }
    }
  } else {
    while(true) {
      counterclockwise();
      if(mySerial.available()) {
        break;
      }
    }
  }
  deleteOld();
}

void getData() {
  char character;
  while(true) {
    if (mySerial.available() > 0) {
      character = mySerial.read();
      cue.concat(mySerial.read());
      if (cue.charAt(cue.length() - 1) == ';') {
        break;
      }
    }
  }
}

int stringtonumber(String snumber) {
  int number = 0;
  for (int z = 0; z < snumber.length(); z++) {
    number = (number*10) + (snumber.charAt(z) - 48);
  }
  return number;
}

void counterclockwise (){
  // 1
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, LOW);
  delay(motorSpeed);
  // 2
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, LOW);
  delay (motorSpeed);
  // 3
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, LOW);
  delay(motorSpeed);
  // 4
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, LOW);
  delay(motorSpeed);
  // 5
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, LOW);
  delay(motorSpeed);
  // 6
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin4, HIGH);
  delay (motorSpeed);
  // 7
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, HIGH);
  delay(motorSpeed);
  // 8
  digitalWrite(motorPin1, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, HIGH);
  delay(motorSpeed);
}

void clockwise(){
  // 1
  digitalWrite(motorPin4, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin1, LOW);
  delay(motorSpeed);
  // 2
  digitalWrite(motorPin4, HIGH);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin1, LOW);
  delay (motorSpeed);
  // 3
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin1, LOW);
  delay(motorSpeed);
  // 4
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, HIGH);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin1, LOW);
  delay(motorSpeed);
  // 5
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin1, LOW);
  delay(motorSpeed);
  // 6
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, HIGH);
  digitalWrite(motorPin1, HIGH);
  delay (motorSpeed);
  // 7
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin1, HIGH);
  delay(motorSpeed);
  // 8
  digitalWrite(motorPin4, HIGH);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin1, HIGH);
  delay(motorSpeed);
}

void deleteOld() {
  if(cue.length() != 0) {
    int n = 1;
    for (n = 1; n < cue.length(); n++) {
      if (cue.charAt(n) == ';') {
        break;
      }
    }
    cue = cue.substring(n + 1);
  }
}


As i wanted to test it on my Attiny45 i rann into the problem of compiling it (Arduino 1.0.1 following THIS tutorial).

The reason: 6.372 Bytes is the size of the compiled sketch. Attiny45 has only 4 :D so ill get an 85, it has 8k memmory. Seems like SoftwareSerial is quite a big library

Robohac

@PaulS Jeah that probably would be easyer, but i have the parts, and a stepperboard costs more than 4€ per stepper. My parts were about 2,50€ so jeah :D (i had thos flying around)

PeterH


The reason: 6.372 Bytes is the size of the compiled sketch. Attiny45 has only 4 :D so ill get an 85, it has 8k memmory. Seems like SoftwareSerial is quite a big library


Do you know how much of that size is taken up by SoftwareSerial? I don't know whether you'd be able to save enough to bring it down to 4K, but there's some pretty repetitive code there and I suspect it would be possible to reduce the size a bit. Worth a try if you're keen to stick with the existing chip.
I only provide help via the forum - please do not contact me for private consultancy.

dc42

I've just done some measurements using the standard Arduino core:

Core (running an empty program): 490 bytes
pinMode and digitalWrite: 864 bytes
SoftwareSerial library: 2114 bytes
String library: 1500 bytes

You could save the 864 bytes and more if you use direct port access, and you could save most of the 1500 bytes if you didn't use String (which is a bad thing to use anyway). You could save some of the SoftwareSerial code if you removed the transmit code and used a fixed baud rate. So I think it's possible to get your program to fit in an Attiny45.

For Attiny mcus, I write the programs in AVR Studio, copying code from the Arduino core and library as and when I need it. That way, I avoid having unnecessary code from the core as well.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

HazardsMind

You should maybe look into direct port manipulation for your stepper motors. It may shave off some of that high memory usage, which is good.
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

robtillaart

Quote
You could save some of the SoftwareSerial code if you removed the transmit code and used a fixed baud rate.

I removed the lookuptables and replaced them with formulas => ~190 bytes saved from the SWserial
- http://arduino.cc/forum/index.php/topic,138497.0.html -
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Robohac

@ dc42 ho would you get rid of strings? should i use char arrays? i think that would make the code much mor complicated, because you constantly have to change the array size.

PeterH


@ dc42 ho would you get rid of strings? should i use char arrays? i think that would make the code much mor complicated, because you constantly have to change the array size.


No, you just make it big enough to cope with all the expected situations, and check to prevent it from overflowing in unexpected situations.
I only provide help via the forum - please do not contact me for private consultancy.

Go Up