|
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 |
| |
| |
| | | |
|
| | | | |
| | |
|