 |
|
 |
i need connect 2 pc for this port (serial), can you help me, please.
|
|
|
|
 |
|
 |
hi, i was wondering:
1) can the serial port being use to control a RC toy car?? i mean the RC controller will only act as the signal transmitter while the GUI (MFC dialog-based) will act as the controller. i was thinking about using the serial port as the communication..so, is it possible?
2) if it is, how can it be done?
these two q's has given me a headache lately...LOL.
|
|
|
|
 |
|
 |
I am interning at a company and they have asked me to retrieve temperature and humidity from a new therm. chamber they just bought, with a Watlow Series F4S/D controller. We have added a RS232(serial port) onto the machine. I have checked the http://www.watlow.com/prodtechinfo (Data communication referemce) and it help me understand more about the communication information between the controller and the RS232 and what programs to use. But I was looking for more of an example to work off
Adri-
|
|
|
|
 |
|
 |
As we are using characters 0x13 and 0x19 for flow control.
{
...
dcb.XonChar = 0x13;
dcb.XoffChar = 0x19;
...
}
Will this cause any problem if we try to send these characters as data.
Also can any one help me find what are the different flow controls available and how to configure port to use each of these?
Thnx N Rgds
Vinayak
Chitragar
|
|
|
|
 |
|
 |
Hi
i want to OCRB or any device which have receive and send message.
thank you.
|
|
|
|
 |
|
 |
Hi,
I don't what you want. As far as I know OCRB is a standardized font designed for OCR devices and I don't find the exact relation with this article. Can you explain more ?
Regards,
Idael
|
|
|
|
 |
|
 |
I have a problem on a Win98 laptop of which I suspect that the serial port is functioning poorly as I often get time-outs. The suspicion I have is that the comm port is closed somehow and the function IsOpen() does not detect this. What happens is that the program continuously tries to write a string located in buffer to the weaving loom through the serial port:
int r = CSerialPort::Write(Buffer,Size);
if (r>0)
{
// process
return 1;
}
else
{
FILE* Out = fopen("Test.txt","a+");
fprintf("Open or not : %d\n",IsOpen());
fclose(Out);
// Close()
// Open("COM1:");
return 0;
// return 0 to try again next time
// this is located in a while loop in a thread
}
What I get is when I try to write again after a reading time out that the write function always returns zero, zero bytes are written. I've written out the status of the port once but it is always 1, open. Hence the application gets no new data to and from the weaving loom. However, when I close the port and open it again it can occur after one or two times that I am successfully able to write and read again. Any idea what causes this behaviour?
|
|
|
|
 |
|
 |
I found the error, it is specific to a Compaq Armada 1750 laptop. The serial port can have a conflict with the infrared port in Win98 and Win2000 and disabling the infrared port seems to do the trick. When not doing this, it is best to close and reopen the comm port to avoid the application stops as it can't transmit data.
|
|
|
|
 |
|
 |
how can interact with your code with my dialog based application .i mean , if i have to get the motor revolutions per minute in my dialog based application in an edit box ,where should i use your calsses (in my application code)
|
|
|
|
 |
|
|
 |
|
 |
As you didn't give more details I assume that you are talking about MFC dialog based application. I also assume that you have some device from where you can read the revolution per minute of a motor using a RS-232 link.
In the code accompanying this article I include a MFC dialog based application as an example. The given app shows how to read information form a serial barcode reader. It queries the serial port for data at regular interval using a Windows timer. In the main dialog you can fin the following definitions:
CBarCodeReader m_BarCodeReader;
UINT m_Timer;
The other step is adding in the OnInitDialog message handler the following line:
m_Timer = SetTimer(1, 300 , 0);
Add a message handler for the message WM_TIMER and read the serial port in
the OnTimer message handler. In the test app I gave the OnTimer is as follows:
void CTestDlg::OnTimer(UINT nIDEvent)
{
if ( m_BarCodeReader.Read(m_BarCode) > 0 )
{
UpdateData(FALSE); MessageBeep(MB_ICONASTERISK); }
CDialog::OnTimer(nIDEvent);
}
The rest is open your port calling CSerialPort::Open or CBarCodeReader::Open depending on which one you used. You can do it in OnInitDialog message handler or in response to some button action (as in my demo app) or when your app logic requires it.
In your case if your device gives you the speed of the motor as an ASCII characters ended in the characters carriage return and line feed (as in the default configuration for many serial barcode readers) you can the explained code without many modifications. If the speed is given as ASCII but ended in other character or as a fixed length string then you can create (cut and paste) a class similar to CBarCodeReader and change the method Read according to your needs. But if your device give you the values as binary data or any non ASCII protocol then you must use CSerialPort directed and you OnTimer should like this:
void CTestDlg::OnTimer(UINT nIDEvent)
{
BYTE buffer[255]; DWORD read;
while ( (read = m_SerialPort.Read(buffer, sizeof(buffer))) > 0 )
{
}
CDialog::OnTimer(nIDEvent);
}Resuming:
- You must declare in your dialog a variable of type
CSerialPort.
- In the
OnInitDialog handler you must initialize the timer.
- Add a
WM_TIMER message handler to your dialog and in the OnTimer handler read the serial port data.
- You must open the port in the
OnInitDialog handler or any other.
The described method is suitable if you can check the port at determined time intervals. If you need to read the port immediately when some data arrives then you need to use some of the notification mechanism instead of this polling mechanism.
Regards,
Idael
|
|
|
|
 |
|
 |
Hello Idael,
I used your CSerialPort class which works excellent but I found out that although the code I used with SetTimer is quite simple, my program is upto two times slower than the old DOS program it is supposed to replace. Do you have an example of such a notification mechanism or a link to an article giving one? I checked MSDN for overlapped communication and it didn't give me much except for a headache.
|
|
|
|
 |
|
 |
The code I proposed in this article is very trivial and could be not suitable for applications that need immediate response when data arrives (real-time applications, for instance). If your application's constraints allow it you can decrease the timer delay in order to query the port more frequently. Another solution is using a worker thread to query the port continually. Those solutions could interfere in the overall performance of your application but sometimes the performance penalty it is not so big. While this code can be easily adapted to supports Win32 Serial Events is better to use a library that was already designed with it in mind. In the article "Serial communication for Win32 with modem support" you can find a library that could helps you. If your problems persist you can contact me to see if I can help you.
Idael.
|
|
|
|
 |
|
 |
Thank you, I will try to embed it in a thread that continuously polls the port for data. I have taken a look at the TSerial_Event class but have no idea how to imbed that in an SDI application for example, like where would I declare the event and would I also need to place that in a thread, and how to stop polling if a stop button is pressed. Many of the examples for the serial port seem too complicated for me, I have no idea how to implement them.
|
|
|
|
 |
|
 |
In the following code I’ll show how to adapt a MFC SDI application to use a worker thread that pool the serial port continually, when data is arrived it is converted to string (assuming that data read is in ASCII format) and added to a CStringList. The data arrival is signaled using a custom windows message. This method is not so efficient because the working thread is active all the time but can works if this performance penalty isn’t so important for your application.
When u create and SDI MFC application using the MFC app wizards a class named CMainFrame is declared in the file MainFrm.h and method defined in MainFrm.cpp, these files are the files where code must be added.
In MainFrm.h add the following line:
#define WM_DATAREAD (WM_USER + 1)
The previous line defines the custom message that will be used to signal that data was arrived. Within the declaration of CMainFrame add the following:
class CMainFrame : public CFrameWnd
{
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSetFocus(CWnd *pOldWnd);
afx_msg void OnDestroy();
afx_msg LRESULT OnDataRead(WPARAM, LPARAM);
DECLARE_MESSAGE_MAP()
private:
CStringList m_PortDataList; CCriticalSection m_CriticalSection; CWinThread* m_pReadPortThread; CSerialPort m_Port; void StartPooling(); void StopPooling(); static UINT ReadPort(LPVOID pParam); };
In MainFrm.cpp, make the following changes:
Add the ON_MESSAGE(WM_DATAREAD, OnDataRead) entry to the message map as following:
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
ON_WM_SETFOCUS()
ON_WM_DESTROY()
ON_MESSAGE(WM_DATAREAD, OnDataRead)
END_MESSAGE_MAP()
Modify the following methods as follows:
CMainFrame::CMainFrame()
{
m_pReadPortThread = NULL;
}
void CMainFrame::OnDestroy()
{
StopPooling();
CFrameWnd::OnDestroy();
}
An finally add the following code:
LRESULT CMainFrame::OnDataRead(WPARAM, LPARAM)
{
CSingleLock slock(&m_CriticalSection);
slock.Lock();
if ( slock.IsLocked() )
{ }
else
{ }
slock.Unlock();
return 0;
}
UINT CMainFrame::ReadPort(LPVOID pParam)
{
CMainFrame* pMainFrame = (CMainFrame*)pParam;
char buffer[100];
DWORD read;
while( pMainFrame->m_Port.IsOpen() )
{
if ( (read = pMainFrame->m_Port.Read(buffer, sizeof(buffer)-1)) > 0 )
{
buffer[read] = 0; CString str(buffer);
CSingleLock slock(&pMainFrame->m_CriticalSection);
slock.Lock();
if ( slock.IsLocked() )
{ pMainFrame->m_PortDataList.AddTail(str);
}
else
{ }
slock.Unlock();
if ( pMainFrame->m_Port.IsOpen() )
{ ::PostMessage(pMainFrame->GetSafeHwnd(), WM_DATAREAD, 0, 0);
}
}
}
return 0;
}
void CMainFrame::StartPooling()
{
StopPooling();
m_Port.Open(_T("COM1:"), 9600, 8, NOPARITY, ONESTOPBIT, GENERIC_READ);
CWinThread* m_pReadPortThread = AfxBeginThread( ReadPort,
(LPVOID)this,
THREAD_PRIORITY_NORMAL,
0, CREATE_SUSPENDED);
m_pReadPortThread->m_bAutoDelete = FALSE; m_pReadPortThread->ResumeThread();
}
void CMainFrame::StopPooling()
{
m_Port.Close(); if (m_pReadPortThread != NULL)
{
if ( WaitForSingleObject(m_pReadPortThread->m_hThread, 3000) != WAIT_OBJECT_0)
{ m_pReadPortThread->SuspendThread();
}
delete m_pReadPortThread;
m_pReadPortThread = NULL;
}
}
Finally you must call StartPooling/StopPooling in a handler to buttons or any other method. To use Tserial_event class declare a member variable of its type
as following:
class CMainFrame : public CFrameWnd
{
private:
Tserial_event m_Port;
void StartPooling(); void StopPooling(); }
In the cpp file:
void SerialEventManager(uint32 object, uint32 event)
{
char *buffer;
int size;
Tserial_event *com;
com = (Tserial_event *) object;
if (com!=0)
{
switch(event)
{
case SERIAL_DATA_ARRIVAL :
size = com->getDataInSize();
buffer = com->getDataInBuffer();
com->dataHasBeenRead();
break;
}
}
}
CMainFrame::CMainFrame()
{
m_Port.setManager(SerialEventManager);
}
void CMainFrame::OnDestroy()
{
StopPooling();
CFrameWnd::OnDestroy();
}
void CMainFrame::StartPooling()
{
m_Port. connect("COM1", 19200, SERIAL_PARITY_NONE, 8, true);
}
void CMainFrame::StopPooling()
{
m_Port.disconnect();
}
Regards,
Idael
|
|
|
|
 |
|
 |
I know U do not like the registry method. But this func is in a piece of industrial code (look at my e-mail address domain) I am not supposed to give away code like this, but it is not unlike other routines on this site and others. This one works as-is, and it works.
// --------------------------- EnumerateSerialPorts -----------------------------
// PURPOSE: Retrieve hardware configuration from registry instead of letting
// the user guess what ports he has available.
//
LONG EnumerateSerialPorts (char *deviceName, DWORD maxLen, DWORD index)
{
CHAR RegPath[MAX_PATH] = "HARDWARE\\DEVICEMAP\\SERIALCOMM";
HKEY hKey;
HKEY hKeyRoot = HKEY_LOCAL_MACHINE;
DWORD retCode;
CHAR ClassName[MAX_PATH] = ""; // Buffer for class name.
DWORD dwcClassLen = MAX_PATH; // Length of class string.
DWORD dwcSubKeys; // Number of sub keys.
DWORD dwcMaxSubKey; // Longest sub key size.
DWORD dwcMaxClass; // Longest class string.
DWORD dwcValues; // Number of values for this key.
CHAR valueName[MAX_VALUE_NAME] ;
DWORD dwcValueName = MAX_VALUE_NAME;
DWORD dwcMaxValueName; // Longest Value name.
DWORD dwcMaxValueData; // Longest Value data.
DWORD dwcSecDesc; // Security descriptor.
FILETIME ftLastWriteTime; // Last write time.
DWORD dwType;
DWORD retValue;
DWORD cbData;
// Use RegOpenKeyEx() with the new Registry path to get an open handle
// to the child key you want to enumerate.
retCode = RegOpenKeyEx (hKeyRoot,
RegPath,
0,
KEY_ENUMERATE_SUB_KEYS |
KEY_EXECUTE |
KEY_QUERY_VALUE,
&hKey);
if (retCode != ERROR_SUCCESS)
return(FAILED);
// Get Class name, Value count.
RegQueryInfoKey ( hKey, // Key handle.
ClassName, // Buffer for class name.
&dwcClassLen, // Length of class string.
NULL, // Reserved.
&dwcSubKeys, // Number of sub keys.
&dwcMaxSubKey, // Longest sub key size.
&dwcMaxClass, // Longest class string.
&dwcValues, // Number of values for this key.
&dwcMaxValueName, // Longest Value name.
&dwcMaxValueData, // Longest Value data.
&dwcSecDesc, // Security descriptor.
&ftLastWriteTime); // Last write time.
// Enumerate the Key Values
cbData = maxLen ;
dwcValueName = MAX_VALUE_NAME;
valueName[0] = '\0';
retValue = RegEnumValue (hKey, index, valueName,
&dwcValueName,
NULL,
&dwType,
(BYTE *)&deviceName[0],
&cbData);
RegCloseKey (hKey); // Close the key handle.
if(dwType == REG_SZ && retValue == (DWORD)ERROR_SUCCESS)
return(SUCCESS);
else
return(FAILED);
} // EnumerateSerialports
Just call it in a loop with 0 as the indes, until it fails, then U know that was the index after last port. I jsut call it and fill a combo-box untill it fails.
I like your nice OO method of deriving the scanner class from the serial port class, I did the same thing to develop, a "threaded" serial class so it can fire events, on it's own thread, so there is no GUI interrption while reading/writting characters (personally overlapped I/O SUX for complexity).
I may put my class up someday, but it looks like spaghetti, since I derived 4 different classes from it, and then went on to derive more from that untill I got almost as many "children" as the layers in the ISO 7-layer diagrams. But the technique rocks! To get an old copy fire up your browser to http://www.codeguru.com/network/mod_rssim.html.
Go well
Conrad - conradb@adroit.co.za
Always do badly to start off, that way when you get the hang of it suddenly, everyone is surprised.
|
|
|
|
 |
|
 |
BuildCommDCB function is not supported in W/CE so you must parse the string by yourself (to provide an overlapped version of CSerialPort::Open that receives a string as parameters and that parse it could be a good idea, maybe I'll include it in a next version ).
Good luck,
Idael.
|
|
|
|
 |
|
 |
A lot of Com classes do what the Com driver does again.
|
|
|
|
 |