Go Down

Topic: Arduino 328 board connected to a balance (Read 6874 times) previous topic - next topic

Labuschagne3

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

GrooveFlotilla

#1
Jul 06, 2009, 12:10 pm Last Edit: Jul 06, 2009, 12:16 pm by GrooveFlotilla Reason: 1
Quote
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"?
Code: [Select]
if ( c != 13 ) {
    if (c >= 46 && c <=57 ) { //only get numbers and .

is easier to read (for you and others) if you write:
Code: [Select]
if ( c != '\r' ) {
    if (c >= '.' && c <='9' ) { //only get numbers and .
Some people are like Slinkies.

Not really good for anything, but they bring a smile to your face when pushed down the stairs.

Labuschagne3

Hi

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

Regards

Johannes

GrooveFlotilla

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:
Code: [Select]
char c = softSerial.read();
to this:
Code: [Select]
char c = softSerial.read() & 0x7F;
(and anywhere else you read a char using the soft serial library)
Some people are like Slinkies.

Not really good for anything, but they bring a smile to your face when pushed down the stairs.

Labuschagne3

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

Labuschagne3

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 <

GrooveFlotilla

#6
Jul 06, 2009, 01:35 pm Last Edit: Jul 06, 2009, 01:48 pm by GrooveFlotilla Reason: 1
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:
Code: [Select]
// 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!
Some people are like Slinkies.

Not really good for anything, but they bring a smile to your face when pushed down the stairs.

Labuschagne3

Any suggstions on this

Code: [Select]
// 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

GrooveFlotilla

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?
Some people are like Slinkies.

Not really good for anything, but they bring a smile to your face when pushed down the stairs.

Labuschagne3

Thanks for all your help

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


GrooveFlotilla

Some people are like Slinkies.

Not really good for anything, but they bring a smile to your face when pushed down the stairs.

Labuschagne3

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

Code: [Select]
/*
 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));
}

GrooveFlotilla

#12
Jul 06, 2009, 03:38 pm Last Edit: Jul 06, 2009, 03:46 pm by GrooveFlotilla Reason: 1
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.
Some people are like Slinkies.

Not really good for anything, but they bring a smile to your face when pushed down the stairs.

Labuschagne3

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:

Code: [Select]
//  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);
 
}  




zooto68

My finger hurts after all that unneccessary scrolling  ::)

Go Up