PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV 2024 → Read data from a scale via RS232
Read data from a scale via RS232
Débuté par willy hermans, 12 juin 2017 11:00 - 12 réponses
Posté le 12 juin 2017 - 11:00
Hello,

Has anyone an example of how to read the the weight-data from a scale via rs232.

Thanks,

Hermans Willy.
Posté le 12 juin 2017 - 11:20
Hi, be careful. There are scales and there are scales.

- Scales for usage in shops have to be calibrated at regular intervals and the connection to a computer makes the whole thing (Computer + software + scale) being a "weighing system" which has to be certified by your standardization body! After certification you'll get a certificate for all of the systems you install at customer location. The combination has to be always the same otherwise you'll need a new certification process. Customer have to receive a copy of the certificate in order to be able to show it to an auditor coming from the said body. Scales to be used here have to have a certain protocol, no other scales can be accepted in Europe!

- scales for production purposes / laboratories etc. can be connected by a simple RS-232 connection and will spit out the weight continuously. It's your software job to allow the scale to settle down a bit and find an average weight as a result.

Which one do you have?
Posté le 12 juin 2017 - 11:27
It is for a Toshiba SL-4700.
It is linked to a cash desk.

I have an example in C but this is to dificult.

// sl4700w.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Oxsercom.h"
#include "sl4700w.h"
#include "cmdlineparser.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

enum STATUS {
NG = 0,
OK = 1,
ABORT = 2
};
typedef enum STATUS STATUS;

#define STX 0x02
#define ETX 0x03
#define ENQ 0x05
#define ACK 0x06
#define BEL 0x07
#define DC2 0x12
#define NAK 0x15
#define ESC 0x1B
#define DEL 0x7F
#define RCV_ABORT 0xFFFE
#define RCV_TIMEOUT 0xFFFF

COXSerialCommFile grRS232;
CCmdLineParser gCmdLine;

/************/
void init(void)
/************/
{
COXSerialCommConfig vrConfig;

// Open the Port
vrConfig.m_nPortId = 0;
vrConfig.m_nBaudRate = CBR_2400;
vrConfig.m_nByteSize = 7;
vrConfig.m_nParity = EVENPARITY;
vrConfig.m_nStopBits = ONESTOPBIT;
vrConfig.m_eFlowControl = COXSerialCommConfig::NONE;

// Overide settings from the commandline
if (gCmdLine.HasKey("port"))
{
vrConfig.m_nPortId = atoi(gCmdLine.GetVal("port")) - 1;
}

grRS232.Open(vrConfig);
grRS232.PurgeRx();
grRS232.PurgeTx();
}

/************************/
void send(unsigned char acChar)
/************************/
{
if (!grRS232.GetDSR())
{
if (!gCmdLine.HasKey("nodsr"))
return;
}

char vcChar = acChar;
grRS232.Write(&vcChar, 1);
}

/***************/
int receive(void)
/***************/
{
char vcChar;
int x;

for(int i=0; i<25 && grRS232.IsRxQueueEmpty(); i++)
{
Sleep(10);
}

if (grRS232.IsRxQueueEmpty())
{
return RCV_TIMEOUT;
}

grRS232.Read(&vcChar, 1);
x = vcChar;
return x;
}

/***********************************/
enum STATUS ReceiveWeight(char *buff)
/***********************************/
{
char weight[8], ch;
int i, bcc=0;

for(i=0; i empty file
break;
}

fflush(fp);
fclose(fp);
return OK;
}

return NG;
}

/***************************/
void ReceiveData(bool abLoop)
/***************************/
{
bool stop = false;
int state = 1, retry = 0, ret, ch;
char buff[6];

do
{
if (gCmdLine.HasKey("debug"))
{
printf("State %d\ ", state);
}
switch (state)
{
case 1:
grRS232.PurgeRx();
send(ENQ);
ch = receive();
if (gCmdLine.HasKey("debug"))
{
printf("Receive %d %02x %c\ ", ch, ch, isprint(ch) ? ch : '.');
}
switch (ch)
{
case ACK:
state = 2;
break;

case RCV_TIMEOUT:
case RCV_ABORT:
stop = TRUE;
break;

case BEL:
case NAK:
default:
state = 1;
break;
}
break;

case 2:
send(DC2);
ch = receive();
if (gCmdLine.HasKey("debug"))
{
printf("Receive %d %02x %c\ ", ch, ch, isprint(ch) ? ch : '.');
}
switch (ch)
{
case STX:
ret = ReceiveWeight(buff);
if (gCmdLine.HasKey("debug"))
{
printf("Receiveweight %d %02x %c\ ", ret, ret, isprint(ret) ? ret : '.');
}
if (ret == OK)
{
int x = SaveData(buff);
if (gCmdLine.HasKey("debug"))
{
printf("SaveData %d %02x %c\ ", x, x, isprint(x) ? x : '.');
}
if (!abLoop && x == OK) stop = true;
state = 3;
}
else if (ret == ABORT)
{
stop = TRUE;
}
else
{
if (retry++ > 5)
{
retry = 0;
state = 1;
}
else
{
state = 2;
}
}
break;

case RCV_ABORT:
stop = TRUE;
break;

case NAK:
if (retry++ > 5)
{
retry = 0;
state = 1;
}
else
{
state = 2;
}
break;

default:
state = 1;
}
break;

case 3:
send(ACK);
state = 1;
break;

default:
state = 1;
} /* switch */
} while(!stop);

if (gCmdLine.HasKey("debug"))
{
printf("stop.\ ", state);
}
}

// The one and only application object
CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;

// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\ "));
nRetCode = 1;
}
else
{
gCmdLine = ::GetCommandLine();
if (gCmdLine.HasKey("help") || gCmdLine.HasKey("?"))
{
printf("SL4700 communication program (WIN32) - Version 2.2.1\ \ ");
printf("Copyright (C) Toshiba TEC Europe Retail Information Systems 1994-2006.\ \ \ \ ");

printf("usage: sl4700w [/file:\"filename\"][/port:x][/append][/debug][/show][/nodsr][/loop]\ ");
}

init();
// while (!grRS232.GetCD()) Sleep(1000);
ReceiveData(gCmdLine.HasKey("loop"));
grRS232.Close();
}

return nRetCode;
}
Posté le 12 juin 2017 - 11:55
Hallo Willy,

i can give you my code, but it is for another scale ( nr1 is COM Port ).

IF sOpen(nr1,2000,2000,sDefaultTimeout,True) THEN
sParameter(nr1,9600,0,8,0)
sRead(nr1,sInEntryQueue(nr1))
sWrite(nr1,"w") // send command to the scale
Multitask(20)
tx1 = sRead(nr1,sInEntryQueue(nr1)) // get the answer
sClose(nr1)
RESULT Val(Middle(ExtractString(tx1,2,CR),7,5)) // extract the weight
END
Posté le 12 juin 2017 - 14:38
Hi,

I Been working with scales since 1985, now for METTLER TOLEDO (Word largest manufacturer of scales).

It`s easy to code using WinDev, but you might want to check out more than just a scale value, you should not use a scale value if the weight is in motion, and as Gunter P Points out the scale usually has to be legal for trade when connected to a POS system. And perhaps you have to have to validate the whole system with "Weight and measurements" authority in the target country.

Some SImple protocolls like our SICS Protocoll you just send a S and the scale returns S S "weight value" "unit" CRLF if stable and S D "weight value" "unit" if Dynamic (Motion) but on the other hand in MT-continuous mode the motion is a bit within the status byte.

Also the different scale manufacturers can use different protocols on the scale in MT we support SICS, MT-Continuous,DATA Access, Modbus, Profibus to mention a few,

If you ask me a Ethernet connection to the scale is better than RS232 but your choice :)


Cheers
Tor-Bjarne
Posté le 13 juin 2017 - 08:23
Hello,

I've tried this

txt1 is string = ""
IF sOpen(1,2000,2000,sDefaultTimeout,True) THEN

sParameter(1,2400,1,7,1)
//sParameter(1,9600,0,8,0)
sRead(1,sInEntryQueue(1))
sWrite(1,"w") // send command to the scale
Multitask(20)
txt1 = sRead(1,sInEntryQueue(1)) // get the answer
sClose(1)
EDT_Resultaat += txt1 + CRLF
EDT_Resultaat += Val(Middle(ExtractString(txt1,2,CR),7,5))+CRLF// extract the weight
END

It returns an empty string..


I also tried this

PROCEDURE Test()

lPoortStatus is boolean
lPoortStatus = sOpen(1,2000,2000,sDefaultTimeout,True)

cResult is Buffer
nSize is int

EDT_Resultaat = ""

IF lPoortStatus = True THEN

sParameter(1,2400,1,7,1)

IF Length(EDT_Send) = 0 THEN
sWrite(1,StringToUTF8("AT"))
ELSE
sWrite(1,StringToUTF8(EDT_Send+Charact(13)))
END
Multitask(20)
//wait(100))
nSize = sInEntryQueue(1)
cResult = sRead(1,nSize)

EDT_Resultaat += nSize + CRLF
EDT_Resultaat += cResult
EDT_Resultaat += sRead(1,sInEntryQueue(1))
nSize = sInEntryQueue(1)
cResult += sRead(1,nSize)

EDT_Resultaat += nSize + CRLF
EDT_Resultaat += cResult+CRLF+CRLF

IF Length(EDT_Send) = 0 THEN
sWrite(1,StringToUTF8("AT"))
ELSE
sWrite(1,StringToUTF8(EDT_Send))
END
Multitask(20)
//wait(100))
nSize = sInEntryQueue(1)
cResult = sRead(1,nSize)

EDT_Resultaat += nSize + CRLF
EDT_Resultaat += cResult
EDT_Resultaat += sRead(1,sInEntryQueue(1))
nSize = sInEntryQueue(1)
cResult += sRead(1,nSize)

EDT_Resultaat += nSize + CRLF
EDT_Resultaat += cResult+CRLF+CRLF


ELSE
EDT_Resultaat = "Kan poort niet openen"
END

sClose(1)


This returns almost always
x€0
depending on the input
Posté le 13 juin 2017 - 09:16
Hi, did you set the protocol by switches or TTY ..? Or: do you know the protocol needed to talk to the scale? Hint: the scale should be accompanied by a manual that details the switches and the protocol. If not, ask the supplier of the scale ...
Posté le 13 juin 2017 - 10:09
Hi,

It actually looks from you "Scale result" that there might bee an inconsistency in the RS232 Setup, remember the scale must be set up with the same baud rate, data bit, stop pit and parity as your software.

Also handshake should be set to of (There`s so little data in your request that handshake is not needed)

a trick is to use Hyperterminal or similar program, to check that the scale has such a valid configuration " as you think", before you start coding.

When you are able to write a 'w' CRLF (if this is the request weight command), and get the weight value back to your terminal emulator you can start worrying about WinDev code. As it is now we do not know if scale requires the hardware signals to send data or a missing Xon, or if something is wrong within your code.

And I don`t know why you use the StringToUTF8 a scale is usually basic ASCII 256 when connected via RS232.

cheers
Tor-Bjarne
Posté le 14 juin 2017 - 09:24
Hi Willy,

Years ago (in 2002 I believe) I created such an interface (might have been parallel port still though instead of serial) with industrial precision weighing scales of different brands for an Irish customer.

I recall that depending on the brand we had to wire our (Parallel or Serial) connectors differently.
Mettler Toledo used a different wiring scheme than the other brands if I recall correctly.

I'll see if I can find some documentation back and will return to you if found.
Not sure, but I guess most modern scales have usb or even ethernet interfaces now so that might be an option as well.

I'll let you know if I found something in my archives.

Bye,

Peter Holemans
Posté le 14 juin 2017 - 10:21
Hi,

Nowdays the 9 PIN wiring is usually Pint 2 (Rx) to 3(Tx) , pin 3(Tx) to 2(Rx) and Pin 5 to 5 (GND), unless the Hardware-protocol is used then you have to make a "Nul modem cable" all searchable on the internet.

I do not think however it`s the cable that is the problem. (But you never know)

cheers
Tor-Bjarne
Posté le 14 juin 2017 - 12:20
Found this back in my archives (Concerned a custom C++ on Citrix DLL talking to WD and getting the data back project integrating with different brands of industrial precision scales, bar codes scanners and Zebra printers):

In short: Mettler Toledo used standard wiring re-reading my tech specs.
Sartorius balances on the other hand required an adapted RS-232 wiring

...
Sartorius balances require the following pin assignments on the 25 pin connectors of the RS-232 interface:
- Tested with a standard 25 (balance) to 9 pin (terminal) cable -
Pin 1: Enable
Pin 2: Enable
Pin 3: Enable
Pin 4: Enable
Pin 5: Enable
Pin 6: Disable
Pin 7: Enable
Pin 8: Enable
Pin 9: Enable
Pin 10: Disable
Pin 11: Enable
Pin 12: Enable
Pin 13: Enable
Pin 14: Enable
Pin 15: Enable
Pin 16: Disable
Pin 17: Disable
Pin 18: Disable
Pin 19: Disable
Pin 20: Enable
Pin 21: Enable
Pin 22: Disable
Pin 23: Disable
Pin 24: Enable
Pin 25: Enable

You never know it may give you a clue on your issue...

Cheers,

Peter Holemans
Posté le 15 juin 2017 - 15:48
Even with HyperTerminal I receive strange respons.

The port settings are correct

This is a page delivered by the scale manufacturer
Delivered by manufacturer

There are no dip switches on the scale.
Posté le 16 juin 2017 - 08:52
Hi

The Serial setup seems to be

//2400 baud, 7 Databit,Even parity,1 Stopbit and no-handhsake ComX is int = 1 sParameter(nComX,2400,7,1,0,False,False,False)
So the strange signs can be a result of you using the wrong Baud (9600).

Now out from your sparse documentation I suspect a ENQ(Enquery/ACK(Acknowledge) protocol, (HP Invented this in 1972)

So It seems you have to send ENQ, or DC2 to the scale, if you receive data from the scale you send ACK, or if you want the same packet of data to be re-sent you send a NAK.

If it`s not a packet of 8 bytes I recon you get a 0x07(Bell) informing that the weight is unstable, and so fort.

I guess your protocol has to be something like:

You: ENQ
Scale ACK
You: DC2
Scale: STX,ID,W5,W4,W3,W2,W1,BCC,ETX // if all good
or
scale: BEL //Unstable

anyhow you send: ACK if you got data within say 50 ms, if not you send NAK

You: ACK or NAK

It`s important you keep track of ENQ/ACK as some equitment (as the scale) can be waiting for an ACK or NAK before sending data again (Next time you want to read the scale).

And if you study the C code you see it is written as a small state machine (I hate state machines), setting the code into a state if waiting for some thing to happen:
case 2: <<- State send(DC2); <<- Request weight retry = 0; state = 1; <<- sets new state furter down in the code: switch (ch) { case ACK: state = 2; <<- ok break; case RCV_TIMEOUT: case RCV_ABORT: stop = TRUE; break; case BEL: case NAK: default: state = 1; <<- state 1 again requesting weight break; ch = receive();


cheers
Tor-Bjarne