使用GSM调制解调器发送英文短信(D-Link DWM-156)

时间:2015-02-04 07:39:06

标签: c# serial-port sms

我正在使用AT命令在C#.Net中开发GSM调制解调器(D-Link DWM-156)的应用程序。发送英文短信时遇到问题。  我试着发送“你好”,但是我在手机里收到了□□□□,或者......你好了。

serialPort1.DataBits = 8;
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
serialPort1.BaudRate = 9600;

serialPort1.DtrEnable = true;
serialPort1.RtsEnable = true;
serialPort1.DiscardInBuffer();
serialPort1.DiscardOutBuffer();


serialPort1.WriteLine("AT\r");
Thread.Sleep(2000);

serialPort1.WriteLine("AT+CMGF=1\r");
Thread.Sleep(1000);

serialPort1.WriteLine("AT+CMGS=\"09390149196\"\r")
Thread.Sleep(2000);

serialPort1.WriteLine("hello" + "\x1A");
Thread.Sleep(1000);

1 个答案:

答案 0 :(得分:1)

很少有修复(可能更多,但我不会看到完整代码)。

  • 不要使用WriteLine(),而是使用Write(),因为\r(单独)是命令行和结果代码终止符。
  • SerialPort.WriteLine()默认写入usASCII编码的字符串,但您的GSM调制解调器需要使用AT命令编码的字符串编码。将SerialPort.Encoding属性设置为特定编码并发送CSCS命令。您可以使用CSCS=? AT命令询问支持的编码。即使默认GSM应该适用,我也要避免隐含地依赖它。
  • 您无需等待每个命令,但必须等待调制解调器答案(检查OKERROR字符串)。

来自docs

  

命令行由三个元素组成:前缀,正文和终止字符。命令行前缀由字符" AT"组成。或" at" [...]终止字符可以通过用户选项(参数S3)选择,默认为CR。

在伪代码中:

void SendCommand(string command) {
    serialPort.Write(command + "\r");

    // Do not put here an arbitrary wait, check modem's response
    // Reading from serial port (use timeout).
    CheckResponse();
}

serialPort.DataBits = 8;
serialPort.Parity = Parity.None;
serialPort.StopBits = StopBits.One;
serialPort.BaudRate = 9600;
serialPort.DtrEnable = true;
serialPort.RtsEnable = true;
serialPort.Encoding = Encoding.GetEncoding("iso-8859-1");

serialPort.DiscardInBuffer();
serialPort.DiscardOutBuffer();

SendCommand("AT"); // "Ping"
SendCommand("AT+CMGF=1"); // Message format
SendCommand("AT+CSCS=\"PCCP437\""); // Character set

SendCommand("AT+CMGS=\"123456\"") // Phone number
SendCommand("hello" + "\x1A"); // Message

要检查响应(绝对避免任意等待!),您可以从这样的事情开始(原始未经测试的适应性,因此您可能需要一些调试,另请参阅this post):

AutoResetEvent _receive;

string ReadResponse(int timeout)
{
    string response = string.Empty;

    while (true)
    {
        if (_receive.WaitOne(timeout, false))
        {
            response += _port.ReadExisting();
        }
        else
        {
            if (response.Length > 0)
                throw new InvalidOperationException("Incomplete response.");
            else
                throw new InvalidOperationException("No response.");
        }

        // Pretty raw implementation, I'm not even sure it covers
        // all cases, a better parsing would be appreciated here.
        // Also note I am assuming verbose V1 output with both \r and \n.
        if (response.EndsWith("\r\nOK\r\n"))
            break;

        if (response.EndsWith("\r\n> "))
            break;

        if (response.EndsWith("\r\nERROR\r\n"))
            break;
    }

    return response;
}

在发送命令之前添加_receive.Reset(),当然还要添加OnPortDataReceived作为SerialPort.DataReceived事件的处理程序:

void OnPortDataReceived(object sender,
    SerialDataReceivedEventArgs e)
{
    if (e.EventType == SerialData.Chars)
        _receive.Set();
}

如果您遇到问题(但可以连接),可以将\r替换为\n。某些调制解调器错误(假设<CR>未使用13参数映射到S3以外的任何其他内容)默认情况下将此字符用作命令行终止符(即使它应该只出现在V1详细输出的输出中。您可以更改代码或发送相应的S3