dvd1478 发表于 2015-1-24 23:17:42

Nucleo开发板方案设计——GSM/GPRS

本帖最后由 dvd1478 于 2015-2-2 14:10 编辑

GSM 的英文是 GlobalSys-temForMobileCommunica-tion,即全球移动通信系统,由欧洲标准化委员会设计提出。GSM 系统具有防盗拷贝能力佳、网络容量大、号码资源丰富、 通话清晰、稳定性强不易受干扰、信息灵敏、通话死角少、手机耗电量低等特点。我国自 1994 年底开始建设 GSM 蜂窝移动通信网,其发展势头世人皆叹。目前,中国移动通信拥有世界上网络 规模最大和客户数量最多的GSM移动通信网。
    GPRS 是GeneralPacketRadioService 的英文简称,中文为通用无线分组业务。它具有实时在线、按 量计费、快捷登录、高速传输、自如切换的优点。使用 GPRS 上网的方法与 WAP 不同, 用WAP上网就如在家中上网,先“拨号连接”,上网后便不能同时使用该电话线,但用 GPRS 下载资料和通话可以同时进行,即通话继续使用 GSM,而数据的传送便可使用 GPRS。
    我们可以简单地理解成为:GSM 是手机语音通话网络,就是打电话发短信的网络;而GPRS 是用手机上网收发数据的网络! 在紧急呼叫机与现下很流行的物联网通讯都有广泛的应用。紧急呼叫机是GSM功能的应用,而物联网是一般都是GPRS的应用。
    这里主要是针对这两个功能进行学习与开发,另外一方向是学习mbed的开发的思想。mbed的开发思想是抛开硬件底层,从而面对类的开发。所用的就是C++/C的开发。


    而有选用的是SIM900A模块,SIM900A 模块板载 SIMCOM 公司的工业级双频GSM/GPRS 模块:SIM900A,工作频段双频:900/1800Mhz,可以低功耗实现语音、SMS(短 信,不支持彩信)、数据和传真信息的传输。 SIM900A 模块支持 RS232 串口和 LVTTL 串口(即支持 3.3V/5V 系统),并带硬件流控制,支持5V~24V的超宽工作范围,使得本模块可以非常方便的与您的产品进行连接,从而给您的产品提供包括语音、短信和GPRS数据传输等功能。


    (1)我是淘宝上选择SIM900A模块,选择时注意不要选太贵的,不值,就算把所有功能引出来,确实方面全方面的学习,但实际上大多数的产品,依我所了解,大都数都是GSM与GPRS的应用。不要选太便宜的,在这方面我就吃过亏了,在功率上并没有处理好或者是信号处理不好,给调试上带我了很大的麻烦。 SIM900A地收发时的瞬间功耗还是很大的,电源上做一些处理,如添加大电容等等。当然初期,调试时可以选择外置电源,这样给给调试带来方便。
   
    (2)判断接线有没问题,其实用一个很简单的方法即可。就是电脑 串口 <===> NucleoF072RB<===> SIM900A串口,Nucleo 在中间只做一个转发的功能即。在mbed这方面却,做得很方面啦,就是关键的几句即可。
Serial serial(SERIAL_TX, SERIAL_RX);//<span style="color: rgb(0, 0, 0); font-family: 微软雅黑; background-color: rgb(255, 255, 255);">串口 <===> NucleoF072RB</span>
GPRSInterface eth(PA_0, PA_1, 115200, "apn", "username", "password");//<span style="color: rgb(0, 0, 0); font-family: 微软雅黑; background-color: rgb(255, 255, 255);">NucleoF072RB</span><span style="color: rgb(0, 0, 0); font-family: 微软雅黑; background-color: rgb(255, 255, 255);"> </span><span style="color: rgb(0, 0, 0); font-family: 微软雅黑; line-height: 1.5; background-color: rgb(255, 255, 255);"><span style="background-color: inherit;"> </span><===><span style="background-color: inherit;"> SIM900A串口</span></span>
int main()
{
    wait(3);
bool flag = eth.init();
   
    while(1){
<font color="#ff0000">      while(eth.serialModem.readable()){
            serial.putc(eth.serialModem.getc());</font>
            }
<font color="#ff0000">      while(serial.readable()){
            eth.serialModem.putc(serial.getc());</font>
            }
      }
}          (3) 就是SIM900A是自动识串口的波特率的,2400~115200 ,但较高波特率时,要多发几次 AT 命令,并且要有一定的延时。
bool GPRS::preInit()
{
    for(int i = 0; i < 2; i++) {
      sendCmd("AT\r\n");
      wait(1);
    }
   
    if(0 != sendCmdAndWaitForResp("AT\r\n","OK",DEFAULT_TIMEOUT,CMD)){
    return false;
   
    }
    if(0 != checkSIMStatus()) {
      return false;
    }
   
    return true;

还有很多的心理,不一一写上来的。写代码的,在这方面我还是菜鸟,这里只是显显羞罢了,有什么不足请大家狠狠拍砖。


以下说一下我学习mbed后的思想


Serial 是SIM900A的接口,继承了Serial类,是其子类。代码上只要以下书写即可
<font color="#000000">class Modem</font>
<font color="#000000">{</font>

<font color="#000000">public:</font>
<font color="#000000">    /**      Create Modem Instance</font>
<font color="#000000">   *@param tx      uart transmit pin to communicate with Modem</font>
<font color="#000000">   *@param rx      uart receive pin to communicate with Modem</font>
<font color="#000000">   *@param baudRate      baud rate of uart communication</font>
<font color="#000000">   */</font>
<font color="#ff0000">    Modem(PinName tx, PinName rx, int baudRate) : serialModem(tx, rx) </font><font color="#000000">{</font>
<font color="#000000">      serialModem.baud(baudRate);</font>
<font color="#000000">    };</font>
      
<font color="#ff0000">      Serial serialModem;</font>
<font color="#000000">protected:</font>
   
。。。。。。。。。。。
<font color="#000000">private:</font>

<font color="#000000">};</font>
把低层的接口封装至modem 类中,而上层的GSM 、GPRS继承了modem类。以下书写即可 ,即能
<font color="#ff0000">class GPRS: public Modem</font>
{
。。。。。。。。。。。
}

GSM 功能已经调试好,而GPRS 还在调试中,好像参赛方案提交的时间快到,我针对GSM功能,做一个简单的紧急呼叫机,设计的思法是这样,任何的操作都有一个按键,拨打接听都是一个按键,保持着 “keep it simple stupid”的思法。






程序流程图


写得很匆忙,C++也是现学现用的,说错的地方,请大学指点指点。方案做得不怎么好,请大学原谅!~

贴了我调试时的代码片段
一、呼叫测试代码
#if 1
/*call up*/
    bool flag = eth.init();
    CallAnswer callFlag = CallWait;
    if (flag != NULL) {
      printf(">>> Could not initialise. Halting!\n");
      exit(0);
    }
   
    printf("Call the number \r\n");
    eth.callUp("1008611");
   
    while(1){
      callFlag =eth.callWaitAsk();
      switch(callFlag){
            case CallOk:
                printf("\r\n Is Calling \r\n");
                //printf("\r\n正在呼叫\r\n");
                break;
            case CallBusy:
                printf("\r\n You dial telephone is on the phone, please later again dial \r\n");
                //printf("\r\n你拨打的电话正在通话中,请稍后再拨\r\n");
                break;
            case CallNoAnswer:
                printf("\r\nYou dial telephone temporarily no man answer, please later again dial \r\n");
                //printf("\r\n你拨打的电话暂时无人接听,请稍后再拨\r\n");
                break;
            case CallNoCarrier:
                printf("\r\nEnd of the conversation\r\n");
                //printf("\r\n通话结束\r\n");
                break;
            default:
                printf("\r\n In the middle of, please wait \r\n");
                //printf("\r\n正中进行,请等待\r\n");
                break;
            } // end switch(callFlag)
            wait(1);
      }
#endif二、发短信测试代码
(这里发了很长时间,原本是自动判断中英文发送的,但是UNICODE GBK双向转换码 即占用很大部分的ROM空间,后面没有使用mbed开法,却没有超出。我想应该是c++占用了很大的ROM空间,最后还是选择舍去了中文的短信的发送,因为这里主要是学习mbed开发的思想)
#if 1
#define PHONE_NUMBER "186****2964"
#define MESSAGE"hello,world"
/* send message*/
    bool flag = eth.init();
    if (flag != NULL) {
      printf(">>> Could not initialise. Halting!\n");
      exit(0);
    }
   
    printf("start to send message.... \r\n");
   
    eth.sendSMS(PHONE_NUMBER,MESSAGE);
   
    exit(0);
#endif读短信
#if 1
/* read message */
#define MESSAGE_LENGTH 160
char message;
int messageIndex = 0;
char phone;
char datetime;
while(1){
      messageIndex = eth.isSMSunread();
      if (messageIndex > 0) { //At least, there is one UNREAD SMS
          eth.readSMS(messageIndex, message, MESSAGE_LENGTH, phone, datetime);         
          //In order not to full SIM Memory, is better to delete it
          eth.deleteSMS(messageIndex);
          serial.printf("From number: %s \r\n",phone);
          serial.printf("Datetime: %s \r\n",datetime);   
          serial.printf("Recieved Message:\" %s \"\r\n",message);
      }
    }
#endif
四、自动接电话与读短信
#if 1
/*Loop Handle */
    bool flag = eth.init();
    CallAnswer callFlag = CallWait;
    if (flag != NULL) {
      printf(">>> Could not initialise. Halting!\n");
      exit(0);
    }
   
    printf("Call the number \r\n");
   
    while(1){
      callFlag = eth.callWaitAsk();
      switch(callFlag){
            case CallRing:
                eth.answer();               
                break;
            case CallSM:
                #define MESSAGE_LENGTH 160
                char message;
                int messageIndex = 0;
                char phone;
                char datetime;
                messageIndex = eth.isSMSunread();
                if (messageIndex > 0) { //At least, there is one UNREAD SMS
                  eth.readSMS(messageIndex, message, MESSAGE_LENGTH, phone, datetime);         
                  //In order not to full SIM Memory, is better to delete it
                  eth.deleteSMS(messageIndex);
                  serial.printf("From number: %s \r\n",phone);
                  serial.printf("Datetime: %s \r\n",datetime);   
                  serial.printf("Recieved Message:\" %s \"\r\n",message);
                }
                break;
            default:
                break;
            } // end switch(callFlag)
            wait(1);
      }
#endif

五、紧急呼叫机
#if 1
const char num[]="551";
bool flag = eth.init();
CallAnswer callFlag = CallWait;
if (flag != NULL) {
    printf(">>> Could not initialise. Halting!\n");
    exit(0);
}
flag = false;
while(1){
      callFlag = eth.callWaitAsk();
      switch(callFlag){
            case CallRing:
                if( mybutton )
                {
                  eth.answer();
                  flag = true;
                  while(flag == true)
                  {
                        wait(1);
                        callFlag = eth.callWaitAsk();
                        if(CallNoCarrier==callFlag)
                            flag = false;      
                  }//end while(flag == true)
                }//end if( mybutton )         
                break;
            case CallSM:
                #define MESSAGE_LENGTH 160
                char message;
                int messageIndex = 0;
                char phone;
                char datetime;
                messageIndex = eth.isSMSunread();
                if (messageIndex > 0) { //At least, there is one UNREAD SMS
                  eth.readSMS(messageIndex, message, MESSAGE_LENGTH, phone, datetime);         
                  //In order not to full SIM Memory, is better to delete it
                  eth.deleteSMS(messageIndex);
                  serial.printf("From number: %s \r\n",phone);
                  serial.printf("Datetime: %s \r\n",datetime);   
                  serial.printf("Recieved Message:\" %s \"\r\n",message);
                }
                break;
            default:
                break;
            } // end switch(callFlag)
            
            
            wait(1);
            if( mybutton ){
                eth.callUp((char *)num);
                  while(flag == true){
                        wait(1);
                        switch(callFlag){
                           
                        case CallOk:
                            //printf("\r\n正在呼叫\r\n");
                            if( mybutton )
                            {
                              eth.callDown();
                            }//end if( mybutton )
                            break;
                        case CallBusy:
                            //printf("\r\n你拨打的电话正在通话中,请稍后再拨\r\n");
                        case CallNoAnswer:
                            //printf("\r\n你拨打的电话暂时无人接听,请稍后再拨\r\n");
                            wait(10);
                            eth.sendSMS((char *)num,"Hello world!\r\n How are you ?\r\n");
                            break;
                        case CallNoCarrier:
                            //printf("\r\n通话结束\r\n");
                        default:
                            wait(1);
                            //printf("\r\n正中进行,请等待\r\n");
                            break;
                        } // end switch(callFlag)
                  }// end while(flag == true)
                }//end if( mybutton )
      }//end while(1)
   
   
   
#endif


SIM900A的库代码:


GPRS的功能还没有调试好,不好意思上传,迟些我搞个GIT 托管代码 才可以。

下一步计划就是做GPRS功能,实现TCP/IP,做一个远程读取现场温度。



==============================================================
以下为我收集的资料一起分享给大家。




上传了官方文档,链接 点击直达调试常用到的软件 传输门

拼命三郎 发表于 2015-1-25 02:30:51

谢谢分享,看来国内用到Arduino接口的很少。

holts1 发表于 2015-1-25 08:36:06

功耗有多大 ?

星辰一方 发表于 2015-1-25 09:05:46

一直也想弄这个GPRS远程,学习下,感谢分享!

fjjjnk1234 发表于 2015-1-25 12:53:38

感谢分享!顶一个

arm8686 发表于 2015-1-25 13:06:46

这模块在连网时的电流确实大。
在供电管脚旁边,得放上个大容量的钽电容,至少是 100uF,还好电压低,选择耐压为 6.3V 这一档的钽电容就可以。

数码小叶 发表于 2015-1-25 14:40:21

谢谢分享

dsjsjf 发表于 2015-1-25 20:28:20

学习,谢谢分享

我是酱油哥 发表于 2015-1-26 08:43:39


学习,谢谢分享

lkl0305 发表于 2015-1-26 20:19:02

多谢分享!:)
页: [1] 2 3
查看完整版本: Nucleo开发板方案设计——GSM/GPRS