[原创]发布《串口调试助手V1.0》程序+C#源码
在 OurAVR 论坛潜水已经有一年多了,在这里下载了不少好的资料,今天把我的第一个 C# 程序和源代码共享出来,供大家交流学习,请高手多多指教。本来想用 VB 的, N 年前学过一点点,现在忘得差不多了。近年来一直在做单片机编程,对 C 比较熟悉,所以决定用 C# ,一周下来,弄出了这个东东。
个人认为 C#=VB+C。(VB 的界面,C 的语法)。比较适合搞单片机的人学习上位机编程,容易上手。说得不对的地方,请多包涵。
串口调试助手V1.0
共享软件
软件描述:
1、自动检测系统串口数量,如有USB转串口设备插入,即插即用,自动添加到下拉列表框。
2、修改端口设置后自动打开串口。
3、可以发送字符、十六进制数据。
4、字符和十六进制数据可以定时循环发送。
5、支持自定义帧格式,自动加入校验。可选和校验和异或校验。
6、有十进制<-->十六进制互转功能,方便参数计算。
7、接收分别以字符和十六进制显示,完美支持中文显示和回车换行。可以自动滚屏,自动清屏。
8、单击接收到的十六进制数据,可以自动解码成十进制有符号和无符号数据,方便调试通讯协议。
开发说明:
本软件是我为了方便自己产品开发,利用业余时间而编写的。这也是我初学 VS2005 一周以来,设计的第一款 Windows 应用程序。
针对自己定义的通讯协议,增加了一些实用的解码功能,方便自己调试程序。
这是免费软件,可以随意复制。在使用过程中有任何意见或建议,可以通过如下方式与我联系:
QQ: 357641612
E-Mail:Delong_z@163.com
本软件采用 Microsoft Visual Studio 2005 开发,需要安装 Microsoft .Net Framework 2.0 支持才能工作。
重庆阿尔舍电子技术有限公司
钟 慰
2009年4月13日
http://cache.amobbs.com/bbs_upload782111/files_14/ourdev_436157.JPG
程序主界面 (原文件名:SerialComm.JPG)
安装程序ourdev_436158.rar(文件大小:455K) (原文件名:SerialCommSetup.rar)
C#2005源代码ourdev_436169.rar(文件大小:239K) (原文件名:SerialComm.rar)
关键源码在6楼,除了解决串口线程死锁相关部分外,其它的都比较简单。解决死锁问题主要参考网上的一篇文章来改写的。只有在不停接收数据时关闭串口时,才有可能死锁,经过改进,这种几率已经比较小了。万一死锁了,用鼠标右键在程序任务栏右击程序几下就可以恢复。 高手啊 顶…… 要装控件吧 谢谢 顶! 不得不顶呀! 源码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
namespace SerialComm
{
public partial class Form1 : Form
{
//===================================================
//申明全局变量。
public int CmdIdx = 0; //命令发送指针初始为0。
bool IsReceving = false; //接收数据标志。
bool DoingStr = false; //处理字符串标志。
bool DoingHex = false; //处理十六进制标志。
//===================================================
public Form1()
{
InitializeComponent();
}
private void IntToHex()
{
try
{
int Int = int.Parse(tbDec.Text);
string TempStr = Convert.ToString(Int, 16);
while(TempStr.Length < 8 )
TempStr = '0' + TempStr;
tbHex.Text = TempStr.ToUpper();
tbDec.SelectAll();
}
catch (Exception Err)
{
tbDec.SelectAll();
MessageBox.Show(Err.Message, "串口调试助手");
}
}
private void HexToInt()
{
try
{
int Int = Convert.ToInt32(tbHex.Text,16);
tbDec.Text = Int.ToString();
tbHex.SelectAll();
}
catch (Exception Err)
{
tbHex.SelectAll();
MessageBox.Show(Err.Message, "串口调试助手");
}
}
private void CmdClick(int idx)
{ //发送命令。
try
{
//自动打开端口。
if (!sComm.IsOpen)
btOpen_Click(null, null);
string TempStr = string.Empty;
switch(idx)
{
case 1:
TempStr = tbCmd1.Text;
break;
case 2:
TempStr = tbCmd2.Text;
break;
case 3:
TempStr = tbCmd3.Text;
break;
case 4:
TempStr = tbCmd4.Text;
break;
case 5:
TempStr = tbCmd5.Text;
break;
default:
return;
}
TempStr = DelSpace(TempStr);
if (cbDefFrm.Checked) //自动添加帧头帧尾和校验
{
TempStr=DelSpace(tbStart.Text)+TempStr; //加入头。
//转换为字节数组。
int Len=TempStr.Length; //待校验的字符串长度。
byte[] VerBin = new byte;
int j=0;
for(int i=0;i<Len;i+=2,j++)
{
VerBin = Convert.ToByte(TempStr.Substring(i, 2), 16);
}
//计算校验字节。
byte VerByte=0;
if (rdXor.Checked)
{
for (int i = 0; i < VerBin.Length; i++)
VerByte ^= VerBin; //异或校验。
}
else if (rdAdd.Checked)
{
for (int i = 0; i < VerBin.Length; i++)
VerByte += VerBin; //和校验。
}
//校验字节转为HEX字符串。
string VerStr = Convert.ToString(VerByte, 16);
//合成一帧。
TempStr = TempStr + DelSpace(VerStr) + DelSpace(tbEnd.Text);
}
SendAsHex(TempStr);
}
catch (Exception err)
{
TimeHex.Stop();
TimeHex.Enabled = false;
MessageBox.Show(err.Message, "串口调试助手");
cbTimeHex.Checked = false;
}
}
private void ClrEncode()
{
lbHexData.Text = string.Empty;
tbByte1.Text = string.Empty;
tbByte2.Text = string.Empty;
tbByte3.Text = string.Empty;
tbByte4.Text = string.Empty;
tbUInt16L.Text = string.Empty;
tbUInt16R.Text = string.Empty;
tbUInt32.Text = string.Empty;
tbSByte1.Text = string.Empty;
tbSByte2.Text = string.Empty;
tbSByte3.Text = string.Empty;
tbSByte4.Text = string.Empty;
tbInt16L.Text = string.Empty;
tbInt16R.Text = string.Empty;
tbInt32.Text = string.Empty;
}
private void SendAsHex(string str)
{
int Len = str.Length;
//组包发送。
byte[] send = new byte;
int j = 0;
for (int i = 0; i < Len; i = i + 2, j++)
send = Convert.ToByte(str.Substring(i, 2), 16);
sComm.Write(send, 0, send.Length);
}
//清除空格。
private string DelSpace(string str)
{
string TempStr = string.Empty;
int Len = str.Length;
for (int i = 0; i < Len; i++)
{
if (str != ' ')
TempStr += str;
}
//Hex 位数检查。
Len = TempStr.Length;
if (Len % 2 != 0)
TempStr = '0' + TempStr;
return TempStr;
}
//重新打开端口。
private void ReOpenPort()
{
try
{
btClose_Click(null,null);
//重新打开通讯端口。
if (!sComm.IsOpen)
btOpen_Click(null, null);
}
catch (Exception Err)
{
MessageBox.Show(Err.Message, "串口调试助手");
}
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
foreach (string com in System.IO.Ports.SerialPort.GetPortNames())//自动获取串行口名称
this.cmPort.Items.Add(com);
cmPort.SelectedIndex = 0;
}
catch
{
MessageBox.Show("找不到通讯端口!", "串口调试助手");
}
}
private void OpenPort()
{
//***避免串口死锁***
sComm.WriteTimeout = 1000;//写超时,如果底层串口驱动效率问题,能有效的避免死锁。
sComm.ReadTimeout = 1000; //读超时,同上。
sComm.NewLine = "\r\n"; //回车换行。
sComm.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.sComm_DataReceived); //注册事件。
//***避免串口死锁***
sComm.PortName = cmPort.Text;
sComm.BaudRate = int.Parse(cmBaudRate.Text);
sComm.DataBits = int.Parse(cmDataBit.Text);
sComm.Parity = (Parity)Enum.Parse(typeof(Parity), cmParity.Text);
sComm.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cmStopBit.Text);
sComm.Open();
}
private void ClosePort()
{
//安全关闭当前串口。
//***避免串口死锁***
sComm.DataReceived -= this.sComm_DataReceived; //注销串口中断接收事件,避免下次再执行进来,造成死锁。
while(IsReceving)
Application.DoEvents(); //处理串口接收事件及其它系统消息。
sComm.Close(); //现在没有死锁,可以关闭串口。
//***避免串口死锁***
}
private void StopAutoSend()
{
//停止自动发送字符串。
TimeStr.Stop();
TimeStr.Enabled = false;
tbTimeStr.Enabled = true;
cbTimeStr.Checked = false;
//停止自动发送命令。
TimeHex.Stop();
TimeHex.Enabled = false;
tbTimeHex.Enabled = true;
cbTimeHex.Checked = false;
}
//===================================================
private void btOpen_Click(object sender, EventArgs e)
{
try
{
OpenPort(); //安全打开串口。
if (sComm.IsOpen)
{
btClose.Enabled = true;
btOpen.Enabled = false;
lbComStat.Text = "已打开 " + Convert.ToString(sComm.PortName) + ' ' + Convert.ToString(sComm.BaudRate) + ' ' + Convert.ToString(sComm.DataBits) + ' ' + Convert.ToString(sComm.Parity) + ' ' + Convert.ToString(sComm.StopBits);
tbSendStr.Focus();
}
}
catch (Exception er)
{
StopAutoSend(); //停止自动发送。
ClosePort(); //安全关闭当前串口。
MessageBox.Show("端口打开失败!" + er.Message, "串口调试助手");
lbComStat.Text = "已关闭";
}
}
private void btSend_Click(object sender, EventArgs e)
{
//自动打开端口。
if (!sComm.IsOpen)
btOpen_Click(null, null);
//发送文本。
try
{
string txt = tbSendStr.Text;
Byte[] EncodeByte = new byte;
EncodeByte = Encoding.GetEncoding("GB2312").GetBytes(txt);
int Len = EncodeByte.Length;
sComm.Write(EncodeByte, 0, Len);
}
catch (Exception err)
{
MessageBox.Show(err.Message, "串口调试助手");
}
}
private void btClrSend_Click(object sender, EventArgs e)
{
tbSendStr.Text = string.Empty;
}
private void cmPort_MouseDown(object sender, MouseEventArgs e)
{
try
{
cmPort.Items.Clear();
foreach (string com in System.IO.Ports.SerialPort.GetPortNames())//自动获取串行口名称
this.cmPort.Items.Add(com);
}
catch
{
MessageBox.Show("找不到通讯端口!", "串口调试助手");
}
}
private void sComm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
IsReceving = true;//***正在接收状态指示。
//读入收到的数据。
int Len = sComm.BytesToRead;
if (Len < 1)
{
IsReceving = false;//***接收完成状态指示。
return;
}
byte[] data = new byte;
sComm.Read(data, 0, Len);
//字符串处理。
string Str = Encoding.GetEncoding("GB2312").GetString(data);
//数据转十六进制字符串。
string Hex = string.Empty;
for (int i = 0; i < data.Length; i++)
{
string tempstr = Convert.ToString(data, 16);
if (tempstr.Length < 2)
tempstr = '0' + tempstr;
Hex += tempstr + ' ';
}
Hex = Hex.ToUpper();
//使用委托跨线程读取数据。
rtbRecStr.Invoke(new EventHandler(delegate
{
DoingStr = true; //***正在处理字符串。
rtbRecStr.AppendText(Str);
if (cbAutoClr.Checked && rtbRecStr.Text.Length > 10000)
rtbRecStr.Text = string.Empty;
rtbRecStr.ScrollToCaret(); //将控件的内容滚动到当前位置。
DoingStr = false;
}
));
rtbRecHex.Invoke(new EventHandler(delegate
{
DoingHex = true; //***正在处理十六进制数据。
rtbRecHex.AppendText(Hex);
if (cbAutoClr.Checked && rtbRecHex.Text.Length > 10000)
rtbRecHex.Text = string.Empty;
rtbRecHex.ScrollToCaret(); //将控件的内容滚动到当前位置。
DoingHex = false;
}
));
while(DoingStr || DoingHex)
Application.DoEvents(); //处理串口接收事件及其它系统消息。
IsReceving =false;//***接收完成状态指示。
}
catch (Exception Err)
{
MessageBox.Show(Err.Message, "串口调试助手");
}
}
private void btClrRec_Click(object sender, EventArgs e)
{
rtbRecStr.Text = string.Empty;
rtbRecHex.Text = string.Empty;
ClrEncode();
}
private void rtbRecHex_MouseClick(object sender, MouseEventArgs e)
{
try
{
int idx = rtbRecHex.SelectionStart / 3;
idx *= 3;
if (rtbRecHex.Text.Length >= idx + 4 * 3)
{
rtbRecHex.Select(idx, 4 * 3);
string SubStr = rtbRecHex.Text.Substring(idx, 4 * 3);
lbHexData.Text = SubStr;
string[] TempStr = SubStr.Split(' ');
string[] Frm=new string;
if(rdBig.Checked)
{ //直接拷贝。
Array.Copy(TempStr, Frm, Frm.Length);
}
else
{ //前后交换。
Frm = TempStr;
Frm = TempStr;
Frm = TempStr;
Frm = TempStr;
}
//数据解码。
tbByte1.Text = Convert.ToString(Convert.ToByte(Frm, 16), 10);
tbByte2.Text = Convert.ToString(Convert.ToByte(Frm, 16), 10);
tbByte3.Text = Convert.ToString(Convert.ToByte(Frm, 16), 10);
tbByte4.Text = Convert.ToString(Convert.ToByte(Frm, 16), 10);
tbUInt16L.Text = Convert.ToString(Convert.ToUInt16(Frm + Frm, 16), 10);
tbUInt16R.Text = Convert.ToString(Convert.ToUInt16(Frm + Frm, 16), 10);
tbUInt32.Text = Convert.ToString(Convert.ToUInt32(Frm + Frm + Frm + Frm, 16), 10);
tbSByte1.Text = Convert.ToString(Convert.ToSByte(Frm, 16), 10);
tbSByte2.Text = Convert.ToString(Convert.ToSByte(Frm, 16), 10);
tbSByte3.Text = Convert.ToString(Convert.ToSByte(Frm, 16), 10);
tbSByte4.Text = Convert.ToString(Convert.ToSByte(Frm, 16), 10);
tbInt16L.Text = Convert.ToString(Convert.ToInt16(Frm + Frm, 16), 10);
tbInt16R.Text = Convert.ToString(Convert.ToInt16(Frm + Frm, 16), 10);
tbInt32.Text = Convert.ToString(Convert.ToInt32(Frm + Frm + Frm + Frm, 16), 10);
}
else
{
ClrEncode();
}
}
catch (Exception Err)
{
MessageBox.Show(Err.Message, "串口调试助手");
}
}
private void rdBig_CheckedChanged(object sender, EventArgs e)
{
rtbRecHex_MouseClick(null, null); //重新刷新数据解码。
}
private void cbDefFrm_CheckedChanged(object sender, EventArgs e)
{
if (cbDefFrm.Checked)
{
gpDefFrm.Enabled = true;
}
else
{
gpDefFrm.Enabled = false;
}
}
private void cbTimeHex_CheckedChanged(object sender, EventArgs e)
{
try
{
if (cbTimeHex.Checked)
{
//禁止Str自动发送。
cbTimeStr.Checked = false;
int t=int.Parse(tbTimeHex.Text);
if (t < 5)
{
t = 5;
tbTimeHex.Text = Convert.ToString(t,10);
}
//起动Hex自动发送。
tbTimeHex.Enabled = false;
TimeHex.Enabled = true;
TimeHex.Interval = t;
TimeHex.Start();
}
else
{
TimeHex.Stop();
TimeHex.Enabled = false;
tbTimeHex.Enabled = true;
}
}
catch (Exception Err)
{
MessageBox.Show("定时值不正确!" + Err.Message, "串口调试助手");
}
}
private void cbTimeStr_CheckedChanged(object sender, EventArgs e)
{
try
{
if (cbTimeStr.Checked)
{
//禁止Hex自动发送。
cbTimeHex.Checked = false;
int t = int.Parse(tbTimeStr.Text);
if (t < 5)
{
t = 5;
tbTimeStr.Text = Convert.ToString(t,10);
}
//启动Str自动发送。
tbTimeStr.Enabled = false;
TimeStr.Enabled = true;
TimeStr.Interval = t;
TimeStr.Start();
}
else
{
TimeStr.Stop();
TimeStr.Enabled = false;
tbTimeStr.Enabled = true;
}
}
catch (Exception Err)
{
MessageBox.Show("定时值不正确!" + Err.Message, "串口调试助手");
}
}
private void btCmd1_Click(object sender, EventArgs e)
{
CmdClick(1);
}
private void btCmd2_Click(object sender, EventArgs e)
{
CmdClick(2);
}
private void btCmd3_Click(object sender, EventArgs e)
{
CmdClick(3);
}
private void btCmd4_Click(object sender, EventArgs e)
{
CmdClick(4);
}
private void btCmd5_Click(object sender, EventArgs e)
{
CmdClick(5);
}
private void cmPort_SelectedIndexChanged(object sender, EventArgs e)
{
ReOpenPort();
}
private void cmBaudRate_SelectedIndexChanged(object sender, EventArgs e)
{
ReOpenPort();
}
private void cmDataBit_SelectedIndexChanged(object sender, EventArgs e)
{
ReOpenPort();
}
private void cmParity_SelectedIndexChanged(object sender, EventArgs e)
{
ReOpenPort();
}
private void cmStopBit_SelectedIndexChanged(object sender, EventArgs e)
{
ReOpenPort();
}
private void TimeHex_Tick(object sender, EventArgs e)
{
try
{
int[] Len ={ tbCmd1.Text.Length,tbCmd2.Text.Length,tbCmd3.Text.Length,tbCmd4.Text.Length,tbCmd5.Text.Length};
int j = 0;
int OldIdx=CmdIdx;
for (int i = OldIdx; i<OldIdx+5; i++)
{
CmdIdx %= 5;
j = i % 5;
if (CmdIdx == j)
{
CmdIdx++;
if (Len > 0)
{
CmdClick(CmdIdx);
return;
}
}
}
}
catch (Exception Err)
{
MessageBox.Show("定时发送错误!" + Err.Message, "串口调试助手");
cbTimeHex.Checked = false;
}
}
private void TimeStr_Tick(object sender, EventArgs e)
{
try
{
btSend_Click(null, null);
}
catch (Exception Err)
{
MessageBox.Show("定时发送错误!" + Err.Message, "串口调试助手");
cbTimeStr.Checked = false;
}
}
private void tbDec_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '\r')//回车键
IntToHex(); //转换为Hex。
}
private void tbDec_Leave(object sender, EventArgs e)
{
IntToHex();
}
private void tbHex_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '\r')//回车键
{
while (tbHex.Text.Length < 8)
tbHex.Text = '0' + tbHex.Text;
HexToInt(); //转换为Dec。
}
}
private void tbHex_Leave(object sender, EventArgs e)
{
while (tbHex.Text.Length < 8)
tbHex.Text = '0' + tbHex.Text;
HexToInt(); //转换为Dec。
}
private void btClose_Click(object sender, EventArgs e)
{
StopAutoSend(); //停止自动发送。
ClosePort(); //安全关闭串口。
if (!sComm.IsOpen)
{
btOpen.Enabled = true;
btClose.Enabled = false;
lbComStat.Text = "已关闭";
}
}
private void btQuit_Click(object sender, EventArgs e)
{
btClose_Click(null, null);
this.Close();
}
//===================================================
}
} 这个有用 收藏了 mark 需要 Microsoft .Net Framework 2.0 库支持,本来想把库也加到安装程序里的,但有点大了,不方便上传,安装时它会自动从微软官方网站上下载组件。如果你已经安装过 .Net 的库,那安装程序会跳过下载安装的步骤,几秒钟就安装完了。 擦擦! 需要 Microsoft .Net Framework 2.0 库支持,能不能换成vc6写的? 我自己也写过,不过比较简单,没楼主的功能多! 其实用脚本是一样一样一样一样的 谢谢! mark//////// 不错,不错!感觉好极了! mark 顶 回11楼,以前学VC,还专门下载了视频教程来看,但都是看得云里雾里的。MFC搞得人头晕。
VC功能确实很不错,但不好学,所以我还是选择简单易懂的语言来编写,更何况 C# 的功能也不弱,也还简单。几天就学会了。 上面的那个sComm 在哪里定义的啊? 回复【楼主位】Delong_z
-----------------------------------------------------------------------
好东西,用C# vs2005在windows下做界面和串口,的确非常方便 mark mark bj 发送中文乱码如何解决 纯顶了! mark,学习了。 mark 楼主强! mark mark 学习下!!! 同意 mark 对了,有朋友反映不能编译,只要在工程属性的 签名 一栏里把 “为 ClickOnce 清单签名”取消钩选即可。 标记下 mark 用下C#,谢 其实我喜欢C++的 MARK 顶 mark mark 为什么没有发送文件项呢? mark 这个要顶,必须的。 mark 学习了,我之前用C#写了一个类似的,尽管已经释放串口变量,但是在关闭窗体的时候还是假死,一直没有解决 标记一下 真心好东西,保留起来学习 mark 好东西!
谢谢! 不错不错谢谢楼主 有谁能放些C#的学习资料就好了。。这方面比较少! mark{:smile:}{:smile:} 高手,不得不顶 谢谢!牛人!佩服!
页:
[1]