<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      XuGang

      記錄一個程序員的成長

       

      使用C# 實現串口撥號器的SIM卡通信

       

      寫此博客意為拋磚引玉,希望能和博客園的朋友們探討一下關于.NET 在工業方面的應用,包括:物聯網、無線通信、嵌入式開發、工業控制等等。歡迎探討,多多指教!^_^

       

      下面是我在開發中,使用C#代碼實現對安裝在COM 串行端口上的SIM卡撥號器的撥號調度程序。

       

      應用場景:

      在使用新能源的風光互補路燈遠程管理系統中,通信服務器需要通過無線通信方式喚醒上位機。

      > 上位機中內置GPRS 無線上網卡,被安裝在風光互補路燈中。

      > 通信服務器上擴展出4個COM 串行端口,分別安裝有:西門子C35TS 撥號器和西門子MC52I 撥號器。

       

      使用需求:

      > 監控中心跟上位機進行通信前,對沒有連接上的上位機先使用撥號器喚醒;

      > 由于長時間連續使用撥號器進行撥號,將導致撥號器的宕機情況,所以采用輪番調用的線性方式使用4個撥號器;

      > 實現自動檢測服務器上的COM 串行端口,并自動識別可使用的撥號器;

      > 增加撥號器后,程序能自動識別并添加使用;

      > 拔出撥號器后,程序能自動識別并停止使用;

      > 能克服撥號器的宕機、假死等異常情況,并在指定的間隔時間重新檢測撥號器,并添加到服務器中使用;

      > 讓撥號器通過SIM卡,實現對上位機的撥號,掛機等功能;

       

      程序實現:

      程序中應用到AT 指令集,詳細介紹請看百度百科。這里附上一些簡單的AT 指令集:

      AT  回車換行  返回:OK
      
      ATD13800000000;  回車換行  建立呼叫
      
      ATA  回車換行  接聽電話
      
      ATH  回車換行  掛機
      
      AT+IPR=9600  回車換行  設置模塊波特率為9600
      
      AT+CSCA=13800000000 回車換行  設置短信中心號碼
      
      AT+CMGF=1  回車換行  設置短信格式為文本方式(=0為PDU方式,用于發送數據和中文)
      
      AT+CMGS  發送文本短信,具體如下:
      
      AT+CMGS=13800000000
      >0000123456789

       

      在程序項目中,需要引用如下程序集:

      using System.IO.Ports;
      using System.Threading;
      using System.Collections;

      并使用到了.NET 的串行端口資源 SerialPort 類

       

      MySerialPort 類

      對每一個連接到COM 串行端口的撥號器實例化 MySerialPort 對象,代碼如下:

      public class MySerialPort
      {
          private SerialPort com;
          public MySerialPort(string _portName)
           {
               this.com = new SerialPort();
      
               //接收數據事件
               this.com.DataReceived += new SerialDataReceivedEventHandler(com_DataReceived);
               //串口名
               com.PortName = _portName;
               this.PortName = _portName;
      
               // BaudRate 串行波特率
               com.BaudRate = 9600; //默認值
      
               // 是否啟用請求發送 (RTS) 信號。
               com.RtsEnable = true; //由計算機發送 Request To Send 信號到聯接的調制解調器,以請示允許發送數據。
      
               // 是否使Data Terminal Ready (DTR)線有效。 xugang 2012.8.20 添加
               com.DtrEnable = true; //Data Terminal Ready 是計算機發送到調制解調器的信號,指示計算機在等待接受傳輸。 
      
               try
               {
                   com.Open();
               }
               catch //(Exception)
               {
                   Close();
               }
               
           }
      
          public MySerialPort(string _portName, int _baudRate):this(_portName)
          {
              if (_baudRate != 0)
              {
                  // BaudRate 串行波特率
                  com.BaudRate = _baudRate;
              }
          }
      
      
          private string portName;
          //串口名稱
          public string PortName
          {
              get { return portName; }
              set { portName = value; }
          }
      
          // BaudRate 串行波特率
          public int BaudRate
          {
              get { return com.BaudRate; }
              set { com.BaudRate = value; }
          }
      
          private bool isWorking;
          //設置是否正在使用
          public bool IsWorking
          {
              get { return isWorking; }
              set { isWorking = value; }
          }
      
      
           // 檢測當前端口是否安裝有撥號器
           public bool HasModem()
           {
               read = ""; //清空返回緩沖區
               WriteSerial("AT\r\n");
               Thread.Sleep(100);
               Console.WriteLine(read);
               if (read.Contains("ATOK"))
               {
                   Console.WriteLine(this.com.PortName + "端口能使用!");
                   return true;
               }
               else return false;
           }
      
           //進行撥號,喚醒上位機
           public void Dialing(string _SIM)
           {
              IsWorking = true; //正在撥號
      
              read = ""; //清空返回緩沖區
      
              WriteSerial(string.Format("ATD{0};\r\n", _SIM));
      
              System.Threading.Thread.Sleep(20 * 1000);
      
              //Console.WriteLine(" {0}  ATH TO:{1}", DateTime.Now, _SIM);
      
              WriteSerial("ATH\r\n");
      
              Thread.Sleep(500);
              Console.WriteLine(read);
              if (read.Contains("ATHOK"))
              {
                  Console.WriteLine(this.com.PortName + "端口撥號已完成!");
              }
              else
              {
                  //System.Threading.Thread.Sleep(1000);
                  WriteSerial("ATH\r\n");
                  Thread.Sleep(500);
                  Console.WriteLine(read);
      
                  if (read.Contains("ATHOK"))
                  {
                      Console.WriteLine(this.com.PortName + "端口撥號已完成!");
                  }
                  else
                  {
                      IsWorking = false; //撥號完成
                      throw new Exception(this.com.PortName + "撥號異常!");
                  }
              }
      
              IsWorking = false; //撥號完成
           }
      
      
          /// <summary>
          /// 向串口端發送命令!
          /// </summary>
          /// <param name="s">命令字符串</param>
          private void WriteSerial(string s)
          {
              //mLogger.Info(s);
      
              byte[] buff = Encoding.ASCII.GetBytes(s);
              try
              {
                  this.com.Write(buff, 0, buff.Length);
              }
              catch (Exception ex)
              {
                  //WriteExecLog.Writing(ex);
                  Console.WriteLine(ex.Message);
              }
          }
      
          //int n = 0;
          string read = "";
          //接收數據事件方法
          void com_DataReceived(object sender, SerialDataReceivedEventArgs e)
          {
              if (sender is SerialPort)
              {
                  try
                  {
                      SerialPort mySerial = sender as SerialPort;
                      read += mySerial.ReadLine().Trim();
                      //Console.WriteLine(mySerial.PortName + " 第" + n.ToString() + "接收數據:" + read);
                      //n++;
                  }
                  catch (TimeoutException)
                  {
                      return;    //xg備忘:可以將異常寫入日志!
                  }
                  catch (Exception)
                  {
                      return;    //xg備忘:可以將異常寫入日志!
                  }
              }
          }
      
          //關閉
          public void Close()
          {
              if (com != null)
              {
                  com.Close();
                  com.Dispose();
              }
          }
      
          //private string ReadSerial()
          //{
          //    while (_keepReading)
          //    {
          //        if (com.IsOpen)
          //        {
          //            //byte[] readBuffer = new byte[com.ReadBufferSize + 1];
          //            byte[] readBuffer = new byte[10];
          //            try
          //            {
          //                //int count = com.Read(readBuffer, 0, com.ReadBufferSize);
          //                int count = com.Read(readBuffer, 0, 9);
          //                String SerialIn = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count);
          //                if (count != 0)
          //                {
          //                    return SerialIn;
          //                }
          //            }
          //            catch (TimeoutException) 
          //            {
          //                return "";
          //            }
          //        }
          //        else
          //        {
          //            TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50);
          //            Thread.Sleep(waitTime);
          //        }
          //    }
      
          //    return "";
          //}
      
      }

       

      SerialPortList 類

      定義一個 SerialPortList 類,實現對所有連接上的撥號器 MySerialPort 對象進行管理和調度使用。代碼如下:

      public class SerialPortList
      {
          //已經安裝了撥號器的串口對象
          private List<MySerialPort> al = null;
      
          private Dictionary<string, int> portBaudRate = null;
          //波特率配置列表
          public Dictionary<string, int> PortBaudRate
          {
              get { return portBaudRate; }
              set { portBaudRate = value; }
          }
      
          private bool hasPort = false;
          //當前有無可使用的串口撥號器
          public bool HasPort
          {
              get { return hasPort; }
              //set { hasPort = value; }
          }
      
          private int reCheckMinutes = 30; //默認30分鐘
          //串口撥號器的重新檢測間隔分鐘
          public int ReCheckMinutes
          {
              get { return reCheckMinutes; }
              set { reCheckMinutes = value; }
          }
      
          #region  構造方法重載
          public SerialPortList() { }
      
          public SerialPortList(Dictionary<string, int> _portBaudRate) 
          {
              this.portBaudRate = _portBaudRate;
          }
          public SerialPortList(int _reCheckMinutes)
          {
              this.reCheckMinutes = _reCheckMinutes;
          }
          public SerialPortList(Dictionary<string, int> _portBaudRate,int _reCheckMinutes) 
          {
              this.portBaudRate = _portBaudRate;
              this.reCheckMinutes = _reCheckMinutes;
          }
          #endregion  構造方法重載
      
          /// <summary>
          ///  獲得串口上已經安裝了撥號器的對象
          /// </summary>
          public void GetSerialPortList()
          {
              al = new List<MySerialPort>();
      
              //步驟一: 獲得所有的串口名稱(列表)
              string[] ports = SerialPort.GetPortNames();
      
              foreach (string port in ports)
              {
                  MySerialPort mySerialPort = null;
      
                  Console.WriteLine("正在檢測:" + port ); //測試使用
      
                  //是否設置波特率?
                  if (portBaudRate != null 
                      && portBaudRate.ContainsKey(port) 
                      && portBaudRate[port] != 0)
                  {
                      mySerialPort = new MySerialPort(port, portBaudRate[port]);
                  }
                  else mySerialPort = new MySerialPort(port);
      
                  bool ok = mySerialPort.HasModem();
                  if (ok)
                  {
                      al.Add(mySerialPort);
                  }
                  else
                  {
                      mySerialPort.Close();
                      mySerialPort = null;
                  }
              }
      
              // 判斷當前計算機有無可使用串口端
              hasPort = al.Count <= 0 ? false : true;
          }
      
      
          /// <summary>
          /// 重新獲得串口上已經安裝了撥號器的對象
          /// </summary>
          public void ReGetSerialPortList()
          {
              if (al == null) GetSerialPortList();
              else
              {
                  //步驟一: 重新獲得所有的串口名稱(列表)
                  string[] portsName_2 = SerialPort.GetPortNames();
      
                  //如果當前串口數目 > 正在使用的COM
                  if (portsName_2.Length > al.Count)
                  {
                      Console.WriteLine("正在重新檢測可以使用的撥號器!"); //測試使用
                      foreach (string pName_2 in portsName_2)
                      {
                          //當前串口名是否存在撥號列表中
                          bool hasAt = al.Exists(delegate(MySerialPort port_1){ 
                                                    return pName_2 == port_1.PortName; 
                                                });
      
                          //如果當前串口名不存在撥號列表中,則重新檢測!
                          if (!hasAt)
                          {
                              Console.WriteLine("正在重新檢測:" + pName_2); //測試使用
      
                              MySerialPort mySerialPort = null;
      
                              //是否設置波特率?
                              if (portBaudRate != null
                                  && portBaudRate.ContainsKey(pName_2) 
                                  && portBaudRate[pName_2] != 0)
                              {
                                  mySerialPort = new MySerialPort(pName_2, portBaudRate[pName_2]);
                              }
                              else mySerialPort = new MySerialPort(pName_2);
      
                              bool ok = mySerialPort.HasModem();
                              if (ok)
                              {
                                  al.Add(mySerialPort);
                              }
                              else
                              {
                                  mySerialPort.Close();
                                  mySerialPort = null;
                              }
                          }
                      }
                  }
              }
      
              // 判斷當前計算機有無可使用串口端
              hasPort = al.Count <= 0 ? false : true;
          }
      
          /// <summary>
          /// 重新獲得串口上已經安裝了撥號器的對象 (波特率使用默認值)
          /// </summary>
          public void ReGetSerialPortList(int _reCheckMinutes)
          {
              //串口撥號器的重新檢測間隔分鐘
              reCheckMinutes = _reCheckMinutes; 
      
               ReGetSerialPortList();//波特率全部使用默認值
          }
      
          /// <summary>
          /// 釋放所有串口資源組件
          /// </summary>
          public void ClearAllSerialPort()
          {
              if (al != null)
              {
                  for (int i = 0; i < al.Count; i++)
                  {
                      al[i].Close();
                      al[i] = null;
                  }
                  al = null;
              }
      
              if (portBaudRate != null)
              {
                  portBaudRate = null;
              }
          }
      
          private int index_Number = -1;
          //串口的調度號
          private int IndexNumber()
          {
      
              lock (this)
              {
                  if (index_Number + 1 >= al.Count)
                  {
                      if (al.Count == 0) index_Number = -1;
                      else index_Number = 0;
                  }
                  else
                  {
                      index_Number++;
                  }
      
                  return index_Number;
              }
      
          }
      
          /// <summary>
          /// 對已經安裝了撥號器的串口調度使用
          /// </summary>
          private void UseingSerialPort(string _SIM)
          {
              if (al == null) return;
      
              // 等待線程進入 
              Monitor.Enter(al);
      
              MySerialPort getPort = null;
              try
              {
                  //獲得當前調用的串口對象的索引號
                  int num = IndexNumber();
      
                  if (num >= 0) //判斷是否存在撥號器
                  {
                      getPort = al[num];
                      if (getPort != null && !getPort.IsWorking)
                      {
                          getPort.Dialing(_SIM); //對 SIM 進行撥號,喚醒上位機
                      }
                  }
                      
              }
              catch
              {
                  //再一次檢查該 COM 能否使用! (范工提議)
                  if (getPort != null)
                  {
                      string re_PortName = getPort.PortName;
                      al.Remove(getPort); //從可用列表去除
                      getPort.Close();
      
                      MySerialPort mySerialPort = new MySerialPort(re_PortName);
                      bool ok = mySerialPort.HasModem();
                      if (ok)
                      {
                          al.Add(mySerialPort); //重新添加到列表
                      }
                      else
                      {
                          mySerialPort.Close();
                          mySerialPort = null;
                      }
                  }
              }
              finally
              {
                  // 通知其它對象
                  Monitor.Pulse(al);
                  // 釋放對象鎖 
                  Monitor.Exit(al);
              }
          }
      
          //重新檢測端口時間
          private DateTime dtCheck = DateTime.Now;
      
          /// <summary>
          /// 調用撥號器
          /// </summary>
          /// <param name="_SIM"></param>
          public void InvokingSerialPort(string _SIM)
          {
              if (hasPort == false)
              {
                  // 獲得串口上已經安裝了撥號器的對象
                  this.GetSerialPortList();
              }
              else
              {
                  this.UseingSerialPort(_SIM);
                  //Thread.Sleep(5000);
      
                  //定期檢測串口列表
                  if (dtCheck.AddMinutes(reCheckMinutes) <= DateTime.Now)
                  {
                      // 重新獲得串口上已經安裝了撥號器的對象
                      this.ReGetSerialPortList();
                      dtCheck = DateTime.Now;
                  }
              }
          }
        
      }


      測試代碼如下:

      class Program
      {
          static void Main(string[] args)
          {
              // 獲得串口上已經安裝了撥號器的對象 (自定義波特率)
              Dictionary<string, int> _portBaudRate = new Dictionary<string, int>();
              _portBaudRate["COM5"] = 9600;
              _portBaudRate["COM6"] = 9600;
              _portBaudRate["COM7"] = 9600;
      
              SerialPortList list = new SerialPortList(_portBaudRate,5);
      
              try
              {
                  // 獲得串口上已經安裝了撥號器的對象
                  list.GetSerialPortList();
      
                  if (list.HasPort == false)
                  {
                      Console.WriteLine("當前計算機無可使用的串口撥號器!");
                  }
      
                  while (list.HasPort)
                  {
                      // 調用撥號器
                      list.InvokingSerialPort("13500000000");  // 實際SIM卡號
                      Thread.Sleep(5000);
                  }
              }
              finally
              {
                  // 釋放所有串口資源組件
                  list.ClearAllSerialPort();
              }
      
              Console.ReadLine();
          }
      }

      測試結果:

       

      參考資源:
      在C# 中使用SerialPort 類實現串口通信(陸續更新)
      AT 指令發送短信流程
      短信 PDU 解碼

       

      posted on 2012-08-23 16:29  鋼鋼  閱讀(7302)  評論(26)    收藏  舉報

      導航

      主站蜘蛛池模板: 视频一区视频二区卡通动漫| 玉环县| 在线精品国产中文字幕| 亚洲男人的天堂久久香蕉| 亚洲男人综合久久综合天堂| 麻豆国产va免费精品高清在线| 久久99国产精品尤物| 国产成人亚洲日韩欧美| 亚洲人成电影网站色mp4| 国产成人无码www免费视频播放| 人妻在线中文字幕| 亚洲av国产成人精品区| 亚洲国产另类久久久精品黑人| 一区二区中文字幕久久| 麻豆国产成人AV在线播放| 人妻少妇邻居少妇好多水在线 | 好吊视频在线一区二区三区| 日本精品不卡一二三区| 婷婷开心深爱五月天播播| 四虎永久精品免费视频| 视频一区视频二区在线视频| 在线观看视频一区二区三区| 国产亚洲精品午夜福利| 日韩一区二区三区日韩精品| 蜜桃在线一区二区三区| 浦东新区| 九九热精品免费在线视频| 色欲国产精品一区成人精品| 中文幕无线码中文字夫妻| 国产嫩草精品网亚洲av| 亚洲一区二区三区十八禁| 成人亚欧欧美激情在线观看| 麻豆精品在线| 亚洲综合小综合中文字幕| 九九热精品免费视频| 久久精品熟女亚洲av艳妇| 国产精品不卡一区二区在线 | av在线播放国产一区| 性色av极品无码专区亚洲| 亚洲区综合中文字幕日日| 高清自拍亚洲精品二区|