AT指令控制GSM/GPRS模块上网连接服务器

现在已经是3G、4G的天下,但古老的GSM模式中有一个GPRS数据承载服务,是在2G网络下对上网需求的优化。


##GSM和GPRS## GSM是全球移动通讯系统Global System of Mobile communication,分属于2G通信。

GPRS是Gerneral Packer Radio Service的英文缩写,中文译为通用无线分组业务,具体来讲,GPRS是一项高速数据处理的科技,即以分组的“形式”把数据传送到用户手上。

GPRS是在GSM系统上发展出来的一种新的承载业务,目的是为GSM用户提供分组形式的数据业务。GPRS采用与GSM同样的无线调制标准、频带、突发结构、跳频规则以及同样的TDMA帧结构。

GPRS允许用户在端到端分组模式下发送和接收数据,而不需要利用电路交换模式的网络资源,从而提供了一种高效、低成本的无线分组数据业务。


##AT指令控制## 部分GPRS模块内置了TCP/IP协议栈,可以很方便的通过厂家扩展的AT指令直接进行TCP或UDP通信。

这是在RTOS(RT-Thread Operating System)里面的一段控制Zigbee模块用GPRS通信方式和服务器通信的代码:

    void thread_gsm_entry(void *parameter)
    {
    uint16_t i = 0;

    gsm_init_hw("uart3");

    rt_kprintf("gsm init hardware success \n");

    thread_gsm_at = rt_thread_create("gsm_at",
                                     thread_gsm_at_entry, RT_NULL,
                                     1024,
                                     10, 10);

    if (thread_gsm_at != RT_NULL)
    { rt_thread_startup(thread_gsm_at); }

    gsm_power_switch();
    rt_thread_delay(RT_TICK_PER_SECOND * 7);

    for (i = 0; i < 5; i++)
    {
        rt_device_write(gsm_dev, 0, "AT\r\n", strlen("AT\r\n")); //测试连接是否正确
        rt_thread_delay(RT_TICK_PER_SECOND * 1);
    }

    for (i = 0; i < 1; i++)
    {
        rt_device_write(gsm_dev, 0, "ATE1\r\n", strlen("ATE1\r\n")); //打开回显
        rt_thread_delay(RT_TICK_PER_SECOND * 1);
    }

    for (i = 0; i < 5; i++)
    {
        rt_device_write(gsm_dev, 0, "AT+CSQ\r\n", strlen("AT+CSQ\r\n")); //检查信号
        rt_thread_delay(RT_TICK_PER_SECOND * 1);
    }

    for (i = 0; i < 5; i++)
    {
        rt_device_write(gsm_dev, 0, "AT+CGREG?\r\n", strlen("AT+CGREG?\r\n"));//获取小区环境
        rt_thread_delay(RT_TICK_PER_SECOND * 1);
    }

    for (i = 0; i < 1; i++)
    {
        rt_device_write(gsm_dev, 0, "AT+CGATT?\r\n", strlen("AT+CGATT?\r\n"));
        rt_thread_delay(RT_TICK_PER_SECOND * 3); //激活
    }

    for (i = 0; i < 1; i++)
    {
        rt_device_write(gsm_dev, 0, "AT+CSTT\r\n", strlen("AT+CSTT\r\n"));
        rt_thread_delay(RT_TICK_PER_SECOND * 5);
    }

    for (i = 0; i < 1; i++)
    {
        rt_device_write(gsm_dev, 0, "AT+CIICR\r\n", strlen("AT+CIICR\r\n"));
        rt_thread_delay(RT_TICK_PER_SECOND * 5);
    }

    for (i = 0; i < 1; i++)
    {
        rt_device_write(gsm_dev, 0, "AT+CIFSR\r\n", strlen("AT+CIFSR\r\n"));
        rt_thread_delay(RT_TICK_PER_SECOND * 1);
    }

    rt_device_write(gsm_dev,
                    0,
                    "AT+CIPSTART=\"TCP\",\"202.201.1.49\",12345\r\n",
                    strlen("AT+CIPSTART=\"TCP\",\"202.201.1.49\",12345\r\n"));
    rt_thread_delay(RT_TICK_PER_SECOND * 5);

    rt_device_write(gsm_dev, 0, "AT+CIPSEND=6\r\n", strlen("AT+CIPSEND=6\r\n"));
    rt_thread_delay(RT_TICK_PER_SECOND * 3);

    rt_device_write(gsm_dev, 0, "DEMO\r\n", strlen("DEMO\r\n"));
    rt_thread_delay(RT_TICK_PER_SECOND * 5);

    gsm_inited = RT_TRUE;
    }

##AT指令步骤和作用##

AT指令的步骤和作用如下所示:

  • AT 测试连接是否正确
  • TE1 打开回显
  • AT+CSQ 返回值是信号质量,越大越质量越好。
  • AT+CGREG 可以查询GPRS状态 一般注册上运营商,附着GPRS都是自动进行 查询模块是否有注册网络
  • AT+CGATT 开机后,如果“AT+CGATT?”命令的返回值为1,说明SIM卡已经开通了GRPS服务
  • AT+CSTT 设置APN
  • AT+CIICR 激活移动场景
  • AT+CIFSR 获得本地IP地址
  • AT+CIPSTART="TCP","202.201.xx.xx",12345\r\n 建立TCP连接
  • AT+CIPSEND=6 开始发送数据,数据长度为6
  • 发送测试数据“DEMO\r\n”

##服务器端##

服务器采用CentOS操作系统,安装JVM。因为GPRS来的数据是TCP报文格式,可以采用Socket编程进行接收,接收到的数据可以插入到数据库中进行保存。这样就可以保存和检索传感器节点的采样数据。

Server端代码采用Java编写,很容易。

     import java.net.*;
    import java.io.*;
    public class Server
    {
    private ServerSocket ss;
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    public Server()
    {
    try
    {
    ss = new ServerSocket(12345);
    socket = ss.accept();
    in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    out = new PrintWriter(socket.getOutputStream(),true);
    while (true)
    {
    String line = in.readLine();
    System.out.println("Monitoring data :" + line);
    //out.close();
    // in.close();
    //socket.close();
    }
    ss.close();
    }
    catch (IOException e)
    {}
    }
    public static void main(String[] args)
    {
    new Server();
    }
    }

需要注意的是千万不要使用out.println,可能会阻塞通信。

socket = ss.accept()要放在while循环外面持续接收数据。

也不要关闭socket和in输入流。Zigbee传来的数据是一个每隔3S的数据流。

在此输入图片描述


##RTOS简介[1]##

RT-Threayd RTOS是一款来自中国的开源实时操作系统,由国内一些专业开发人员开发、维护。它不仅仅是一款高效、稳定的实时核心,也是一套面向嵌入式系统的软件平台,覆盖了全抢占的实时操作系统内核,小巧而与底层具体实现无关的文件系统,轻型的TCP/IP协议栈以及轻型的多窗口多线程图形用户界面。


##RTOS应用## 这个例子里面有三个任务(进程):一个是DEMO进程,一个是RF进程,一个是GSM进程。我们看看任务的写法:

    //设置和DEMO进程相关的堆栈、数据结构和声明相关的函数
    ALIGN(RT_ALIGN_SIZE)  //DEMO线程,点灯线程
    static rt_uint8_t demo_stack[ 2048 ];
    static struct rt_thread thread_demo; 
    extern void thread_demo_entry(void *parameter);

    ALIGN(RT_ALIGN_SIZE)  //RF线程,接收Zigbee分节点的数据,通过GPRS与Server Socket通信
    static rt_uint8_t rf_stack[ 2048 ];
    static struct rt_thread thread_rf;
    void thread_rf_entry(void *parameter);

    ALIGN(RT_ALIGN_SIZE)  //GSM线程,初始化GSM设置,初次通信,发送“DEMO”字符。
    static rt_uint8_t gsm_stack[ 2048 ];
    static struct rt_thread thread_gsm; 
    void thread_gsm_entry(void *parameter);

    int rt_application_init(void)
    {
    rt_err_t result;

    /* init demo thread */
    result = rt_thread_init(&thread_demo,
                            "demo",
                            thread_demo_entry,
                            RT_NULL,
                            (rt_uint8_t*)&demo_stack[0],
                            sizeof(demo_stack),
                            30,
                            5);
    if (result == RT_EOK)
    {
        rt_thread_startup(&thread_demo);
    }

    /* init rf thread */
    result = rt_thread_init(&thread_rf,
                            "rf",
                            thread_rf_entry,
                            RT_NULL,
                            (rt_uint8_t*)&rf_stack[0],
                            sizeof(rf_stack),
                            10,
                            5);
    if (result == RT_EOK)
    {
        rt_thread_startup(&thread_rf);
    }
    
    /* init gsm thread */
    result = rt_thread_init(&thread_gsm,
                            "gsm",
                            thread_gsm_entry,
                            RT_NULL,
                            (rt_uint8_t*)&gsm_stack[0],
                            sizeof(gsm_stack),
                            20,
                            5);
    if (result == RT_EOK)
    {
        rt_thread_startup(&thread_gsm);
    }
     return 0;
    }

##核心收据收发##

    if (gsm_inited)
            {
                rt_device_write(gsm_dev, 0, "AT+CIPSEND=", strlen("AT+CIPSEND="));
                rt_device_write(gsm_dev, 0, num_temp, strlen(num_temp));
                rt_device_write(gsm_dev, 0, "\r\n", strlen("\r\n"));

                rt_thread_delay(RT_TICK_PER_SECOND * 1);

                rt_device_write(gsm_dev, 0, data_temp, strlen(data_temp));

                rt_thread_delay(RT_TICK_PER_SECOND * 3);
            }

其中gsm_inited在GSM线程中被置位(gsm_inited = RT_TRUE),表明模块调试和初始化完毕,开始收发数据。

这是在RF线程(任务)中写的数据核心收发程序,data_temp中存储的是节点发来的数据, rt_device_write(gsm_dev, 0, data_temp, strlen(data_temp))使得数据传到服务器上。


##Reference##

[1].http://www.rt-thread.org/

[2].http://www.linuxidc.com/Linux/2012-09/69974.htm



Previous     Next
tuzhi /
Published under (CC) BY-NC-SA in categories Hardware  tagged with RTOS