如何使用SerialPort类用Modena传输文件??

chrisziling 2009-03-18 04:08:53
有电脑A、B,均不能联网但有Modem和电话线!

需要实现功能如下:
A拨号B,应答后A将123.txt传给B,接收完成后B将456.txt传给A,传输结束,程序自动做其他更新操作!

在网上搜了,一下操作modem传输数据可以使用.net的SerialPort类,但是具体如何实现全然不知,希望高手或前辈给予指点,如何使用modem传输文件!

拜谢了!
...全文
262 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
zzxap 2009-03-26
  • 打赏
  • 举报
回复
[code=C#]
学习C Sharp主要的目的就是为了给项目做一个PC端的界面,并且通过串口和所用的CC2430之间通信。

C#里面的串口类非常好用,这里就不详细说了。。

下面是接收端的事件

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
FileStream Save = new FileStream(@"E:/received.dat", FileMode.Append, FileAccess.Write);
Byte[] array = new byte[1024];
int count = serialPort1.BytesToRead;
serialPort1.Read(array, 0, count);
Save.Write(array, 0, count);
Save.Close();
}

这里所有的操作都是同步的,异步的我还没研究过。。

下面是发送端的代码:



private void button1_Click(object sender, EventArgs e)
{
Byte[] arry = new Byte[100];

try
{
serialPort1.Open();
// serialPort2.Open();
// if (serialPort1.IsOpen) MessageBox.Show("Serial 1 opened");
}
catch
{
MessageBox.Show("Port one open Failed");

}

FileInfo file = new FileInfo(@"E:\test.BMP");
FileStream Send = new FileStream(@"E:\test.BMP", FileMode.Open, FileAccess.ReadWrite);

for (int i = 0; i < Send.Length/100; i++)
{
Send.Read(arry, 0, 100);
//线程挂起250mS
// System.Threading.Thread.SpinWait(250);

//Thread.sleep(int)也能使程序挂起。。不过容易让人感觉程序失去响应


serialPort1.Write(arry, 0, 100);
} //每次向串口发送100个字节,最后再把不足100字节的结尾给发送过去
Send.Read(arry, 0,(int) (Send.Length%100));
serialPort1.Write(arry, 0, (int)(Send.Length % 100));

serialPort1.Close();
Send.Close();

}

[/CODE]
zzxap 2009-03-26
  • 打赏
  • 举报
回复
[code=C#]
这里主要是讲用serailPort来实现modem的来电显示。
来电显示要依赖于具体的modem,不同的modem,可能AT指令不一样,所以需要定义一个接口,将应用程序与硬件的耦合进行解耦。


public interface IModem
{
void Open();
void Close();
bool SupportAT
{
get;
}
bool SupportCID
{
get;
}
event EventHandler<RingEventArgs> Ring;
}
这个接口定义了open,close方法,还有是否支持AT指令,是否支持来电显示,还有一个响铃事件。RingEventArgs里面包含了来电的电话号码。
在写这个IModem的实现类时,使用的是笔记本的modem,也不知道是什么型号的,就直接用modem来命名。

public class Modem : IModem
{
public event EventHandler<RingEventArgs> Ring;
System.IO.Ports.SerialPort port = null;

public Modem()
{
port = new System.IO.Ports.SerialPort();
port.PortName = Settings.Instance.GetValue("PortName", "COM3");
port.BaudRate = Settings.Instance.GetValue("BaudRate", 460800);
port.DataBits = 8;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.ReadTimeout =
port.WriteTimeout = 1000;//1S

port.ReadBufferSize =
port.WriteBufferSize = 1024;//1K

port.Handshake = Handshake.None;
port.ReceivedBytesThreshold = 10;
port.RtsEnable = true;
port.DtrEnable = true;
port.NewLine = "\r";

this.port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived);
}
上面就是端口的配置,不同的modem可能配置不同,需要根据实际的modem进行设置。

public void Open()
{
if (!this.port.IsOpen)
this.port.Open();
if (!SupportAT)
throw new Exception("设备不支持AT指令");
if (!SupportCID)
throw new Exception("设备不支持来显");
}
public void Close()
{
if (this.port.IsOpen)
this.port.Close();
}
public bool SupportAT
{
get
{
this.port.WriteLine("AT");
System.Threading.Thread.Sleep(500);
string result = this.port.ReadExisting();
return result.ToUpper().Contains("OK");
}
}
public bool SupportCID
{
get
{
string[] commandList = Settings.Instance.SectionValues("CID");
string result = string.Empty;
foreach (string command in commandList)
{
this.port.WriteLine(command);
System.Threading.Thread.Sleep(500);
result = this.port.ReadExisting();
if (result.ToUpper().Contains("OK"))
{
return true;
}
}
return false;
}
}
这是一些方法和属性的实现。需要注意的是在发出指令后,最好能将线程堵塞一段时间,以保证有硬件足够的时间来响应,保证能够接收到完整的回复信息。这里的System.Threading.Thread.Sleep(500);就是这个目的。

void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string phoneNumber = this.port.ReadExisting();
Regex r = new Regex(@"NMBR\s*=\s*[0-9]*");
Match m = r.Match(phoneNumber);

string result = string.Empty;
if (m != null && m.Success)
{
result = m.Value;
result = result.Substring(result.IndexOf("=") + 1).Trim();
}
if (string.IsNullOrEmpty(result))
return;
if (Ring != null)
{
RingEventArgs eventArgs = new RingEventArgs();
eventArgs.PhoneNumber = result;
foreach (EventHandler<RingEventArgs> handler in Ring.GetInvocationList())
{
handler.Invoke(this, eventArgs);
if (eventArgs.Handled)
break;
}
}
}
Ring响铃事件实际上是根据DataReceived接收到的数据进行处理,比如判断是否是来电,截取来电的号码,然后事件冒泡,触发Ring事件。不同的modem返回回来的值肯能是不一样的。上面的正则表达是可能需要再次更改。(网上查到的是 = 号的左右有空格,可是我调试的那个modem却没有)

[/CODE]
chrisziling 2009-03-26
  • 打赏
  • 举报
回复
1、为什么每次只发送100字节,不可以一次发送完整的所有字节吗?
2、接收端怎么才能判断文件已经发送完毕,然后处理?
javacaspnet 2009-03-24
  • 打赏
  • 举报
回复
对于熟悉MSComm控件的程序设计者,SerialPort类是相当容易上手的。在进行串口通讯时,一般的流程是设置通讯端口号及波特率、数据位、停止位和校验位,再打开端口连接,发送数据,接收数据,最后关闭端口连接这样几个步骤。

数据接收的设计方法在这里比较重要,采用轮询的方法比较浪费时间,在Visual Basic中的延时方法中一般会调用API并用DOEvents方法来处理,但程序不易控制,建议采用DataReceived事件触发的方法,合理的设 置ReceivedBytesThreshold的值,若接收的是定长的数据,则将ReceivedBytesThreshold设为接收数据的长度,若 接收数据的结尾是固定的字符或字符串则可采用ReadTo的方法或在DataReceived事件中判断接收的字符是否满足条件。

SerialPort类读取数据的许多方法是同步阻塞调用,尽量避免在主线程中调用,可以使用异步处理或线程间处理调用这些读取数据的方法。

由于DataReceived事件在辅线程被引发,当收到完整的一条数据,返回主线程处理或在窗体上显示时,请注意跨线程的处理,C#可采用控件异步委托的方法Control.BeginInvoke及同步委托的方法Invoke。
lzhsuperman 2009-03-22
  • 打赏
  • 举报
回复
帮顶了
fcxxfcxx 2009-03-22
  • 打赏
  • 举报
回复
学习
chrisziling 2009-03-22
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 javacaspnet 的回复:]
          private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
                {
            FileStream Save = new FileStream(@"E:/received.dat", FileMode.Append, FileAccess.Write);
            Byte[] array = new byte[1024];
            int count = serialPort1.BytesToRead;
            serialPort1.Read(array, 0, count);
            Save.Write(a…
[/Quote]

请教javacaspnet大哥,还有两点不明白!
1、为什么每次只发送100字节,不可以一次发送完整的所有字节吗?
2、接收端怎么才能判断文件已经发送完毕,然后处理?
sxmonsy 2009-03-20
  • 打赏
  • 举报
回复
冒泡泡.
chrisziling 2009-03-20
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 wangfuchong 的回复:]
我是看的voice mode部分,数据部分我没看,应该也是要先用AT指令,然后把文件的二进制流往端口写就行了吧?我想当然的

楼主的电话线还是经过电信的吧?不经过电信的交换机直接连?
[/Quote]
经过电信的,因为有几台电脑分布在不同的位置,而且只有电话线,且不允许上网!!
javacaspnet 2009-03-20
  • 打赏
  • 举报
回复
接分
wonder888888 2009-03-20
  • 打赏
  • 举报
回复
学习,接分
javacaspnet 2009-03-20
  • 打赏
  • 举报
回复
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
FileStream Save = new FileStream(@"E:/received.dat", FileMode.Append, FileAccess.Write);
Byte[] array = new byte[1024];
int count = serialPort1.BytesToRead;
serialPort1.Read(array, 0, count);
Save.Write(array, 0, count);
Save.Close();
}

这里所有的操作都是同步的,异步的我还没研究过。。

下面是发送端的代码:



private void button1_Click(object sender, EventArgs e)
{
Byte[] arry = new Byte[100];

try
{
serialPort1.Open();
// serialPort2.Open();
// if (serialPort1.IsOpen) MessageBox.Show("Serial 1 opened");
}
catch
{
MessageBox.Show("Port one open Failed");

}

FileInfo file = new FileInfo(@"E:\test.BMP");
FileStream Send = new FileStream(@"E:\test.BMP", FileMode.Open, FileAccess.ReadWrite);

for (int i = 0; i < Send.Length/100; i++)
{
Send.Read(arry, 0, 100);
//线程挂起250mS
// System.Threading.Thread.SpinWait(250);

//Thread.sleep(int)也能使程序挂起。。不过容易让人感觉程序失去响应


serialPort1.Write(arry, 0, 100);
} //每次向串口发送100个字节,最后再把不足100字节的结尾给发送过去
Send.Read(arry, 0,(int) (Send.Length%100));
serialPort1.Write(arry, 0, (int)(Send.Length % 100));

serialPort1.Close();
Send.Close();

}

怫悰 2009-03-19
  • 打赏
  • 举报
回复
我是看的voice mode部分,数据部分我没看,应该也是要先用AT指令,然后把文件的二进制流往端口写就行了吧?我想当然的

楼主的电话线还是经过电信的吧?不经过电信的交换机直接连?
chrisziling 2009-03-19
  • 打赏
  • 举报
回复
发送信息用Write()方法,如何发文件啊!!!!请教了!!
chrisziling 2009-03-18
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 wangfuchong 的回复:]
冒泡

前一段时间想做电话自动答录,看了一点

直接通过串口写AT指令写数据应该可以吧?

看看modem的对应(型号或者芯片)资料
[/Quote]

用AT发送文件的指令搞不清楚!不知道Windows的超级终端是这么工作的!!
Teng_s2000 2009-03-18
  • 打赏
  • 举报
回复
UP
怫悰 2009-03-18
  • 打赏
  • 举报
回复
冒泡

前一段时间想做电话自动答录,看了一点

直接通过串口写AT指令写数据应该可以吧?

看看modem的对应(型号或者芯片)资料
悔说话的哑巴 2009-03-18
  • 打赏
  • 举报
回复
UP

111,126

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧