بسم الله الرحمن الرحيم
نبدأ سلسلة برامج نشرح بها اساسيات التعامل مع
serial Port
ملحوظة:-
البرامج منقولة من احد الكتب ( قام برفعه احد الاخوة الاعضاء - طارق فيصل - في قسم السي شارب بمشاركة وعنوانها ربط fingerprint مع Csharp وهذا رابط الكتب من المشاركة )
http://www.mediafire.com/download.php?jdzm1xmi3tz
أولا : نبذة عن الاتصال المتوالي Serial Communication- طريقة ارسال البيانات هي ارسال بت واحد تلو الاخر أي متوالي على عكس Parellel Communication اي الاتصال المتوازي والذي يتم فيه ارسال بايت تلو الاخر
- يكون الارسال على الشكل الاتي
بت ( لمعرفة بداية الارسال ) + الداتا ( يمكن ان تكون 5 بت او 6 بت او 7 بت او 8 بت ) + بت النهاية ( يمكن ان يكون بت واحد او واحد ونص او اثنان بت )
- هناك بت اضافي يمكن ان يضاف الى الرسالة للتحقق من صحة البيانات ( لا يقوم بتصحيح الخطأ وانما لاكتشاف الخطأ فقط ) وهناك 4 طرق لهذه الخاصية ( لن نخوض فيها )
-- الاتصال المتوالي لا يعني بالضرورة وجود كابل متوالي Serial Cable
وانما هو طريقة اتصال بين جهازيين بالصورة التي شرحناها بالاعلى فعلى سبيل المثال جميع الاجهزة التي تستخدم تقنية Bluetooth للاتصال فيما بينها تستخدم طريقة الاتصال المتوالي لذلك لكي نستطيع تجربة تلك البرامج هناك اكثر من طريقة :-- الاتصال بين جهازي كمبيوتر بكابل متوالي Serial Cable
- الاتصال بين مخرجين Serial Ports على نفس الجهاز بكابل متوالي.
- استخدام Bluetooth Adapter بين حهازين .
- استخدام كابل محول بين Serial Port and USB او بمعنى اخر Serial - to - USB cable للربط بين مخرج serial ومخرج USB
بعد هذه المقدمة البسيطة عن الاتصال المتوالي ومتطلبات اختبار برامجنا نأتي الى اول برامجنا .
البرنامج الأول : برنامج محادثة عن طريق الاتصال المتوالي - ننشأ برنامج ويندوز جديد وليكن اسمه SerialChat
- نصمم الواجهة كما بالصورة:-
وهي تحتوي على الاتي :-
- كمبوبوكس ComboBox: لتخزين اسماء Serial Ports المنافذ المتاحة على الكمبيوتر.
اسمها :
ccbCOMPorts
- تكست بوكس TextBox: للنص المراد ارساله
اسمها : txtDataToSend
مع جعلها تقبل تعدد السطور
mutliLine : true
- ريتش تكست بوكس RichTextBox: للنص المستقبل
اسمها : txtDataReceived
مع جعلها تقبل تعدد السطور
جعل الخاصية ScrollBar رأسية
Scrollbar : vertical
- بعض الازرار ووظيفتها ظاهرة من اسمها في الصورة وهم :
btnConnect لبدء الاتصال
btnDisconnect لانهاء الاتصال
btnSend لارسال النص
- اداة عنوان Label : لعرض حالة الاتصال
اسمها : lblMessage
للتعامل مع Serial Port هناك اداة موجودة في صندوق الادوات تسمى SerialPort تجدها في تصنيف Components
يمكنها ان تضيفها الى الفورم او ننشأ كائن منه عن طريق الكود وهو ما سنستخدمه هنا .
نبدأ بإنشاء كائن من كلاس SerialPort
public partial class Form1 : Form
{
private System.IO.Ports.SerialPort serialPort = new System.IO.Ports.SerialPort();
........
........ في حدث التحميل للفورم نجلب اسماء جميع المنافذ المتوالية Serial Ports المتاحة بالكمبيوتر بالشكل الاتي :-
private void Form1_Load(object sender, EventArgs e)
{
.......
.......
.......
string[] portNames = System.IO.Ports.SerialPort.GetPortNames();
for (int i = 0; i <= portNames.Length - 1; i++)
{
cbbCOMPorts.Items.Add(portNames[i]);
}
btnDisconnect.Enabled = false;
}في حدث الضغط على زرار الاتصال ننفذ الكود التالي :-
private void btnConnect_Click(object sender, EventArgs e)
{
//-- لغلق المنفذ اذا كان مفتوحاً
if (serialPort.IsOpen)
{
serialPort.Close();
}
try
{
//-- نحدد بعض خصائص المنفذ لكي يكون جاهز للاتصال
serialPort.PortName = cbbCOMPorts.Text;
serialPort.BaudRate = 9600;
serialPort.Parity = System.IO.Ports.Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = System.IO.Ports.StopBits.One;
serialPort.Encoding = System.Text.Encoding.Unicode;
//-- لفتح المنفذ
serialPort.Open();
//-- تحديث اداة العنوان بالحالة الجديدة للمنفذ وتعطيل زرار الاتصال وتفعيل زرار انهاء الاتصال
lblMessage.Text = cbbCOMPorts.Text + " connected.";
btnConnect.Enabled = false;
btnDisconnect.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}قبل المضي قدما بالبرنامج نشرح الخصائص التي حددناها بالكود وهي :-
- PortName : اسم المنفذ والذي تم اختياره من الكمبوبوكس
- BaudRate : وهي سرعة الاتصال وتقاس بالبت في الثانية b/s
- prity: وهي اسلوب اكتشاف الخطأ الذي ذكرناه في المقدمة والقيمة كما نرى تأتي من enum خاص بالكلاس والقيمة None تعني اننا لن نستخدم اسلوب اكتشاف الخطأ بمعنى انه لن يتم اضافة البت الخاص به .
- DataBits : وهي عدد البت الخاص بالداتا وكما ذكرنا يمكن ان تكون 4 , 5 , 6, 7 , 8
- StopBit : وهي البت التي تحدد نهاية الرسالة المرسلة والتي كما ذكرنا يمكن ان تكون 1 , 1.5 ، 2
- Encoding : تخص نوع تشفير البيانات المرسلة ( الافتراضي هو ASCII ويمكن ان لا نحددها اذا كانت الرسالة باللغة الانجليزية اما اذا كانت الرسالة باللغة العربية فيتعين علينا تحديده بالقيمة الموجودة بالكود Unicode )
في حدث الضغط على زرار انهاء الاتصال ننفذ الكود التالي :-
private void btnDisconnect_Click(object sender, EventArgs e)
{
try
{
//-- لانهاء الاتصال وغلق المنفذ
serialPort.Close();
//-- update the label and enable and disable buttons
lblMessage.Text = cbbCOMPorts.Text + " disconnected.";
btnDisconnect.Enabled = false;
btnConnect.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}في حدث الضغط على زرار ارسال ننفذ الكود التالي :-
private void btnSend_Click(object sender, EventArgs e)
{
try
{
serialPort.Write(txtDataToSend.Text + Environment.NewLine);
txtDataReceived.AppendText(">" + txtDataToSend.Text + Environment.NewLine);
txtDataReceived.ScrollToCaret();
txtDataToSend.Text = String.Empty;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}لارسال الرسالة نستخدم الدالة Write الخاصة بالكائن serialPort والتي تستقبل متغير من النوع نص string وهي الرسالة المراد ارسالها , او مصفوفة من الحروف , او مصفوفة من النوع Byte
والدالة ScrollToCaret الخاصة بـ RichTextBox تقوم بتحريك ScrollBar الى اسفل لكي يظهر الجزء الموجود به النص الجديد
نلاحظ ان عملية الارسال سهلة فقط استخدام الدالة Write , أما لاستقبال البيانات من المنفذ فهناك بعض الامور التي يجب معرفتها
فهناك حدث خاص بالاداة Serial Port وهو DataReceived وهذا الحدث يتم تفعيله عند استقبال المنفذ اي بيانات اتوماتيكيا
لذا اذا كنا استخدمنا الاداة الموجودة بصندوق الادوات ووضعها على الفورم , فعند رؤية الاحداث الخاصة بها سنرى هذا الحدث في صندوق الخصائص ونكتب الكود المراد تنفيذه , أما في حالتنا هذه وقد قمنا بانشاء كائن من الاداة باستخدام الكود فيتعين علينا اضافة EventHandler الخاص بهذا الحدث بالشكل الاتي :-
private void Form1_Load(object sender, EventArgs e)
{
//-- Set the eventhandler for the DataReceived event.
serialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(serialPort_DataReceived);
.......
......
......
أيضا يجب معرفة أنه لا نستطيع قراءة الرسالة المستقبلة وعرضها مباشرة على الاداة الخاصة بعرض الرسائل وذلك لأنه يتم استقبال البيانات من المنفذ على Thread أخر غير الرئيسي الذي تم تنفيذ البرنامج عليه ( Thread : تقسيم فرضي للمعالج لكي يستطيع تنفيذ اكثر من عملية في نفس الوقت ) وهذا يعني اننا لن نستطيع تحديث الادوات الموجودة على الفورم( اي الموجودة على Thread الرئيسي للبرنامج ).
لذلك نستخدم الدالة BeginInvoke والتي تمكننا من التعامل مع Thread اخر غير الرئيسي , لكن هذه الدالة تأخذ متغير من النوع Delegate .
لذلك علينا ان ننشأ Delegate جديد وبه الدالة ننشأ الدالة التي ستقوم بتحديث الادوات على الفورم بالشكل الاتي :-
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
txtDataReceived.BeginInvoke(new myDelegate(updateTextBox));
}
public delegate void myDelegate();
public void updateTextBox()
{
// -------- في حالة استقبال بيانات باللغة العربية ----------------
//-- معرفة عدد البايت الذي تم استقباله --
int bytesToRead = serialPort.BytesToRead;
//-- تعريف مصفوفة من النوع حرف .
char[] ch = new char[bytesToRead];
int bytesRead = 0;
//قراءة البيانات المستقبلة وملآ مصفوفة الحروف بها .
bytesRead = serialPort.Read(ch,0,bytesToRead);
// استخراج النص من مصفوفة الحروف
string str = new string(ch, 0, bytesRead);
//تحديث الاداة على الفورم بالنص المستقبل
txtDataReceived.AppendText(str);
txtDataReceived.ScrollToCaret();
#endregion
// في حالة استقبال بيانات باللغة الانجليزية .
//txtDataReceived.AppendText(serialPort.ReadExisting());
//txtDataReceived.ScrollToCaret();
}نلاحظ اننا في حالة استقبال رسالة باللغة الانجليزية ASCII code نستخدم الدالة ReadExisting الموجودة بالكلاس SerialPort أما في حالة استقبال رسالة باللغة العربية Unicode لا نستطيع استخدام هذه الدالة وبدلا منها نستخدم الدالة Read
بهذا نكون قد انتهينا من أول برامجنا في التعامل مع Serial Communication او الاتصال المتوالي
اتمنى ان يكون الموضوع سهل والشرح والكود مفهوم وغير مبهم .
دمتم سالمين ....
وبالتوفيق للجميع .....
حررت من قبل:
Prof.Mendl في
الجمعة,23/شعبان/1430 هـ,04:53 مساءً