Introduction
Whoever work with standard RS232 components from a .NET environment, and need real, embedded-like RS232 communication, realize in a short time that the component needs to be wrapped, or at least, additionally supported by custom software. I designed this tutorial because I couldn*t find something similar on the web. The code is an excerpt from a huge GPS tracking application, and it proved to work nicely. Just to mention, that there are other methods for RS232 communication such as using hand-shaking protocols, and hardware/software enabled pin control.
Background
I won*t go in to the details of basic RS232 communication, except that it is a point-to-point communication between two hosts, and they could be computers or embedded devices. My point here will be the software implementation part, using C# in a .NET 2.0 environment to be precise, but the principles are adoptable to any other language and IDE. Also, the type of data I*m going to send/read is string, but with little more effort, the code can be adopted to send/receive any type of serializable data. One more restriction, the demo code is adopted to receive a huge block of data and then process it. Another way is to continually append read data to some FIFO buffer, and do an online parsing of whatever data has arrived at the time (search for delimiters inside the arrived data before the reading ends), for continual receiving of data without any pause between two packets.
Methods used
We will need as few as the following four methods to do the job:
void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e);
private void ReadData(object s, EventArgs e);
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e);
private void AddRecieve(object s, EventArgs e);
Using the code
The first thing we need for an RS232 communication is a SerialPort component from the Components tab in the form editor's toolbox. The component itself supports both synchronous and asynchronous (event driven) communication. That means, for reading the port, we can use:
1. Blocking methods
Wait for the hardware to do the job, and then return to the app, so the read operation waits until the reading is finished (a few methods give us different ways of reading the port).
2. Non-blocking methods
We don*t wait in a loop for reading the port, we use interrupts, so when the port has something in an input buffer, the SerialPort component alarms us via delegate methods, such as DataRecieved.
Here, we will use event driven communication, because in my belief, this is the only true RS232 robust communication. So, lets begin. Let*s create some private members for our form, like:
Collapse Copy Code
private System.Timers.Timer timer1;
private StringBuilder recievedB = new StringBuilder();
private string recievedData;
Now, what we first need to do is a basic setup of the component we put on our form, meaning, set the component name (say, serialPort1), baudRate, parity, stopBits, etc. On the Events tab in Properties window, we create the delegate for DataRecieved (actually, the MVS will do that for us when we desire it), and name it serialPort1_DataReceived(). We will see later what we need the timer for. As for the recieveB, we use a StringBuilder class because it has a nice method Append, which doesn*t recreate the string every time we do a concatenation, rather it uses something like linking lists of strings (actually, you don*t have to know how it works). And finally, when all data has arrived, we will need a string to hold the received data needed for further parsing, recievedData. Next comes the coding of the delegate method we created. If we intend to update some controls in the form (as is the usual case), we need to call this.Invoke(some_delegate_method), because of the cross-thread operations. Check MSDN help for help on Invoke. We will create the method like this:
Collapse Copy Code
private void serialPort1_DataReceived(object sender,
System.IO.Ports.SerialDataReceivedEventArgs e)
{
this.Invoke(new EventHandler(AddRecieve));
}
And next, we need to create and code the actual delegate to perform the reading:
Collapse Copy Code
private void AddRecieve(object s, EventArgs e)
{
string st = serialPort1.ReadExisting();
recievedB.Append(st);
timer1.Interval = 1000;
timer1.Start();
}
Let*s comment this code a bit. First, we call ReadExisting, which means reading anything that is in the SerialPorts input buffer. There can be a few bytes, or as many as a few kilobytes of data. Anyway, we read what*s arrived up to now, and Append that to our main holder for the received data 每 the recieveB (the StringBuilder class instance).
Now, the second part of this method. How do we know that the other side of the communication link finished sending data, so we can process it? Think logically for yourselves# For those who figured it out, yes, we know this when for some time (predefined time) there is nothing to read, meaning the event serialPort1_DataRecieved() isn*t firing for some time. This time can vary from 30ms (arguable) up to a minute, it's up to us to decide. In this case, we*ll be using a one second interval so called deadTimePeriod (there is a term for a similar thing, called readTimeout). What do we do with this timer? We crate the timer in the form's constructor, add the onElapsed method for firing up when the time has elapsed, and, I prefer the garbage collector not to destroy my timer. On every firing of the serialPort1_DataReceived() event, we restart the timer1 to the initial interval (in our case 1s), and start it again. Here is the form's construction:
Collapse Copy Code
public Form1()
{
InitializeComponent();
serialPort1.Open();
timer1 = new System.Timers.Timer(1000);
timer1.Elapsed += new System.Timers.ElapsedEventHandler(timer1_Elapsed);
GC.KeepAlive(timer1);
}
The method that will execute on the timer overflow is called timer1_Elapsed. Following that, we will code the method as:
Collapse Copy Code
void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timer1.Stop();
this.Invoke(new EventHandler(ReadData));
}
First, we stop the timer, and second, we do the final receiving of the data. And again, just in case, we call Invoke. The actual method for reading the received data and parsing it looks something like:
Collapse Copy Code
private void ReadData(object s, EventArgs e)
{
recievedData = recievedB.ToString();
int j = recievedB.Length;
if (recievedData.Contains("RMR0" /*some delimiting end*/))
{
labelCard.Text = "Read " + j.ToString() + " bytes...";
// finally we have the data, we need to process it
ProcessData();
}
else
{
DialogResult dr = MessageBox.Show("Bad card data detected!," +
" Read good data?", "Error!",
MessageBoxButtons.YesNo,
MessageBoxIcon.Error);
if (dr == DialogResult.Yes)
{
}
}
}
Of course, the method ProcessData() is open for you to code it. The send method is trivial, on buttonSend_Click, just send whatever you need - in this case, the text from textBoxSend. This could be done as an asynchronous method as well, using standard asynchronous method, invoking in .NET 2.0.
Points of Interest
Finally, I feel I need to explain the whole process again. The communication points are A and B. Both sides open their ports, and side B starts sending bytes over the comm. link. A serialPort1 component on side A is receiving data in almost a byte-by-byte basis, and is filling some sort of a buffer. The point here, was knowing when side B has sent us all data it wished to send in this transmission so side A can start examining the data in whole. Point A does this by using a timer which co
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
串口通信编程pdf(c++、c#程序实例各两个) (214个子文件)
SmsTest.aps 32KB
DlgPreprint.aps 22KB
Toolbar.bmp 1KB
DlgPreprint.bsc 7.89MB
PrjSerails.csproj.GenerateResource.Cache 900B
BusApp.csproj.GenerateResource.Cache 827B
DlgPreprint.clw 1KB
Sms.cpp 14KB
DlgPreprintDlg.cpp 9KB
WrapperView.cpp 8KB
SmsTraffic.cpp 7KB
SmsTest.cpp 7KB
CommonCtrl.cpp 6KB
MainFrm.cpp 5KB
SmsTestView.cpp 4KB
NSerialPortManager.cpp 4KB
MainFrm.cpp 3KB
SettingsDlg.cpp 2KB
DlgPreprint.cpp 2KB
Comm.cpp 2KB
SmsTestDoc.cpp 2KB
ArrayList.cpp 1KB
stdafx.cpp 214B
StdAfx.cpp 213B
StdAfx.cpp 209B
stdafx.cpp 18B
Form1.cs 31KB
Form1.Designer.cs 9KB
mycom.cs 8KB
check.cs 4KB
Form1.cs 4KB
Resources.Designer.cs 3KB
Form2.cs 2KB
Form2.Designer.cs 2KB
AssemblyInfo.cs 2KB
SerialsClass.cs 2KB
CRC16.cs 1KB
AssemblyInfo.cs 1KB
Settings.Designer.cs 1KB
Program.cs 469B
BusApp.csproj 4KB
PrjSerails.csproj 4KB
UpgradeReport.css 3KB
mt.dep 67B
mt.dep 67B
mt.dep 67B
mt.dep 67B
Comm.dll 112KB
SmsTest.dsp 5KB
DlgPreprint.dsp 4KB
DlgPreprint.dsw 545B
SmsTest.dsw 537B
SmsTest.exe 236KB
DlgPreprint.exe 152KB
BusApp.exe 60KB
BusApp.exe 60KB
ArrayList.exe 52KB
ArrayList.exe 52KB
DlgPreprint.exe 32KB
PrjSerails.exe 24KB
PrjSerails.exe 24KB
PrjSerails.vshost.exe 6KB
BusApp.vshost.exe 6KB
UpgradeReport_Plus.gif 71B
UpgradeReport_Minus.gif 69B
CommonCtrl.h 2KB
WrapperView.h 2KB
SmsTestView.h 2KB
Sms.h 2KB
MyPreviewView.h 2KB
MainFrm.h 2KB
DlgPreprintDlg.h 2KB
SmsTraffic.h 1KB
MainFrm.h 1KB
SmsTestDoc.h 1KB
SmsTest.h 1KB
DlgPreprint.h 1KB
SettingsDlg.h 1KB
StdAfx.h 1KB
resource.h 1KB
StdAfx.h 1KB
stafx.h 1KB
NSerialPortManager.h 950B
resource.h 873B
Comm.h 420B
stdafx.h 378B
BuildLog.htm 15KB
BuildLog.htm 9KB
BuildLog.htm 8KB
BuildLog.htm 7KB
DlgPreprint.ico 1KB
SmsTest.ico 1KB
SmsTestDoc.ico 1KB
App.ico 1KB
settings.ico 766B
vc80.idb 899KB
vc80.idb 787KB
vc80.idb 723KB
vc60.idb 225KB
vc80.idb 179KB
共 214 条
- 1
- 2
- 3
yangxianyy
- 粉丝: 11
- 资源: 10
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
- 1
- 2
前往页