Arduino中一种变通的发送固定格式中文短信的方法:以DHT22+GSM模块为例

假设有这么个需求,用DHT22定时检测温湿度,将结果用GSM模块发送到指定的手机。

对Arduino来说,用DHT22检测温湿度不是件难事;通过芯片串口发送GSM AT指令也很容易实现。最关键的技术点是如何在Arduino下编码明文的短信内容到PDU。但这个工作并非Arduino的强项。网上找了些文章,实现起来太过复杂。

出于简化代码的考虑,是否可以将待发送短信内容通过其它手段预先存成“模板”,发送时只替换部分内容呢?

比如,我们规定短信格式只能是:

温度:12.3 ℃;湿度:45.6

(其中只有温度值和湿度值能根据实际测量值动态改变,且这些数值都不可以为负数。强制保留一位小数,整数部分取值范围0-99)

先自己用C#编写一段代码生成这条短信:(为了阅读方便加了空格,实际上是没有的)
089168 BADCFEHGJIFK 11000D9168 badcfehgjiFk 0008FF 26 6E295EA6FF1A 0031 0032 002E 0033 00202103FF1B6E7F5EA6FF1A 0034 0035 002E 0036 0020FF05
53

稍微解释下标粗的那些部分。“BADCFEHGJIFK”是指编码后的短信中心号码,“badcfehgjiFk”是指编码后的接收方手机号码。原始的中心号码为ABCDEFGHIJK(11位,无需86前缀),原始的接收手机是abcdefghijk(也是11位,同样无需86前缀)。编码规则很简单,如果手机号码长度是单数,最后加F,然后两位一组,奇数位和偶数位位置互换。ABCD就变成了BADC。举例:上海联通短信中心号码是13010314500,所以编码后就是3110304105F0,实际发送时就用这串文字代入。

53是等下发送at+cmgs=XX指令时需要用到的,示例短信中,经计算这个值就是53。当温度和湿度的整数部分都是个位数的时候这个值是49,一个个位数一个两位数则为51。另一个需要注意的是0008FF后面的26(用户信息长度)。当温度和湿度的整数部分都是个位数的时候为22,一个个位数一个两位数则为24。

剩下的就好办了。注意到0031 0032 002E 0033和0034 0035 002E 0036。在本文的例子中可以看作就是一个简单粗暴的替换关系。0030对应“0”,0031对应“1”,0032对应“2”。。。以此类推,0039对应“9”。002E对应小数点。因此这个就是编码后的12.3和45.6。

这样短信的大体框架就能定了,实际内容也能按数值定制,接下来就可以走串口发送了。

AT+CSCS="GSM"
成功返回“OK”
AT+CMGF=0
成功返回“OK”
AT+CMGS=长度
成功返回“> ”(大于号空格)
此时就可以发送PDU格式的消息了,最后发送0x1A作为终结符。成功返回OK,整个过程结束。

作为测试,本文假设每次串口发送都是会成功的,先不管返回值无脑直接发。

// DHT sensor library by Adafruit
// 库管理中搜索上述库,安装后直接使用
#include "DHT.h"

#define DHT22_PIN A0  // DHT22的数据线接A0
#define DHTTYPE DHT22
#define LEDPIN 13

DHT dht(DHT22_PIN, DHTTYPE);

String codedCenterNumber = "3110304105F0"; // 编码后的上海联通
String codedMPNumber = "31********F0";     // 编码后的接收短信手机号码

void setup() {

  pinMode(LEDPIN, OUTPUT);
  digitalWrite(LEDPIN, HIGH);

  dht.begin();

  // 亮5.5秒灯以示正在初始化
  // 然后灭灯
  Serial.begin(115200, SERIAL_8N1);
  delay(5000);
  Serial.println("at");
  delay(500);
  Serial.flush();

  digitalWrite(LEDPIN, LOW);

}

int i = 0;

void loop() {

  if (i == 1)
  {
    float t = dht.readTemperature();
    float h = dht.readHumidity();
    SendSMS(t, h);
  }

  i++;
  // 修改此判断数值以改变发送频次
  if (i == 60)
    i = 1;

  delay(60000);

}

// =======================
void SendSMS(float tVal, float hVal)
{

  String cmgs = "";
  String smsPDU = "";
  if (tVal < 10.0 && hVal < 10.0)
  {
    cmgs = "AT+CMGS=49";
    smsPDU = GetPDU(codedCenterNumber, codedMPNumber, GetPDUFormatValue(tVal), GetPDUFormatValue(hVal), "22");
  }

  if (tVal >= 10.0 && hVal >= 10.0)
  {
    cmgs = "AT+CMGS=53";
    smsPDU = GetPDU(codedCenterNumber, codedMPNumber, GetPDUFormatValue(tVal), GetPDUFormatValue(hVal), "26");
  }

  if ((tVal < 10.0 && hVal >= 10.0) || (tVal >= 10.0 && hVal < 10.0))
  {
    cmgs = "AT+CMGS=51";
    smsPDU = GetPDU(codedCenterNumber, codedMPNumber, GetPDUFormatValue(tVal), GetPDUFormatValue(hVal), "24");
  }

  digitalWrite(LEDPIN, HIGH);

  Serial.println("AT");
  delay(500);
  Serial.flush();

  Serial.println("AT+CSCS=\"GSM\"");
  delay(500);
  Serial.flush();

  Serial.println("AT+CMGF=0");
  delay(500);
  Serial.flush();

  Serial.println(cmgs); //
  delay(500);
  Serial.flush();


  Serial.print(smsPDU);
  delay(500);
  Serial.flush();


  Serial.write(0x1a);
  delay(500);
  Serial.flush();


  digitalWrite(LEDPIN, LOW);

}

/*
// 如您喜欢,可以直接拨打手机
// 当然,通话是不可能通话的
void CallMP(String MP)
{
  digitalWrite(LEDPIN, HIGH);

  Serial.println("at");
  delay(500);
  Serial.flush();
  Serial.println("atd" + MP);
  delay(500);
  Serial.flush();

  digitalWrite(LEDPIN, LOW);
}
*/


// 短信中心和手机号码都不需要加86前缀
String GetPDU(String codedCenterNumber, String codedMpNumber, String tValue, String hValue, String len)
{
  String rtn = "";
  rtn += "089168";
  rtn += codedCenterNumber;
  rtn += "11000D9168";
  rtn += codedMpNumber;
  rtn += "0008FF" + len + "6E295EA6FF1A";
  rtn += tValue;
  rtn += "00202103FF1B6E7F5EA6FF1A";
  rtn +=  hValue;
  rtn +=  "0020FF05";
  return rtn;
}

// 数值转变为PDU需要的形式
String GetPDUFormatValue(float val)
{
  String rtn = "";
  String v = String(val, 1);

  for (int i = 0; i < v.length(); i++)
  {
    char c = v.charAt(i);
    switch (c)
    {
      case '0':
        rtn += "0030";
        break;
      case '1':
        rtn += "0031";
        break;
      case '2':
        rtn += "0032";
        break;
      case '3':
        rtn += "0033";
        break;
      case '4':
        rtn += "0034";
        break;
      case '5':
        rtn += "0035";
        break;
      case '6':
        rtn += "0036";
        break;
      case '7':
        rtn += "0037";
        break;
      case '8':
        rtn += "0038";
        break;
      case '9':
        rtn += "0039";
        break;
      case '.':
        rtn += "002E";
        break;
      default:
        break;
    }

  }
  return rtn;
}

最终效果如图:

发布了122 篇原创文章 · 获赞 61 · 访问量 53万+

猜你喜欢

转载自blog.csdn.net/ki1381/article/details/98068013