利用MSCOMM控件通过串口MODEN实现来电显示-c# source code

时间:2022-09-06 10:31:21

利用MSCOMM控件通过串口MODEN实现来电显示-c# source code
注:此代码都已调试通过

处理方式
MSComm控件提供了两种处理通信的方式:一种为事件驱动方式,该方式相当于一般程序设计中的中断方式。当串口发生事件或错误时,MSComm控件会产生OnComm事件,用户程序可

以捕获该事件进行相应处理。本文的两个例子均采用该方式。另一种为查询方式,在用户程序中设计定时或不定时查询MSComm控件的某些属性是否发生变化,从而确定相应处理。

在程序空闲时间较多时可以采用该方式。
常用属性和方法
利用MSComm控件实现计算机通信的关键是理解并正确设置MSComm控件众多属性和方法。以下是MSComm控件的常用属性和方法:
●Commport:设置或返回串口号。
●Settings:以字符串的形式设置或返回串口通信参数。
●Portopen:设置或返回串口状态。
●InputMode:设置或返回接收数据的类型。
●Inputlen:设置或返回一次从接收缓冲区中读取字节数。
●InBufferSize:设置或返回接收缓冲区的大小,缺省值为1024字节。
●InBufferCount:设置或返回接收缓冲区中等待计算机接收的字符数。
●Input:从接收缓冲区中读取数据并清空该缓冲区,该属性设计时无效,运行时只读。
●OutBufferSize:设置或返回发送缓冲区的大小,缺省值为512字节。
●OutBufferCount:设置或返回发送缓冲区中等待计算机发送的字符数。
●Output:向发送缓冲区发送数据,该属性设计时无效,运行时只读。
●Rthreshold:该属性为一阀值。当接收缓冲区中字符数达到该值时,MSComm控件设置Commevent属性为ComEvReceive,并产生OnComm事件。用户可在OnComm事件处理程序中进行相

应处理。若Rthreshold属性设置为0,则不产生OnComm事件。例如用户希望接收缓冲区中达到一个字符就接收一个字符,可将Rthreshold设置为1。这样接收缓冲区中接收到一个字

符,就产生一次OnComm事件。
●Sthreshold:该属性亦为一阀值。当发送缓冲区中字符数小于该值时,MSComm控件设置Commevent属性为ComEvSend,并产生OnComm事件。若Sthreshold属性设置为0,则不产生

OnComm事件。要特别注意的是仅当发送缓冲区中字符数小于该值的瞬间才产生OnComm事件,其后就不再产生OnComm事件。例如Sthreshold设置为3,仅当发送缓冲区中字符数从3降

为2时,MSComm控件设置Commevent属性为ComEvSend,同时产生OnComm事件,如发送缓冲区中字符始终为2,则不会再产生OnComm事件。这就避免了发送缓冲区中数据未发送完就反

复发生OnComm事件。
●CommEvent:这是一个非常重要的属性。该属性设计时无效,运行时只读。一旦串口发生通信事件或产生错误,依据产生的事件和错误,MSComm控件为CommEvent属性赋不同的代

码,同时产生OnComm事件。用户程序就可在OnComm事件处理程序中针对不同的代码,进行相应的处理。CommEvent属性的代码、常数及含义参见表1及表2。
表1 CommEvent通信事件代码 常数 含义
1 ComEvReceive 接受到Rthreshold个字符。该事件将持续产生,直到用Input属性从接受缓冲区中读取并删除字符。
2 ComEvSend 发送缓冲区中数据少于Sthreshold个,说明串口已经发送了一些数据,程序可以用Output属性继续发送数据。
3 ComEvCTS Clear To Send信号线状态发生变化。
4 ComEvDSR Data Set Ready信号线状态从1变到0。
5 ComEvCD Carrier Detect信号线状态发生变化。
6 ComEvRing 检测到振铃信号。
7 ComEvEOF 接受到文件结束符。


表2 CommEvent通信错误代码 常数 含义
1001 ComEvntBreak 接受到一个中断信号。
1002 ComEvntCTSTO Clear To Send信号超时。
1003 ComEvntDSRTO Data Set Ready信号超时。
1004 ComEvntFrame 帧错误。
1006 ComEvntOverrun 串口超速。
1007 ComEvntCDTO 载波检测超时。
1008 ComEvntRxOver 接受缓冲区溢出,缓冲区中已没有空间。
1009 ComEvntRxParity 奇偶校验错。
1010 ComEvntTxFull 发送缓冲区溢出,缓冲区中已没有空间。
1011 ComEvntDCB 检索串口的设备控制块时发生错误。

怎样判断MODEM是否具有来电显示功能
1、打开"超级终端"软件 点击"开始"->"程序"->"附件"->"通讯"->"超级终端"
2、接下来是"新建连接",这里随便输入几个字符即可
3、接下来"输入待拨电话的详细信息",这里主要是要选择好您要测试的MODEM,电话号码可不输入。
利用MSCOMM控件通过串口MODEN实现来电显示-c# source code
4、接下来"进行拨号",这里直接点击"取消"按钮即可,不要点击"拨号"按钮
5、输入MODEM的AT指令
ATZ       回车
结果:屏幕上显示"OK"提示。如果您在输入"ATZ"指令时看不到输入的内容,不关它,照着输入知道看到OK提示
AT+VCID=1 回车
结果:如果您的MODEM支持这条指令的话,屏幕上将看到"OK"提示,如果不支持将看到"ERROR"提示。
     如果看到的是"ERROR"提示,您可将"AT+VCID=1"改成"AT#CID=1"再试一次,一般可看到"OK"提示了。
     如果执行了上面两条指令后,得到的还是"ERROR"指令,请查阅MODEM手册,看激活MODEM来电功能的指令是什么。
利用MSCOMM控件通过串口MODEN实现来电显示-c# source code
6、接下来利用其他电话进行拨打,看屏幕上是否显示来电号码,如果有,表明您的MODEM支持来电。


来电显示的实现
MODEM的AT命令CID和VCID是设置是不是来电显示的,如果电信开通了来电显示功能
就能通过MODEM来显示对方的电话号码。那么首先设置CID=1或是VCID=1

般来说来电显示的信息为:
DATE = MMDD "来电日期 MMDD
TIME = HHMM "来电时间 HHMM
NMBR = ######## "来电号码

下面的代码,实现了来电显示功能:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text.RegularExpressions;
using System.Xml;

namespace incomingtelegramdisplay
{
 /// <summary>
 /// Form1 的摘要说明。
 /// </summary>
 public class Form1 : System.Windows.Forms.Form
 {
  private AxMSCommLib.AxMSComm com;
  private System.Windows.Forms.RichTextBox rtfTerminal;
  /// <summary>
  /// 必需的设计器变量。
  /// </summary>
  private System.ComponentModel.Container components = null;
  private System.Windows.Forms.Label lblPhoneNum;
  private System.Windows.Forms.Button button1;
  private System.Windows.Forms.Button button2;
  private System.Windows.Forms.Label label1;
  private string callinfo="";

    public Form1()
  {
   //
   // Windows 窗体设计器支持所必需的
   //
   InitializeComponent();
   

   //
   // TODO: 在 InitializeComponent 调用后添加任何构造函数代码
   //
   // Initialize the COM Port control
   InitComPort();
   
   // Send data out through the COM port
   //com.Output = "Serial Terminal Initialized";
   com.Output="at+vcid=1"+"\r";


  }

  private void InitComPort()
  {
   try
   {
    // Set the com port to be 1
    com.CommPort = 3;
   
    // This port is already open, close it to reset it.
    if (com.PortOpen) com.PortOpen = false;
   
    // Trigger the OnComm event whenever data is received
    com.RThreshold = 1; 
   
    com.SThreshold=0;
    // Set the port to 9600 baud, no parity bit, 8 data bits, 1 stop bit (all standard)
    com.Settings = "9600,n,8,1";

    // Force the DTR line high, used sometimes to hang up modems
    com.DTREnable = true;
   
    // No handshaking is used
    com.Handshaking = MSCommLib.HandshakeConstants.comNone;

    // Don't mess with byte arrays, only works with simple data (characters A-Z and numbers)
    com.InputMode = MSCommLib.InputModeConstants.comInputModeText;
    //com.InputMode = MSCommLib.InputModeConstants.comInputModeBinary;

   
    // Use this line instead for byte array input, best for most communications
    //com.InputMode = MSCommLib.InputModeConstants.comInputModeText;
   
    // Read the entire waiting data when com.Input is used
    com.InputLen = 0;

    // Don't discard nulls, 0x00 is a useful byte
     com.NullDiscard = false;
   
    // Attach the event handler
    com.OnComm += new System.EventHandler(this.OnComm);
   
    // Open the com port
    com.PortOpen = true; 

    //com.Output = "Serial Terminal Initialized";
    
   }
   catch(Exception e)
   {
   MessageBox.Show(e.Message);
   }

   
  }
  

  private void OnComm(object sender, EventArgs e)  //  MSCommLib OnComm Event Handler
  {
    

     this.callinfo=callinfo+com.Input.ToString();
   this.rtfTerminal.Text=this.callinfo;
   infoToken(this.rtfTerminal.Text);
   
       
  }

  private void infoToken(string temp)
  {
   //DATE = 0106
   //TIME = 0219
   //NMBR = 21156896
   // Build a regular expression to match data that
   
   Regex r = new Regex(@"NMBR\s=\s[0-9]*");
           string num="";
   // Cycle through the matches
   for (Match m = r.Match(temp); m.Success; m = m.NextMatch())
   {
    // Display the result to the 'Output' debug window
    //this.lblPhoneNum.Text=m.Value;
                num=m.Value;
    
   }
            num=num.Substring(7);
   this.lblPhoneNum.Text=num;

  }

  private void ProcessComData(string input)
  {
   // Send incoming data to a Rich Text Box
   rtfTerminal.AppendText(input + "\n");
  }


  /// <summary>
  /// 清理所有正在使用的资源。
  /// </summary>
  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }

  #region Windows 窗体设计器生成的代码
  /// <summary>
  /// 设计器支持所需的方法 - 不要使用代码编辑器修改
  /// 此方法的内容。
  /// </summary>
  private void InitializeComponent()
  {
   System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
   this.com = new AxMSCommLib.AxMSComm();
   this.rtfTerminal = new System.Windows.Forms.RichTextBox();
   this.lblPhoneNum = new System.Windows.Forms.Label();
   this.button1 = new System.Windows.Forms.Button();
   this.button2 = new System.Windows.Forms.Button();
   this.label1 = new System.Windows.Forms.Label();
   ((System.ComponentModel.ISupportInitialize)(this.com)).BeginInit();
   this.SuspendLayout();
   //
   // com
   //
   this.com.Enabled = true;
   this.com.Location = new System.Drawing.Point(16, 192);
   this.com.Name = "com";
   this.com.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("com.OcxState")));
   this.com.Size = new System.Drawing.Size(38, 38);
   this.com.TabIndex = 0;
   //
   // rtfTerminal
   //
   this.rtfTerminal.Location = new System.Drawing.Point(24, 24);
   this.rtfTerminal.Name = "rtfTerminal";
   this.rtfTerminal.Size = new System.Drawing.Size(240, 120);
   this.rtfTerminal.TabIndex = 1;
   this.rtfTerminal.Text = "richTextBox1";
   //
   // lblPhoneNum
   //
   this.lblPhoneNum.Location = new System.Drawing.Point(104, 160);
   this.lblPhoneNum.Name = "lblPhoneNum";
   this.lblPhoneNum.Size = new System.Drawing.Size(160, 23);
   this.lblPhoneNum.TabIndex = 2;
   this.lblPhoneNum.Text = "label1";
   //
   // button1
   //
   this.button1.Location = new System.Drawing.Point(96, 208);
   this.button1.Name = "button1";
   this.button1.TabIndex = 3;
   this.button1.Text = "button1";
   this.button1.Click += new System.EventHandler(this.button1_Click);
   //
   // button2
   //
   this.button2.Location = new System.Drawing.Point(192, 208);
   this.button2.Name = "button2";
   this.button2.TabIndex = 4;
   this.button2.Text = "记录号码";
   this.button2.Click += new System.EventHandler(this.button2_Click);
   //
   // label1
   //
   this.label1.Location = new System.Drawing.Point(24, 160);
   this.label1.Name = "label1";
   this.label1.Size = new System.Drawing.Size(72, 23);
   this.label1.TabIndex = 5;
   this.label1.Text = "来电号码:";
   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
   this.ClientSize = new System.Drawing.Size(288, 246);
   this.Controls.Add(this.label1);
   this.Controls.Add(this.button2);
   this.Controls.Add(this.button1);
   this.Controls.Add(this.lblPhoneNum);
   this.Controls.Add(this.rtfTerminal);
   this.Controls.Add(this.com);
   this.Name = "Form1";
   this.Text = "Form1";
   this.Load += new System.EventHandler(this.Form1_Load);
   ((System.ComponentModel.ISupportInitialize)(this.com)).EndInit();
   this.ResumeLayout(false);

  }
  #endregion

  /// <summary>
  /// 应用程序的主入口点。
  /// </summary>
  [STAThread]
  static void Main()
  {
   Application.Run(new Form1());
  }

  private void Form1_Load(object sender, System.EventArgs e)
  {
  
  }

  private void button1_Click(object sender, System.EventArgs e)
  {
  string a="DATE = 0106 TIME = 0219 NMBR = 21156896";
        infoToken(a);
  }

  private void button2_Click(object sender, System.EventArgs e)
  {
  string fileName="..\\incomingPhoneNumber.xml";
   XmlTextWriter tw=new XmlTextWriter(fileName,null);
   tw.Formatting=Formatting.Indented;
   tw.WriteStartDocument();

   tw.WriteStartElement("IncomingCall");
   tw.WriteElementString("PhoneNumber",this.lblPhoneNum.Text);
           
            tw.WriteEndElement();
   tw.WriteEndDocument();
   tw.Flush();
   tw.Close();
  }
 }
}