一、 新手上路,一般幾種方法來學習VS2010的C#編程:
1.查閱各種書籍和技術文檔,傳統而耗時;
2.借助視頻教程快速上手,省事有效卻無法掌握一些小細節,寫起程序來,各種調試不通過,還是浪費時間;
3.直接采用網絡大神的程序,在運行成功的前提下,再仔細消化各種精髓,方法雖然高效,但也是建立在作者編寫文檔友好的情況下。
對於以上的第一種適合那種不着急項目進度,只管自己開心滿足自己興趣的新手,第二種適合那種需要趕進度、不需要太注意小細節的項目,第三種屬於技術渣,為了像我這種技術渣的新手們上路更輕松,特編寫以下關於USB轉串口的串口通信程序開發文檔。
二、新手借用大神程序常見問題:不知道程序里的一些東西怎么來的
這一個最致命的問題在各大知名技術分享網站甚至是博客園都表現得非常明顯!
評:比如C#中界面如何設計、界面調用的控件屬性如何更改?隨便一個程序,摘自網絡不經修正、未經親自調試,就把簡陋的對新手上路極不友好的垃圾文檔發表出來,浪費新手大量寶貴時間,這個慘痛教訓我親身經歷,未免新手再受關於《串口通信-RS232》相關垃圾文檔的荼毒,現在我將我實現項目的全部過程及遇到的問題敘述如下,其中各類專業性的參數,可以百度查閱,關鍵字可以選擇“串行通信原理、RS232”等。
此程序的界面設計步驟為:
(1)新建項目
在VisualStudio2010菜單欄點擊“文件”>“新建項目”,創建VisualC#下的Windows
(2)選用控件
在窗體上添加三個“GroupBox”控件,分別將窗體分為“串口設置”、“數據接收”以及“數據發送”三部分。
添加若干“Label”和“ComboBox”分別用於串口號、波特率、停止位、奇偶校驗、數據位等的設置;
添加兩個“RodioButton”用於字符顯示和HEX顯示(HEX=16進制)的選擇;
添加若干“Button”用於串口檢測、打開串口、清空數據以及發送數據等功能按鈕;
最后分別在數據接收欄和數據發送欄中各添加一個“TextBox”控件,用於數據的收發。
對各個布置好的控件進行命名,方便編程。(按下圖紅色字體進行命名)
此外,還需更改以下屬性:更改“字符顯示”的RodioButton控件屬性中的Checked為true,使在打開程序后默認選擇“字符顯示”。
更改數據接收欄中的TextBox控件屬性中的ReadOnly為true,使這個空間只能顯示接收到的數據,不能被編輯。
更改窗體Form屬性中的AcceptButton為btnSend(發送數據按鈕的名稱),使在窗體下按下回車鍵關聯“發送數據”按鈕。
3.點擊程序需要按鈕生成事件
注:同一個窗體也可以設置多個事件,設置方法為選中下圖“閃電”標志,選擇事件(如Load/Paint等)
三、附上完整程序
此程序有極其完整的注釋,對有一定C#程序基礎的閱讀者不會有困難了。
按照步驟完成屬性更改后,需要將USB轉串口線的RX、TX用杜邦線連接(或者直接焊在一塊),形成短接,這樣僅使用一個串口,就可以實現自發自收的效果(相當於本機與本機進行通信),至此程序調試成功。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
SerialPort sp = null;//聲明一個串口類
bool isOpen = false;//打開串口標志位
bool isSetProperty = false;//屬性設置標志位
bool isHex = false;//十六進制顯示標志位
public Form1()
{
InitializeComponent();
}
/// <summary>
/// 串口參數設置
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Load(object sender, EventArgs e)
{
this.MaximumSize = this.Size;
this.MinimumSize = this.Size;
this.MaximizeBox = false;
for (int i = 0; i < 10; i++)//最大支持到串口10,可根據自己需求增加
{
cbxCOMPort.Items.Add("COM" + (i + 1).ToString());
}
cbxCOMPort.SelectedIndex = 0;
//列出常用的波特率
cbxBaudRate.Items.Add("1200");
cbxBaudRate.Items.Add("2400");
cbxBaudRate.Items.Add("4800");
cbxBaudRate.Items.Add("9600");
cbxBaudRate.Items.Add("19200");
cbxBaudRate.Items.Add("38400");
cbxBaudRate.Items.Add("43000");
cbxBaudRate.Items.Add("56000");
cbxBaudRate.Items.Add("57600");
cbxBaudRate.Items.Add("115200");
cbxBaudRate.SelectedIndex = 5;
//列出停止位
cbxStopBits.Items.Add("0");
cbxStopBits.Items.Add("1");
cbxStopBits.Items.Add("1.5");
cbxStopBits.Items.Add("2");
cbxStopBits.SelectedIndex = 1;
//列出數據位
cbxDataBits.Items.Add("8");
cbxDataBits.Items.Add("7");
cbxDataBits.Items.Add("6");
cbxDataBits.Items.Add("5");
cbxDataBits.SelectedIndex = 0;
//列出奇偶校驗位
cbxParity.Items.Add("無");
cbxParity.Items.Add("奇校驗");
cbxParity.Items.Add("偶校驗");
cbxParity.SelectedIndex = 0;
//默認為Char顯示
rbnChar.Checked = true;
}
/// <summary>
/// 檢測哪些串口可用
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCheckCOM_Click(object sender, EventArgs e)
{
bool comExistence = false;//有可用串口標志位
cbxCOMPort.Items.Clear();//清除當前串口號中的所有串口名稱
for (int i = 0; i < 10; i++)
{
try
{
SerialPort sp = new SerialPort("COM" + (i + 1).ToString());
sp.Open();
sp.Close();
cbxCOMPort.Items.Add("COM" + (i + 1).ToString());
comExistence = true;
}
catch (Exception)
{
continue;
}
}
if (comExistence)
{
cbxCOMPort.SelectedIndex = 0;//使ListBox顯示第1個添加的索引
}
else
{
MessageBox.Show("沒有找到可用串口!", "錯誤提示");
}
}
/// <summary>
/// 串口檢查按鈕:檢查串口是否設置
/// </summary>
private bool CheckPortSetting()
{
if (cbxCOMPort.Text.Trim() == "")
return false;
if (cbxBaudRate.Text.Trim() == "")
return false;
if (cbxDataBits.Text.Trim() == "")
return false;
if (cbxParity.Text.Trim() == "")
return false;
if (cbxStopBits.Text.Trim() == "")
return false;
return true;
}
/// <summary>
/// 檢查是否發送數據
/// </summary>
/// <returns></returns>
private bool CheckSendData()
{
if (tbxSendData.Text.Trim() == "")
return false;
return true;
}
/// <summary>
/// 設置串口的屬性:停止位、數據位、奇偶校驗位
/// </summary>
private void SetPortProperty()
{
sp = new SerialPort();
sp.PortName = cbxCOMPort.Text.Trim();//設置串口名
sp.BaudRate = Convert.ToInt32(cbxBaudRate.Text.Trim());//設置串口的波特率
float f = Convert.ToSingle(cbxStopBits.Text.Trim());//設置停止位
if (f == 0)
{
sp.StopBits = StopBits.None;
}
else if (f == 1.5)
{
sp.StopBits = StopBits.OnePointFive;
}
else if (f == 1)
{
sp.StopBits = StopBits.One;
}
else if (f == 2)
{
sp.StopBits = StopBits.Two;
}
else
{
sp.StopBits = StopBits.One;
}
sp.DataBits = Convert.ToInt16(cbxDataBits.Text.Trim());//設置數據位
string s = cbxParity.Text.Trim();//設置奇偶校驗位
if (s.CompareTo("無") == 0)
{
sp.Parity = Parity.None;
}
else if (s.CompareTo("奇校驗") == 0)
{
sp.Parity = Parity.Odd;
}
else if (s.CompareTo("偶校驗") == 0)
{
sp.Parity = Parity.Even;
}
else
{
sp.Parity = Parity.None;
}
sp.ReadTimeout = -1;//設置超時讀取時間
sp.RtsEnable = true;
//定義DataReceived事件,當串口收到數據后觸發事件
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
if (rbnHex.Checked)
{
isHex = true;
}
else
{
isHex = false;
}
}
/// <summary>
/// 發送串口數據
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnSend_Click(object sender, EventArgs e)
{
if (isOpen)//寫串口數據
{
try
{
sp.WriteLine(tbxSendData.Text);
}
catch (Exception)
{
MessageBox.Show("發送數據時發生錯誤!", "錯誤提示");
return;
}
}
else
{
MessageBox.Show("串口未打開!", "錯誤提示");
return;
}
if (!CheckSendData())//檢測要發送的數據
{
MessageBox.Show("請輸入要發送的數據!", "錯誤提示");
return;
}
}
/// <summary>
/// 串口狀態檢測:是否設置、是否占用
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnOpenCom_Click(object sender, EventArgs e)
{
if (isOpen == false)
{
if (!CheckPortSetting())//檢測串口設置
{
MessageBox.Show("串口未設置!", "錯誤提示");
return;
}
if (!isSetProperty)//串口未設置則設置串口
{
SetPortProperty();
isSetProperty = true;
}
try//打開串口
{
sp.Open();
isOpen = true;
btnOpenCom.Text = "關閉串口";
//串口打開后則相關的串口設置按鈕便不可再用
cbxCOMPort.Enabled = false;
cbxBaudRate.Enabled = false;
cbxDataBits.Enabled = false;
cbxParity.Enabled = false;
cbxStopBits.Enabled = false;
rbnChar.Enabled = false;
rbnHex.Enabled = false;
}
catch (Exception)
{
//打開串口失敗后,相應標志位取消
isSetProperty = false;
isOpen = false;
MessageBox.Show("串口無效或已被占用!", "錯誤提示");
}
}
else
{
try//打開串口
{
sp.Close();
isOpen = false;
isSetProperty = false;
btnOpenCom.Text = "打開串口";
//關閉串口后,串口設置選項便可以繼續使用
cbxCOMPort.Enabled = true;
cbxBaudRate.Enabled = true;
cbxDataBits.Enabled = true;
cbxParity.Enabled = true;
cbxStopBits.Enabled = true;
rbnChar.Enabled = true;
rbnHex.Enabled = true;
}
catch (Exception)
{
lblStatus.Text = "關閉串口時發生錯誤";
}
}
}
private void sp_DataReceived(object sender,SerialDataReceivedEventArgs e)
{
System.Threading.Thread.Sleep(100);//延時100ms等待接收完數據
// this.Invoke就是跨線程訪問ui的方法
this.Invoke((EventHandler)(delegate
{
if(isHex==false)
{
tbxRecvData.Text+=sp.ReadLine();
}
else
{
Byte[] ReceivedData=new Byte[sp.BytesToRead];
sp.Read(ReceivedData,0,ReceivedData.Length);
String RecvDataText=null;
for(int i=0;i<ReceivedData.Length-1;i++)
{
RecvDataText+=("0x"+ReceivedData[i].ToString("X2")+"");
}
tbxRecvData.Text+=RecvDataText;
}
sp.DiscardInBuffer();//丟棄接收緩沖區數據
}));
}
private void btnCleanData_Click(object sender,EventArgs e)
{
tbxRecvData.Text="";
tbxSendData.Text="";
}
}
}
四、調試結果