Arduino 328 board connected to a balance

Hi All

I’m trying to read data from a balance (Scales), I got a arduino Duemilanove 328 board.

The balance can only be set to Baud 9600, Stop Bits 7, Parity Even.

The arduino code shoud be set to read 7 stop bits in stead of 8.

I connected the Balance directly to th PC Com1 port then I can read the data from the balance, using realterm and echo it back to com2 serial where my arduino serial board is connected the arduino board will read the data.

But when I plug the balance directli into the Arduino serial port I dont get any data comming in from the balance.

Can someone please look at my code and advise me.

The code I’m using is as follow.

// 26 April 2009
// Version .6

#include <SoftwareSerial7.h>
#include <WString.h>

//rx and tx pins
int rx_pin = 2;
int tx_pin = 3;
int relay_pin = 8;
int relay2_pin = 9;
int relay3_pin = 10;
int state;

//buffer for values coming in
String reading = String(19);

//Initialise the external serial port
SoftwareSerial7 softSerial = SoftwareSerial7(rx_pin, tx_pin);

void setup()
{
// for software serial
pinMode(rx_pin, INPUT);
pinMode(tx_pin, OUTPUT);
pinMode(relay_pin, OUTPUT);

// set the data rate for the hardware serial port
Serial.begin(9600);
// set the data rate for the SoftwareSerial port
softSerial.begin(9600);

//switch relay on
digitalWrite(relay_pin, HIGH);
state = 0;
}

void loop()
{
if (state == 0) {
//step 1 read values and stop the relay when it gets to the right weight
//Serial.println(“State 0”);
double value;
char c = softSerial.read();
if ( c != 13 ) {
if (c >= 46 && c <=57 ) { //only get numbers and .
reading.append(c);
} else {
}
} else {
value = atof(reading);
Serial.println(value);
if ( value > 40 ) {
if ( value > 50 ) {
Serial.println(“Over”);
//trip relay off
digitalWrite(relay_pin, LOW);
//Increment state so that we move onto the next part of the loop
state = 1;
} else {
//pulse the relay
Serial.println(“Pulse”);
digitalWrite(relay_pin, HIGH);
delay(100);
digitalWrite(relay_pin, LOW);
}
}
reading = “”;
}
}
//step 2 - tip the bowl
if (state == 1) {
Serial.println(“State 1”);
digitalWrite(relay2_pin, HIGH);
delay(5000);
digitalWrite(relay2_pin, LOW);
state = 2;
}

//step 3 - seal the bag
if (state == 2) {
Serial.println(“State 2”);
digitalWrite(relay3_pin, HIGH);
delay(5000);
digitalWrite(relay3_pin, LOW);
state = 3;
}

//step 4 - start the relay
if (state == 3) {
Serial.println(“State 3”);
delay(5000);
digitalWrite(relay_pin, HIGH);
state = 0;
}

}

Many thanks

Johannes

The balance can only be set to Baud 9600, Stop Bits 7, Parity Even

Seven stop bits is excessive - I’ve never heard of more than 2 stop bits.
Did you mean “7 data, 1 stop, even parity”?

 if ( c != 13 ) {
     if (c >= 46 && c <=57 ) { //only get numbers and .

is easier to read (for you and others) if you write:

 if ( c != '\r' ) {
     if (c >= '.' && c <='9' ) { //only get numbers and .

Hi

Yes sorry I ment 7 data, 1 stop, even parity.

Regards

Johannes

If you're using a software serial library to read the results from the balance, you'll need to modify the library - it will probably be as simple as changing a constant for the number of data bits from 8 to 7, though I'm puzzled why it isn't working anyway. Are you sure that you're not receiving anything, or maybe just what looks like junk?

Try changing this line:char c = softSerial.read(); to this:char c = softSerial.read() & 0x7F; (and anywhere else you read a char using the soft serial library)

My programming is not very good, do I have to change it in the code and in the soft serial file.

here is my softserial code, can you please have a look and see where I must make any changes?

/*
NewSoftSerial.cpp - Multi-instance software serial library
Copyright (c) 2006 David A. Mellis. All rights reserved.
Interrupt-driven receive and other improvements by ladyada
Tuning, circular buffer, derivation from class Print,
multi-instance support, porting to 8MHz processors by
Mikal Hart

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

The latest version of this library can always be found at
http://arduiniana.org.
*/

// When set, _DEBUG co-opts pins 11 and 13 for debugging with an
// oscilloscope or logic analyzer. Beware: it also slightly modifies
// the bit times, so don’t rely on it too much at high baud rates
#define _DEBUG 0

//
// Includes
//
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include “WConstants.h”
#include “pins_arduino.h”
#include “NewSoftSerial7.h”
//
// Lookup table
//
typedef struct _DELAY_TABLE
{
long baud;
unsigned short rx_delay_centering;
unsigned short rx_delay_intrabit;
unsigned short rx_delay_stopbit;
unsigned short tx_delay;
} DELAY_TABLE;

#if F_CPU == 16000000

static const DELAY_TABLE PROGMEM table =
{
// baud rxcenter rxintra rxstop tx
{ 115200, /5/1, 17, 17, /15/13, },
{ 57600, /15/10, 37, 37, 34, },
{ 38400, 25, 57, 57, 54, },
{ 31250, 31, 70, 70, 68, },
{ 28800, 34, 77, 77, 74, },
{ 19200, 54, 117, 117, 114, },
{ 14400, 74, 156, 156, 153, },
{ 9600, 114, 236, 236, 233, },
{ 4800, 233, 474, 474, 471, },
{ 2400, 471, 950, 950, 947, },
{ 1200, 947, 1902, 1902, 1899, },
{ 300, 3804, 7617, 7617, 7614, },
};

#define XMIT_START_ADJUSTMENT 5

#elif F_CPU == 8000000

static const DELAY_TABLE table PROGMEM =
{
// baud rxcenter rxintra rxstop tx
{ 115200, 1, 5, 5, 3, },
{ 57600, 1, 15, 15, /12/13, },
{ 38400, /6/2, 25, /25/26, /22/23, },
{ 31250, /9/7, 32, 33, 29, },
{ 28800, 11, 35, 35, 32, },
{ 19200, 20, 55, 55, 52, },
{ 14400, 30, 75, 75, 72, },
{ 9600, 50, 114, 114, 112, },
{ 4800, 110, 233, 233, 230, },
{ 2400, 229, 472, 472, 469, },
{ 1200, 467, 948, 948, 945, },
{ 300, 1895, 3805, 3805, 3802, },
};

#define XMIT_START_ADJUSTMENT 4

#else

#error This version of NewSoftSerial supports only 16 and 8MHz processors

#endif

//
// Statics
//
NewSoftSerial7 *NewSoftSerial7::active_object = 0;
char NewSoftSerial7::_receive_buffer[_NewSS_MAX_RX_BUFF];
volatile uint8_t NewSoftSerial7::_receive_buffer_tail = 0;
volatile uint8_t NewSoftSerial7::_receive_buffer_head = 0;

//
// Debugging
//
// This function generates a brief pulse on pin 8-13
// for debugging or measuring on an oscilloscope.
inline void DebugPulse(uint8_t pin, uint8_t count)
{
#if _DEBUG
uint8_t a = PORTB;
while (count–)
{
PORTB = a | _BV(pin-8);
PORTB = a;
}
#endif
}

//
// Private methods
//

/* static */
inline void NewSoftSerial7::tunedDelay(uint16_t delay) {
uint8_t tmp=0;

asm volatile(“sbiw %0, 0x01 \n\t”
“ldi %1, 0xFF \n\t”
“cpi %A0, 0xFF \n\t”
“cpc %B0, %1 \n\t”
“brne .-10 \n\t”
: “+r” (delay), “+a” (tmp)
: “0” (delay)
);
}

// This function sets the current object as the “active”
// one and returns true if it replaces another
bool NewSoftSerial7::activate(void)
{
if (active_object != this)
{
_buffer_overflow = false;
uint8_t oldSREG = SREG;
cli();
_receive_buffer_head = _receive_buffer_tail = 0;
active_object = this;
SREG = oldSREG;
return true;
}

return false;
}

//
// The receive routine called by the interrupt handler
//
void NewSoftSerial7::recv()
{

#if GCC_VERSION < 40302
// Work-around for avr-gcc 4.3.0 OSX version bug
// Preserve the registers that the compiler misses
// (courtesy of Arduino forum user etracer)
asm volatile(
“push r18 \n\t”
“push r19 \n\t”
“push r20 \n\t”
“push r21 \n\t”
“push r22 \n\t”
“push r23 \n\t”
“push r26 \n\t”
“push r27 \n\t”
::);
#endif

uint8_t d = 0;

// If RX line is high, then we don’t see any start bit
// so interrupt is probably not for us
if (!rx_pin_read())
{
// Wait approximately 1/2 of a bit width to “center” the sample
tunedDelay(_rx_delay_centering);
DebugPulse(13, 1);

// Read each of the 8 bits
// for (uint8_t i=0x1; i; i <<= 1)
for (uint8_t i=0x1; i != 0x8; i <<= 1)
{
tunedDelay(_rx_delay_intrabit);
DebugPulse(13, 1);
uint8_t noti = ~i;
if (rx_pin_read())
d |= i;
else // else clause added to ensure function timing is ~balanced
d &= noti;
}

// skip the stop bit and parity bit
tunedDelay(_rx_delay_stopbit *2);
// skip the stop bit
// tunedDelay(_rx_delay_stopbit);
DebugPulse(13, 1);

// if buffer full, set the overflow flag and return
if ((_receive_buffer_tail + 1) % _NewSS_MAX_RX_BUFF != _receive_buffer_head)
{
// save new data in buffer: tail points to where byte goes
_receive_buffer[_receive_buffer_tail] = d; // save new byte
_receive_buffer_tail = (_receive_buffer_tail + 1) % _NewSS_MAX_RX_BUFF;
}
else
{
#if _DEBUG // for scope: bring pin 11 high: overflow indicator
PORTB |= _BV(3);
#endif
_buffer_overflow = true;
}
}

#if GCC_VERSION < 40302
// Work-around for avr-gcc 4.3.0 OSX version bug
// Restore the registers that the compiler misses
asm volatile(
“pop r27 \n\t”
“pop r26 \n\t”
“pop r23 \n\t”
“pop r22 \n\t”
“pop r21 \n\t”
“pop r20 \n\t”
“pop r19 \n\t”
“pop r18 \n\t”
::);
#endif
}

void NewSoftSerial7::tx_pin_write(uint8_t pin_state)
{
if (pin_state == LOW)
*_transmitPortRegister &= ~_transmitBitMask;
else
*_transmitPortRegister |= _transmitBitMask;
}

uint8_t NewSoftSerial7::rx_pin_read()
{
return *_receivePortRegister & _receiveBitMask;
}

//
// Interrupt handling
//

/* static */
inline void NewSoftSerial7::handle_interrupt()
{
if (active_object)
{
active_object->recv();
}
}

ISR(PCINT0_vect)
{
NewSoftSerial7::handle_interrupt();
}

ISR(PCINT1_vect)
{
NewSoftSerial7::handle_interrupt();
}

ISR(PCINT2_vect)
{
NewSoftSerial7::handle_interrupt();
}

//
// Constructor
//
NewSoftSerial7::NewSoftSerial7(uint8_t receivePin, uint8_t transmitPin) :
_rx_delay_centering(0),
_rx_delay_intrabit(0),
_rx_delay_stopbit(0),
_tx_delay(0),
_buffer_overflow(false)
{
setTX(transmitPin);
setRX(receivePin);
}

//
// Public methods
//
void NewSoftSerial7::setTX(uint8_t tx)
{
pinMode(tx, OUTPUT);
digitalWrite(tx, HIGH);
_transmitBitMask = digitalPinToBitMask(tx);
uint8_t port = digitalPinToPort(tx);
_transmitPortRegister = portOutputRegister(port);
}

void NewSoftSerial7::setRX(uint8_t rx)
{
pinMode(rx, INPUT);
digitalWrite(rx, HIGH); // pullup!
_receivePin = rx;
_receiveBitMask = digitalPinToBitMask(rx);
uint8_t port = digitalPinToPort(rx);
_receivePortRegister = portInputRegister(port);
}

void NewSoftSerial7::begin(long speed)
{
_rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0;

for (unsigned i=0; i<sizeof(table)/sizeof(table[0]); ++i)
{
long baud = pgm_read_dword(&table*.baud);*

  • if (baud == speed)*
  • {*
    rx_delay_centering = pgm_read_word(&table*.rx_delay_centering);
    _rx_delay_intrabit = pgm_read_word(&table.rx_delay_intrabit);
    _rx_delay_stopbit = pgm_read_word(&table.rx_delay_stopbit);
    _tx_delay = pgm_read_word(&table.tx_delay);*

    * break;
    }
    }
    // Set up RX interrupts, but only if we have a valid RX baud rate*

    * if (rx_delay_stopbit)*
    * {*

    * if (receivePin < 8)*
    * {
    // a PIND pin, PCINT16-23*

    * PCICR |= BV(2);
    PCMSK2 |= BV(receivePin);*
    * }*

    * else if (receivePin <= 13)*
    * {*

    * // a PINB pin, PCINT0-7*_

    * PCICR |= _BV(0);
    PCMSK0 |= BV(receivePin-8);*
    * }*

    * else if (_receivePin <*

Can you please use the “Code” button when posting software please?

First of all, I’d try the simple fix in your own sketch, before messing with the library.

Seven data bits plus parity and one stop bit gives the same frame length as eight data plus stop bit.
The library probably simply counts bits and shifts them into a byte as soon as it detects a valid start bit.
However, the parity bit may be set, which may mean that the most significant bit of the byte may be invalid for simple comparisons, (for instance “0x0D” consists of three set bits (odd parity), so the actual value will be padded to “0x8D” to give an even number of set bits.
ANDing this with 0x7F will give you the value you expect.
To see if the serial line is receiving characters, you could try blinking a LED.

Re: library:

 // Read each of the 8 bits
//    for (uint8_t i=0x1; i; i <<= 1)
   for (uint8_t i=0x1; i != 0x8; i <<= 1)

That doesn’t look right!

Any suggstions on this

 // Read each of the 8 bits
//    for (uint8_t i=0x1; i; i <<= 1)
   for (uint8_t i=0x1; i != 0x8; i <<= 1)

you said it does not look right

Well, I'm not sure, but that looks like it would only read three bits of the character. (for i = 1, i = 2, i = 4)

Have you tried any of the other soft serial libraries?

Is this library tested?

Thanks for all your help

No I havn't, where can I get other softserials that will work?

Try: http://arduino.cc/en/Reference/SoftwareSerial

make sure you read the description very carefully.

Sorry I think I send you the wrong code for soft serial can you please look at this one.

/*
  SoftwareSerial.cpp - Software serial library
  Copyright (c) 2006 David A. Mellis.  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
*/

/******************************************************************************
 * Includes
 ******************************************************************************/

#include "WConstants.h"
#include "SoftwareSerial7.h"

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

/******************************************************************************
 * Constructors
 ******************************************************************************/

SoftwareSerial7::SoftwareSerial7(uint8_t receivePin, uint8_t transmitPin)
{
  _receivePin = receivePin;
  _transmitPin = transmitPin;
  _baudRate = 0;
}

/******************************************************************************
 * User API
 ******************************************************************************/

void SoftwareSerial7::begin(long speed)
{
  _baudRate = speed;
  _bitPeriod = 1000000 / _baudRate;

  digitalWrite(_transmitPin, HIGH);
  delayMicroseconds( _bitPeriod); // if we were low this establishes the end
}

int SoftwareSerial7::read()
{
  int val = 0;
  int bitDelay = _bitPeriod - clockCyclesToMicroseconds(50);
  
  // one byte of serial data (LSB first)
  // ...--\    /--\/--\/--\/--\/--\/--\/--\/--\/--...
  //       \--/\--/\--/\--/\--/\--/\--/\--/\--/
  //      start  0   1   2   3   4   5   6   7 stop

  while (digitalRead(_receivePin));

  // confirm that this is a real start bit, not line noise
  if (digitalRead(_receivePin) == LOW) {
    // frame start indicated by a falling edge and low start bit
    // jump to the middle of the low start bit
    delayMicroseconds(bitDelay / 2 - clockCyclesToMicroseconds(50));
      
    // offset of the bit in the byte: from 0 (LSB) to 7 (MSB)
    for (int offset = 0; offset < 7; offset++) {
      // jump to middle of next bit
      delayMicroseconds(bitDelay);
      
      // read bit
      val |= digitalRead(_receivePin) << offset;
    }
      
    delayMicroseconds(_bitPeriod);
    
    return val;
  }
  
  return -1;
}

void SoftwareSerial7::print(uint8_t b)
{
  if (_baudRate == 0)
    return;
    
  int bitDelay = _bitPeriod - clockCyclesToMicroseconds(50); // a digitalWrite is about 50 cycles
  byte mask;

  digitalWrite(_transmitPin, LOW);
  delayMicroseconds(bitDelay);

  for (mask = 0x01; mask; mask <<= 1) {
    if (b & mask){ // choose bit
      digitalWrite(_transmitPin,HIGH); // send 1
    }
    else{
      digitalWrite(_transmitPin,LOW); // send 1
    }
    delayMicroseconds(bitDelay);
  }

  digitalWrite(_transmitPin, HIGH);
  delayMicroseconds(bitDelay);
}

void SoftwareSerial7::print(const char *s)
{
  while (*s)
    print(*s++);
}

void SoftwareSerial7::print(char c)
{
  print((uint8_t) c);
}

void SoftwareSerial7::print(int n)
{
  print((long) n);
}

void SoftwareSerial7::print(unsigned int n)
{
  print((unsigned long) n);
}

void SoftwareSerial7::print(long n)
{
  if (n < 0) {
    print('-');
    n = -n;
  }
  printNumber(n, 10);
}

void SoftwareSerial7::print(unsigned long n)
{
  printNumber(n, 10);
}

void SoftwareSerial7::print(long n, int base)
{
  if (base == 0)
    print((char) n);
  else if (base == 10)
    print(n);
  else
    printNumber(n, base);
}

void SoftwareSerial7::println(void)
{
  print('\r');
  print('\n');  
}

void SoftwareSerial7::println(char c)
{
  print(c);
  println();  
}

void SoftwareSerial7::println(const char c[])
{
  print(c);
  println();
}

void SoftwareSerial7::println(uint8_t b)
{
  print(b);
  println();
}

void SoftwareSerial7::println(int n)
{
  print(n);
  println();
}

void SoftwareSerial7::println(long n)
{
  print(n);
  println();  
}

void SoftwareSerial7::println(unsigned long n)
{
  print(n);
  println();  
}

void SoftwareSerial7::println(long n, int base)
{
  print(n, base);
  println();
}

// Private Methods /////////////////////////////////////////////////////////////

void SoftwareSerial7::printNumber(unsigned long n, uint8_t base)
{
  unsigned char buf[7 * sizeof(long)]; // Assumes 8-bit chars. 
  unsigned long i = 0;

  if (n == 0) {
    print('0');
    return;
  } 

  while (n > 0) {
    buf[i++] = n % base;
    n /= base;
  }

  for (; i > 0; i--)
    print((char) (buf[i - 1] < 10 ? '0' + buf[i - 1] : 'A' + buf[i - 1] - 10));
}

That looks a little more sensible, after a quick scan.

I'd take this one step at a time - first I'd try to get the serial line working, making sure you can receive stuff from the balance.

A thought - how is the balance's serial line connected to the Arduino, and is it an RS232 device? How are you doing the level conversion? Have you checked this part of the circuit?

[LATER] Another thought. Although that library you just posted looks like a modified version (for seven bits) of the standard software serial library, I think I'd use the standard library, and just AND everything that comes out of it with 0x7F, as I said earlier.

You do need to take it step-by-step - forget the relay stuff, strip it out and concentrate on getting good readings from the balance. You'll gain experience, and not be distracted by too many lines of code.

I’m getting a reply from the balance now. Unfortuanately I can’t read it, it is just squares that i’m getting.

Can you please have a look?

I’m using the following code:

//  15 April 2009

#include <SoftwareSerial.h>


//rx and tx pins 
int rx_pin    =  2;
int tx_pin    =  3;


int startbyte;
int userInput[3];
int byte_1;
int byte_2;
int i;
int smoke_toggle = LOW; 
int led_toggle = LOW;
int status = LOW;


SoftwareSerial softSerial =  SoftwareSerial(rx_pin, tx_pin);

void setup()
{
  // for software serial
  pinMode(rx_pin, INPUT);
  pinMode(tx_pin, OUTPUT);

  // set the data rate for the hardware serial port
  Serial.begin(9600);
  // set the data rate for the SoftwareSerial port
  softSerial.begin(9600);
  Serial.println("Hello world!");  

}

void loop() 
{
   
  char c = softSerial.read()& 0x7F;
  delay(1000);
  Serial.println(c);
  
}

My finger hurts after all that unneccessary scrolling ::)

void loop() {

char c = softSerial.read()& 0x7F; delay(1000); Serial.println(c);

}

The problem with the soft serial libraries is that they can't receive in the background (that's why "available" doesn't work), so putting that delay in doesn't help. In other words, you can only receive if you're acually calling the "read" method, unlike the hardware receive method which buffers. Can you take out the delay? What does your interface circuit look like? Can you post a link to the spec of the balance?

Hi

Thank tou very much for all your help.

Sorry for all the code, I'm new in the forums.

The balance is a Mettler Tolede Pm400 balance that I'm using.

I removed the delay and it made it a bit worse.

Any other ideas?

How is the balance connected to the Arduino? Do you have level shifters/inverters?

I got the balance connected to the following serial board http://sodoityourself.com/max232-serial-level-converter/ then from the serial board to pin 2 and 3 of the arduino board and then from the ardunio board to the Computer with a usb Cable so I can do the uploads to the board.

Have you tried printing the received characters in hex, to see if there's any consistency or pattern?