通过GPRS模块发送MMS 
基于GPRS的远程自动抄表系统的设计



基于GPRS网络的GPS图形导航仪

GPS- Deriving British Ordnance Survey Grid Reference from NMEA data - Part 1 - modify NMEAinterpreter class
How to Write a GPS Application - Introduction

PDU 编码

 C++,Delphi 7位编码
http://www.dreamfabric.com/sms/ SMS and the PDU format 7-bit
GSM MODEM接收短信 C编码

手机发送短消息  (全面)
http://blog.csdn.net/qianbo_0423/archive/2006/02/17/601029.aspx

Use P/Invoke to Develop a .NET Base Class Library for Serial Device Communications
http://msdn.microsoft.com/msdnmag/issues/02/10/NETSerialComm/default.aspx
This article assumes you're familiar with C# and RS232 communications
 
AT编程相关技术问题 
http://blog.csdn.net/zlyperson/archive/2004/12/15/217316.aspx

 Palm 串行通讯GPS数据读取的实现
http://yhyblog.bokee.com/4826431.html

AT指令编程必读

http://www.sendsms.cn/technic/03.htm

基于串口通信的远程自动抄表系统实现

http://www.sendsms.cn/technic/07.htm

 

安瑞尔短信网(下载中心)控件

http://www.forwardsoft.net/pages/product_download.html

通信技术专栏

http://www.sendsms.cn/technic.htm

Visual C#实现自定义组件的设计

发邮件

VC 6.0实现串行通信的三种方法

http://htm.winsteps.net/program/5880.htm

带你了解无线上网卡的安装和设置

http://www.topc.cn/Article/portable/2006030714431366768.htm

基于CDMA 1X的远程监控系统设计

http://www.avrw.com/article/art_115_5340.htm

 

无线论坛

http://www.web54.com/list.aspx?u=f/904/1-500.html

简单而强大的多线程串口编程工具CserialPort类(附VC基于MFC单文档协议通讯源程序及详细编程步骤)

http://www.gjwtech.com/scomm/sc2serialportclass.htm

利用SerialPort类实现收发短信(C# 2.0) (DLL

http://blog.csdn.net/veryhappy/archive/2006/04/05/651949.aspx

.net开发手机短信

http://blog.csdn.net/Awinye/archive/2005/11/28/538300.aspx

短信开发

http://blog.csdn.net/hesicong/category/23319.aspx 很全很全很全

如何通过电脑发送短信——开始篇

http://blog.csdn.net/itcoco/archive/2006/01/12/576911.aspx

 

自己动手打造企业级短信平台(上)

http://blog.csdn.net/devercn/archive/2004/09/21/111809.aspx

PDU短信发送编码程序(C# 2.0[]

http://hi.baidu.com/wang_zan/blog/item/f148bc3514feba8ba61e121e.html

各种无线上网方法比较

http://doreso125.bokee.com/5623391.html

 

VisualStudio2005serialPort控件访问串口实例[转载]

http://www.cublog.cn/u/15586/showart_189530.html

Imports System
Imports System.IO.Ports
Imports System.Threading
 
Public Class PortChat
     Shared _continue As Boolean
      Shared _serialPort As SerialPort

      Public Shared Sub Main()
         Dim name As String
          Dim message As String
          Dim sComparer As StringComparer = StringComparer.OrdinalIgnoreCase
         Dim readThread As Thread = New Thread(AddressOf Read)

          ' Create a new SerialPort object with default settings.
          _serialPort = New SerialPort()

          ' Allow the user to set the appropriate properties.
          _serialPort.PortName = SetPortName(_serialPort.PortName)
         _serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate)
         _serialPort.Parity = SetPortParity(_serialPort.Parity)
         _serialPort.DataBits = SetPortDataBits(_serialPort.DataBits)
         _serialPort.StopBits = SetPortStopBits(_serialPort.StopBits)
         _serialPort.Handshake = SetPortHandshake(_serialPort.Handshake)

          ' Set the read/write timeouts
          _serialPort.ReadTimeout = 500
         _serialPort.WriteTimeout = 500

          _serialPort.Open()
         _continue = True
          readThread.Start()

          Console.Write("Name: ")
         name = Console.ReadLine()

          Console.WriteLine("Type QUIT to exit")

          While (_continue)
             message = Console.ReadLine()

              If sComparer.Equals("quit", message) Then
                  _continue = False
              Else
                  _serialPort.WriteLine( _
                     String.Format("<{0}>: {1}", name, message))
             End If
          end while

           readThread.Join()
         _serialPort.Close()
     End Sub

       Public Shared Sub Read()
         While (_continue)
             Try
                  Dim message As String = _serialPort.ReadLine()
                 Console.WriteLine(message)
             Catch ex As TimeoutException
                 ' Do nothing
              End Try
          End While
      End Sub

       Public Shared Function SetPortName(ByVal defaultPortName As String) As String
          Dim newPortName As String

           Console.WriteLine("Available Ports:")
         Dim s As String
          For Each s In SerialPort.GetPortNames()
             Console.WriteLine(" {0}", s)
         Next s

          Console.Write("COM port({0}): ", defaultPortName)
         newPortName = Console.ReadLine()

          If newPortName = "" Then
              newPortName = defaultPortName
         End If
          Return newPortName
     End Function

       Public Shared Function SetPortBaudRate(ByVal defaultPortBaudRate As Integer) As Integer
          Dim newBaudRate As String

           Console.Write("Baud Rate({0}): ", defaultPortBaudRate)
         newBaudRate = Console.ReadLine()

          If newBaudRate = "" Then
              newBaudRate = defaultPortBaudRate.ToString()
         End If

           Return Integer.Parse(newBaudRate)
     End Function

       Public Shared Function SetPortParity(ByVal defaultPortParity As Parity) As Parity
         Dim newParity As String

           Console.WriteLine("Available Parity options:")
         Dim s As String
          For Each s In [Enum].GetNames(GetType(Parity))
             Console.WriteLine(" {0}", s)
         Next s

          Console.Write("Parity({0}):", defaultPortParity.ToString())
         newparity = Console.ReadLine()

          If newparity = "" Then
              newparity = defaultPortParity.ToString()
         End If

           Return CType([Enum].Parse(GetType(Parity), newParity), Parity)
     End Function

       Public Shared Function SetPortDataBits(ByVal defaultPortDataBits As Integer) As Integer
          Dim newDataBits As String

           Console.Write("Data Bits({0}): ", defaultPortDataBits)
         newDataBits = Console.ReadLine()

          If newDataBits = "" Then
              newDataBits = defaultPortDataBits.ToString()
         End If

           Return Integer.Parse(newDataBits)
     End Function

       Public Shared Function SetPortStopBits(ByVal defaultPortStopBits As StopBits) As StopBits
         Dim newStopBits As String

           Console.WriteLine("Available Stop Bits options:")
         Dim s As String
          For Each s In [Enum].GetNames(GetType(StopBits))
             Console.WriteLine(" {0}", s)
         Next s

          Console.Write("Stop Bits({0}):", defaultPortStopBits.ToString())
         newStopBits = Console.ReadLine()

          If newStopBits = "" Then
              newStopBits = defaultPortStopBits.ToString()
         End If

           Return CType([Enum].Parse(GetType(StopBits), newStopBits), StopBits)
     End Function

       Public Shared Function SetPortHandshake(ByVal defaultPortHandshake As Handshake) As Handshake
         Dim newHandshake As String

           Console.WriteLine("Available Handshake options:")
         Dim s As String
          For Each s In [Enum].GetNames(GetType(Handshake))
             Console.WriteLine(" {0}", s)
         Next s

          Console.Write("Stop Bits({0}):", defaultPortHandshake.ToString())
         newHandshake = Console.ReadLine()

          If newHandshake = "" Then
              newHandshake = defaultPortHandshake.ToString()
         End If

           Return CType([Enum].Parse(GetType(Handshake), newHandshake), Handshake)
     End Function
End Class

 

using System;
using System.IO.Ports;
using System.Threading;
 
public class PortChat
{
     static bool _continue;
     static SerialPort _serialPort;

      public static void Main()
     {
         string name;
         string message;
         StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
         Thread readThread = new Thread(Read);

          // Create a new SerialPort object with default settings.

          _serialPort = new SerialPort();

          // Allow the user to set the appropriate properties.

          _serialPort.PortName = SetPortName(_serialPort.PortName);
         _serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);
         _serialPort.Parity = SetPortParity(_serialPort.Parity);
         _serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);
         _serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);
         _serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);

          // Set the read/write timeouts

          _serialPort.ReadTimeout = 500;
         _serialPort.WriteTimeout = 500;

          _serialPort.Open();
         _continue = true;
         readThread.Start();

          Console.Write("Name: ");
         name = Console.ReadLine();

          Console.WriteLine("Type QUIT to exit");

          while (_continue)
         {
             message = Console.ReadLine();

              if (stringComparer.Equals("quit", message))
             {
                 _continue = false;
             }
             else
              {
                 _serialPort.WriteLine(
                     String.Format("<{0}>: {1}", name, message) );
             }
         }

          readThread.Join();
         _serialPort.Close();
     }

      public static void Read()
     {
         while (_continue)
         {
             try
              {
                 string message = _serialPort.ReadLine();
                 Console.WriteLine(message);
             }
             catch (TimeoutException) { }
         }
     }

      public static string SetPortName(string defaultPortName)
     {
         string portName;

          Console.WriteLine("Available Ports:");
         foreach (string s in SerialPort.GetPortNames())
         {
             Console.WriteLine(" {0}", s);
         }

          Console.Write("COM port({0}): ", defaultPortName);
         portName = Console.ReadLine();

          if (portName == "")
         {
             portName = defaultPortName;
         }
         return portName;
     }

      public static int SetPortBaudRate(int defaultPortBaudRate)
     {
         string baudRate;

          Console.Write("Baud Rate({0}): ", defaultPortBaudRate);
         baudRate = Console.ReadLine();

          if (baudRate == "")
         {
             baudRate = defaultPortBaudRate.ToString();
         }

          return int.Parse(baudRate);
     }

      public static Parity SetPortParity(Parity defaultPortParity)
     {
         string parity;

          Console.WriteLine("Available Parity options:");
         foreach (string s in Enum.GetNames(typeof(Parity)))
         {
             Console.WriteLine(" {0}", s);
         }

          Console.Write("Parity({0}):", defaultPortParity.ToString());
         parity = Console.ReadLine();

          if (parity == "")
         {
             parity = defaultPortParity.ToString();
         }

          return (Parity)Enum.Parse(typeof(Parity), parity);
     }

      public static int SetPortDataBits(int defaultPortDataBits)
     {
         string dataBits;

          Console.Write("Data Bits({0}): ", defaultPortDataBits);
         dataBits = Console.ReadLine();

          if (dataBits == "")
         {
             dataBits = defaultPortDataBits.ToString();
         }

          return int.Parse(dataBits);
     }
     
     public static StopBits SetPortStopBits(StopBits defaultPortStopBits)
     {
         string stopBits;

          Console.WriteLine("Available Stop Bits options:");
         foreach (string s in Enum.GetNames(typeof(StopBits)))
         {
             Console.WriteLine(" {0}", s);
         }

          Console.Write("Stop Bits({0}):", defaultPortStopBits.ToString());
         stopBits = Console.ReadLine();

          if (stopBits == "")
         {
             stopBits = defaultPortStopBits.ToString();
         }

          return (StopBits)Enum.Parse(typeof(StopBits), stopBits);
     }

      public static Handshake SetPortHandshake(Handshake defaultPortHandshake)
     {
         string handshake;

          Console.WriteLine("Available Handshake options:");
         foreach (string s in Enum.GetNames(typeof(Handshake)))
         {
             Console.WriteLine(" {0}", s);
         }

          Console.Write("Stop Bits({0}):", defaultPortHandshake.ToString());
         handshake = Console.ReadLine();

          if (handshake == "")
         {
             handshake = defaultPortHandshake.ToString();
         }

          return (Handshake)Enum.Parse(typeof(Handshake), handshake);
     }
}

C#开发终端式短信的原理和方法

http://blog.csdn.net/gztoby/archive/2004/09/21/112041.aspx

简介

  没发过短信的年轻人肯定是属于那种受保护的稀有动物,通讯发达的今天短信已经成为人们交流的重要手段,其中也蕴含着巨大的市场和经济利益,掌握短信技术的人才也受到各大公司的追捧是目前职场上耀眼的明星。本文介绍了短信的原理和实现方法,重点说明了短信的编码方式、AT指令以及用C#实现串口通讯的方法。

  前言

  目前,主有三种发送短信的方式:

  1 网关方式:就是向当地的电信部门申请,不需要额外的设备,适用于大型的通信公司,像华为、傲天、中兴、亚信等。

  2 终端方式:就是借助像GSM MODEM之类的设置(支持AT指令的手机也行),通过数据线连接电脑,来发送短信,用这种方法比较适用于小型及个人。要实现这种方式必须理解串口通信、AT指令、短信编码、解码,这也是本文讨论的重点。

  3 利用一些网站来实现,方式简单,不过对网站依赖性太高,对网络的要求也比较高,非常不适于进行项目开发


 

终端短信连接示意图



原理篇

  短信编码

  在收发短信方面,按时间产生先后,共产生了三种模式:Block Mode、基于AT指令的Text Mode、基于AT指令的PDU Modem, Text Mode比较简单,多款诺基亚手机均支持该模式。西门子的手机大多只支持PDU模式,PDU模式是发送或接收手机SMS信息的一种方法,短信息正文经过十六进制编码后被传送。目前,PDU已取代Block Mode,因我们主要探讨PDU模式的发送。以西门子3508手机为例。

  SMS是由Etsi所制定的一个规范(GSM 03.40 GSM 03.38)。当使用7-bits编码时,它可以发送最多160个字符;但用8-bit编码,最多可以发送140个字符,通常无法直接通过手机显示;还有用16-bit编码时,最多70个字符,被用来显示Unicode(UCS2)文本信息,可以被大多数的手机所显示。我们今天讨论的是UCS2编码,也就是说,最多只能发送70个字符,不管英文还是中文。

  现例如我们现在要发送如下信息,向我的手机13715342642发送"你好,Hello!"。在没有发送之前,你要清楚,手机SIM卡所在地的短信中心号,并不是你现在所在地方的短信中心号,像我在深圳,深圳的短信中心号是:8613800755000,即使我现在到外地,短信中心号仍是深圳。从上面我们得到了下面的信息:

  接收的手机号:13715342642
  短信中心号:8613800755000
  短信内容:你好,Hello!

  在实际使用中,上面这些信息并不为手机所执行,要进行编码手机才会执行,先不管,看看编码后的信息:

0891683108705500F011000D91683117352446F2000800124F60597DFF0C00480065006C006C006F0021

  看不懂吧,我来解释一下:

  08 - 指的是短信中心号的长度,也就是指(91)+( 683108705500F0)的长度

  91 - 指的是短信息中心号码类型。91TON/NPI遵守International/E.164标准,指在号码前需加'+'号;此外还有其它数值,但91最常用。

  683108705500F0 - 短信息中心号码。由于位置上略有处理,实际号码应为:8613800731500(字母F是指长度减1)。这需要根据不同的地域作相应的修改。前面的(08)+(91)+( 683108705500F0)实际上就构成了整个短信的一部份,通称短消息中心地址(Address of the SMSC)。

  11 - 文件头字节

  00 - 信息类型(TP-Message-Reference

  0D - 被叫号码长度

  91 - 被叫号码类型

  其实在实际处理中,我们通常把11000D91写死在程序中,因为在国内,这些数据都是不会改变的。

  683117352446F2 -被叫号码,经过了位移处理,实际号码为"8613715342642"。上面的(00+0D+91+( 683117352446F2),构成了整个短信的第二部份目的地址(TP-Destination-Address)。

  00 - 协议标识TP-PID,这里一般为00

  08 - 数据编码方案TP-DCSTP-Data-Coding-Scheme,采用前面说的USC2(16bit)数据编码

  00 - 有效期TP-VPTP-Valid-Period

  12-长度TP-UDLTP-User-Data-Length),也就是4F60597DFF0C00480065006C006C的长度 36 / 2 = 18 的十六进 12

  4F60597DFF0C00480065006C006C 006F0021- 这里就是短信内容了,实际内容为:"你好,Hello!"程序实现,请参考本文章所带源程序的PDUdecoding.cs

AT指令

  说到AT指令可多了,有厚厚的一本书,不属于我们今天讨论的范围,在这里我仅讨论在发送短信中必须要用的几个AT指令。

  与SMS有关的GSM AT指令(from GSM07.05)如表1所示:

AT 指令

AT+CMGC

Send an SMS command(发出一条短消息命令)

AT+CMGD

Delete SMS message(删除SIM卡内存的短消息)

AT+CMGF

Select SMS message formate(选择短消息信息格式:0-PDU;1-文本)

AT+CMGL

List SMS message from preferred store(列出SIM卡中的短消息PDU/text: 0/"REC UNREAD"-未读,1/"REC READ"-已读,2/"STO UNSENT"-待发,3/"STO SENT"-已发,4/"ALL"-全部的)

AT+CMGR

Read SMS message(读短消息)

AT+CMGS

Send SMS message(发送短消息)

AT+CMGW

Write SMS message to memory(向SIM内存中写入待发的短消息)

AT+CMSS

Send SMS message from storage(从SIN|M内存中发送短消息)

AT+CNMI

New SMS message indications(显示新收到的短消息)

AT+CPMS

Preferred SMS message storage(选择短消息内存)

AT+CSCA

SMS service center address(短消息中心地址)

AT+CSCB

Select cell broadcast messages(选择蜂窝广播消息)

AT+CSMP

Set SMS text mode parameters(设置短消息文本模式参数)

AT+CSMS

Select Message Service(选择短消息服务)

表一:相关的GSM AT指令

  我现在以实例来说明这些指令的使用方法:

  先用手机数据线将手机连接到电脑串口,并将串口的波特率设置为19200,可以开始了。

  1、首先测试你的连接及手机是否支持AT指令,请在你的串口调试程序中输入:

  AT<回车>

  屏幕上返回"OK"表明计算机与手机连接正常,那样我们就可以进行其它的AT指令测试了

  2、设置短信发送格式

  AT+CMGF=1<回车>

  屏幕上返回"OK"表明现在短信的发送方式为PDU方式,如果是设置为TEXT方式,则,AT+CMGF=0<回车>

  3 发送短信

  发送内容及手要号仍旧同上面在编码中的一样,编码后,得到要发送的数据如下

0891683108705505F011000D91683117352446F2000800124F60597D002C00480065006C006C006F0021

  我们用如下指令来发送

  AT+CMGS=33<回车>

  如果返回"",就把上面编码数据输入,并以CTRL+Z结尾,稍等一下,你就可以看到返回OK啦。

  说明一下,为什么AT+CMGS=33呢,是这样得来的:

11000D91683117352446F2000800124F60597D002C00480065006C006C006F0021

  这一段字符串的长度除以2得到的结果,上面的字符串,短信中心号加上短信内容得到的,怎么得到的,请回顾一下解码部份

  在我们前面的讨论中,一条完整的短信发送,只要执行三条AT指令,ATAT+CMGS=?、AT+CMGS=?就可以了。由于篇幅,我只能在这里提到这么多,大家要是想了解更多,可以向各手机厂商索取AT指令白皮书,里面很详细的。

  上面讲到的,只能为我们实际中作准备,我们还必须要一个发送途径,根据我们的需要,我们选择投资最少,实现比较方便的串口通信。注意,串口通过数据线跟手机相连,用AT指令来实现发送短信,在我们选择数据线时,建议购买原厂所配,非原厂所配,在使用过程中,经常出现一些莫明其妙的问题,比如,手机屏幕黑了,手机老是提示电池电量不足之类的。

串口通信

  在C#中要实现串口通信,很多人都不知所措,在论坛上经常可以看到"怎么用MSCOMM实现串口通信""怎样能过串口与设备相连"诸如此类的问题。其实国外的网友早就把这些列入FAQ中了。

  通常,在C#中实现串口通信,我们有四种方法:

  第一:通过MSCOMM控件这是最简单的,最方便的方法。可功能上很难做到控制自如,同时这个控件并不是系统本身所带,所以还得注册,不在本文讨论范围。可以访问http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=320 ,一个国外网友的写的教程,作者很热心,我曾有发邮件给他,很快就回复了。

  第二:微软在.NET新推出了一个串口控件,基于.NETP/Invoke调用方法实现,详细的大家可以访问微软网站http://msdn.microsoft.com/msdnmag/issues/02/10/NETSerialComm/default.aspx,方便得到更多资料。

  第三:就是用第三方控件啦,可一般都要付费的,不太合实际,不作考虑

  第四:自己用API写串口通信,这样难度高点,但对于我们来说,可以方便实现自己想要的各种功能

  在本文,我们采用第四种方法来实现串口通信,不过不是自己写,用一个国外网友现成的已经封装好的类库,不过功能简单点,相对我们来说已经够用了。

  在整个终端短信的操作过程中,与串口的通信,只用到了四个功能,打开、写、读、关闭串口。下面是类库对这四个功能的定义:

  打开串口:

  函数原型:public void Open()

  说明:打开事先设置好的端口

  示例:

using JustinIO;

static JustinIO.CommPort ss_port = new JustinIO.CommPort();
ss_port.PortNum = COM1; //
端口号
ss_port.BaudRate = 19200; //
串口通信波特率
ss_port.ByteSize = 8; //
数据位
ss_port.Parity = 0; //
奇偶校验
ss_port.StopBits = 1;//
停止位
ss_port.ReadTimeout = 1000; //
读超时
try
{
 if (ss_port.Opened)
 {
  ss_port.Close();
  ss_port.Open(); //打开串口
 }
 else
 {
  ss_port.Open();//打开串口
 }
 return true;
}
catch(Exception e)
{
 MessageBox.Show("错误:" + e.Message);
 return false;
}


  写串口:

  函数原型:public void Write(byte[] WriteBytes)

  WriteBytes 就是你的写入的字节,注意,字符串要转换成字节数组才能进行通信

  示例:

ss_port.Write(Encoding.ASCII.GetBytes("AT+CGMI\r")); //
获取手机品牌

  读串口:

  函数原型:public byte[] Read(int NumBytes)

  NumBytes 读入缓存数,注意读取来的是字节数组,要实际应用中要进行字符转换

  示例:

string response = Encoding.ASCII.GetString(ss_port.Read(128)); //
读取128个字节缓存

  关闭串口:

  函数原型:ss_port.Close()

  示例:

ss_port.Close();

  由于篇幅,以及串口通信涉及内容广泛,我在这里只讲这些。

  在上面我们已经把终端短信所需的各种原始技术有所了解,是可以小试牛刀的时候了。

实践篇

  在整个开始的时候,你要准备以下软硬件:

   硬件:西门子3508C35系列手机一个
   西门子手机通信数据线一条
   软件:VS.NETC#
   短信编码类库(PDUdecoding.cs
   串口通信类库(JustinIO.cs

  当所要求的软硬件都准备好后,我们就可以正式开始了。下面以我自己的测试用例为大家详细介绍。

 
  做什么事情都应该有计划,虽然我们的测试用例很简单,但还是画个简单的流程图:



  有了流程图,还只是明白了程序怎么运行,再看看界面,会让你更心动的了。


图二、短信终端C#版界面图

  再不开始,就有人骂我了。下在我讲的开发环境是在VS.NET(C#)中。COME GO,GO…

  步骤一、打开VS.NET,新建项目-Visual C#项目-Windows应用程序,名称中输入你的工程名就行啦,我的是smsForCsharp

  步骤二、参照上面的界面图,设计你的程序界面,下面是我程序中各控件的主要属性

控件名称

控件Name属性

说明

TextBox

targetNumber

接收手机号码

TextBox

CenterNumber

短信中心号

TextBox

smsState

发送短信后,返回的信息。注意设置控件为多行

TextBox

smsContent

短信内容,同样,注意设置为多行

ComboBox

ConnectPort

连接手机的端口,例:COM1\COM2

ComboBox

ConnectBaudRate

串口连接的波特率,在串口通信中很重要的

Button

btnSend

发送按钮

Button

btnConnect

连接按钮,主要用于程序的初始化

Button

btnExit

退出按钮


  步骤三、将PDUdecoding.csJustinIO.cs拷入刚刚新建工程目录,并打开解决方案资源管理器,右键添加现有项,选中两个文件就行了,这里再打开类视图,里面是不是多了两个类,JustinIOSMS类啊,如图三,要是没有,那你再试。


图三,添加类后的类视图

  步骤四、引用命名空间,用代码查看方式打开Form1.cs(这里以我电脑为准,如果你自己更改过,请以你电脑为准),在代码前面加上

using JustinIO;
using SMS;
using System.IO;
using System.Text;


  步骤五、在smsFormCsharp类中,添加两个字段ss_portsms,分别为JustinIOSMS的对象,如下



  步骤六、添加串口初始化代码,如下:

/// summary
///
初始化串口
///
/summary
public bool InitCom(string m_port, int m_baudrate)
{
 ss_port.PortNum = m_port;//串口号
 ss_port.BaudRate = m_baudrate;//波特率
 ss_port.ByteSize = 8;//数据位
 ss_port.Parity = 0;//
 ss_port.StopBits = 1;//停止位
 ss_port.ReadTimeout = 1000;//读超时
 try
 {
  if (ss_port.Opened)
  {
   ss_port.Close();
   ss_port.Open();
  }
  else
  {
   ss_port.Open();//打开串口
  }
  return true;
 }
 catch(Exception e)
 {
  MessageBox.Show("错误:" + e.Message);
  return false;
 }
}


  将上述代码直接拷入你的程序中,并确保添加在Main主函数的后面,按F5,调试应该没什么问题,不过上面还没有实际任何看得见的功能,仅仅是打开了串口而以。

  步骤七、打开串口后,我们就应该初始化程序,取得手机的名牌,型号,以及短信中心号,双击连接按钮,并把下面代码拷入程序中:

/// summary
///
初始化代码,并获取手机相关信息
///
/summary
///
param name="sender"></param
///
param name="e"></param
private void btnConnect_Click(object sender, System.EventArgs e)
{
 bool opened = InitCom(ConnectPort.SelectedItem.ToString(),Convert.ToInt32(ConnectBaudRate.SelectedItem.ToString()));//打开并初始化串口
 bool Connected = false;
 if (opened)
 {
  ss_port.Write(Encoding.ASCII.GetBytes("AT+CGMI\r")); //获取手机品牌
  string response = Encoding.ASCII.GetString(ss_port.Read(128));
  if (response.Length 0)
  {
   ConnectState.Text = response.Substring(10,7);
   Connected = true;
  }
  else
  {
   ConnectState.Text = "与手机连接不成功";
   Connected = false;
  }
  ss_port.Write(Encoding.ASCII.GetBytes("AT+CGMM\r"));//获取手机型号
  response = Encoding.ASCII.GetString(ss_port.Read(128));
  if(response.Length 0)
  {
   ConnectState.Text =ConnectState.Text+ " " + response.Substring(10,5) + " 连接中......";
   Connected = true;
  }
  else
  {
   ConnectState.Text = "与手机连接不成功";
   Connected = false;
  }
  ss_port.Write(Encoding.ASCII.GetBytes("AT+CSCA?\r"));//获取手机短信中心号
  response = Encoding.ASCII.GetString(ss_port.Read(128));
  if(response.Length 0)
  {
   CenterNumber.Text = response.Substring(20,13);
   Connected = true;
  }
  else
  {
   Connected = false;
  }
  if (Connected == true)
  {
   btnConnect.Enabled = false;
   btnSend.Enabled = true;
  }
  else
  {
   btnConnect.Enabled = true;
   btnSend.Enabled = false;
  }
 }
}


  到这里,你可以按F5,编译调试,通过,在确保你的手机与电脑连接正常下,点击连接按钮看看,是不是像我的一样,手机型号及短信中心号者正常显示出来了。


图四、连接后程序界面

  步骤八、看到上在的结果,是不是感觉到离成功发送短信很近啦,看这么长的文章,费了大家不少时间,再不亮出发短信部份,对不起大家了。

  双击发送按钮,将下面代码拷入程序中。

/// summary
///
发送短信
///
/summary
///
param name="sender"></param
///
param name="e"></param
private void btnSend_Click(object sender, System.EventArgs e)
{
 string decodedSMS = sms.smsDecodedsms(CenterNumber.Text,targetNumber.Text,smsContent.Text);
 byte[] buf =Encoding.ASCII.GetBytes(String.Format("AT+CMGS={0}\r",sms.nLength));
 ss_port.Write(buf);
 string response = Encoding.ASCII.GetString(ss_port.Read(128));
 string SendState = "";
 if( response.Length 0 && response.EndsWith(" "))
 {
  ss_port.Write(Encoding.ASCII.GetBytes(String.Format("{0}\x01a",decodedSMS)));
  SendState = "发送成功!";
 }
 else
 {
  SendState = "发送失败";
 }

 string Result = String.Format("{0},{1},{2}\n\r",targetNumber.Text,smsContent.Text,SendState);
 smsState.Text += Result;
}


  快按F5!神啊,快通过吧!不用求神了,已经通过了,现在你就可以发短信了,请确保手机可以正常连接电脑。按连接,然后填入你要的发送的目标手机号,并在内容中添入你要发送的内容,发送吧!成功了!成功了是这样子的!看你的跟我的一样吗?


图五、发送成功

  还有一些事 不要忘了,记得添加退出代码。双击退出,添加下面代码:

/// summary
///
关闭串口,退出程序
///
/summary
///
param name="sender"></param
///
param name="e"></param
private void btnExit_Click(object sender, System.EventArgs e)
{
 ss_port.Close();
 Application.Exit();
}


  到这里都告一个段落了,所有的功能都完成了!不过由于这仅仅是一个演示用例,还有很多没有考虑,像串口通信中的,在实际操作不可这样操作的,应该用多线程来处理,一个专门用来读串口,一个专门用来写串口。还有程序中很多防出错代码没有添加进去,希望有心有朋友添加,并公布出来,这也是我写这篇文章希望看到的结果。请勿将本程序直接用于实际中,真诚提醒你!

  终于写完了,我也放松了许多,本来很早就应该完成了,因为一些个人原因,没有及时写完,向那些曾经问过我相关问题,没有及时回复的朋友,抱歉一声,希望你们继续支持我!

  调试环境

  Windows 2000 ProfessionalVisual Studio.NET、西门子3508手机、西门子专用数据线。

常见问题

  第一, 手机品牌,因为不同产商的手机,对AT指令的支持不同,所以请选择适合你手机AT指令,像NOKIA的就只能用TEXT模式的AT指令。

  第二, 数据线,问题出得最多的地方也就是数据,如果接上数据线后,你的手机显示为黑屏,建议你换数据线。

  第三, 手机SIM卡上的短信中心号设置,请确保在你的手机上可以发送短信。

  第四, 请你先用串口调试工具调试手机与电脑的连接,这样对你整个工作都是一个保证。

 

在服务器建立一个简单的数据,发送短信的程序运行在服务器上,循环检测数据库中是否有未发短信,有的话,就发送。
客户端要有输入短信的内容,完成后把数据插入数据库,当然是以未发的状态保存的。这样服务器端的程序只要检测到有未发送的短信程序就会自动发送了。这样所有的客户端就可以通过一个GSM Modem发送短信了。
服务器端的程序可以通过AT指令从COM口和红外端口来执行,如果不想太麻烦的话,可以试试我的可以发送文字、图片、铃声,打电话的ActiveX控件喽。参考:www.gebon.com/sms

 

下面是发送SMS消息核心代码。首先需要定义一些微软Windows API

l
一个API打开SMS消息组件

l
一个API发送SMS消息

l
一个API关闭SMS消息组件

Public Declare Function SmsOpen Lib "SMS" (ByVal ptsMessageProtocol
As String, ByVal dwMessageModes As Long, ByRef psmshHandle As
Long, ByRef phMessageAvailableEvent As Long) As Long

Public Declare Function SmsSendMessage Lib "SMS" (ByVal smshHandle
As Long, ByVal psmsaSMSCAddress As Long, ByVal
psmsaDestinationAddress As String, ByVal pstValidityPeriod As
Long, ByVal pbData As String, ByVal dwDataSize As Long, ByVal
pbProviderSpecificData As String, ByVal dwProviderSpecificDataSize
As Long, ByVal smsdeDataEncoding As Long, ByVal dwOptions As Long,
ByRef psmsmidMessageID As Long) As Long

Public Declare Function SmsClose Lib "SMS" (ByVal smshHandle As Long) As Long



你也需要为不同的API声明一些API常数:

Public Const SMS_MSGTYPE_TEXT = "Microsoft Text SMS Protocol"
Public Const SMS_MODE_SEND = 2 '
用发送模式打开
Public Const SMSDE_GSM = 1 '
使用标准GSM
encoding
Public Const SMSAT_INTERNATIONAL = 1 '
国际号码
format
Public Const PS_MESSAGE_OPTION_NONE = 0 '
没有消息选项
Public Const PS_MESSAGE_CLASS0 = 0 '
立即发送
Public Const PSRO_NONE = 0 '
没有更替
Public Const SMS_OPTION_DELIVERY_NONE = 0 '
没有发送选项



下面是发送SMS消息的完整代码:

Public Sub SendSMS(ByVal Number As String, ByVal Message As String)

Dim SMSHandle As Long
Dim SMSEvent As Long
Dim SMSAddress As String
Dim SMSProvider As String

'
打开SMS消息组件
Call SmsOpen(SMS_MSGTYPE_TEXT, SMS_MODE_SEND, SMSHandle, SMSEvent)

'
设置地址结构体
SMSAddress = LongToBytes(SMSAT_INTERNATIONAL) & Number

'
设置提供者结构体
SMSProvider = LongToBytes(PS_MESSAGE_OPTION_NONE) & _
LongToBytes(PS_MESSAGE_CLASS0) & _
LongToBytes(PSRO_NONE)

'
发送消息
If 0 = SmsSendMessage(SMSHandle, 0, SMSAddress, 0, Message, _
LenB(Message), SMSProvider, 12, SMSDE_GSM, _
SMS_OPTION_DELIVERY_NONE, 0) Then
MsgBox "Message sent!", vbInformation, App.Title
Else
MsgBox "Could not send message!", vbCritical, App.Title
End If

'
关闭SMS消息组件
Call SmsClose(SMSHandle)

End Sub