STM32F103学习笔记(6)——4G Cat.1模块EC200S使用

一、简介

EC200S-CN 是移远通信最近推出的 LTE Cat 1 无线通信模块,支持最大下行速率 10Mbps 和最大上行速率 5Mbps,具有超高的性价比;同时在封装上兼容移远通信多网络制式 LTE Standard EC2x(EC25、EC21、EC20 R2.0、EC20 R2.1)和 EC200T/EG25-G/EG21-G 模块以及 UMTS/HSPA+ UC20/UC200T 模块,实现了 3G 网络与 4G 网络之间的无缝切换。EC200S-CN 还支持标准的 Mini PCIe 封装,以满足不同行业产品应用需求。

Quectel EC2x 模块具有嵌入式 TCP/IP堆栈,使主机可以通过 AT 命令直接上网。可以实现TCP客户端、UDP客户端、TCP服务器和UDP服务器。

ES200S资料:链接:https://pan.baidu.com/s/10PzjAjYqCM2sI1r-C6-7ww?pwd=gsux 提取码:gsux

二、AT指令

2.1 AT

测试AT指令功能是否正常,等待模块返回 OK。

AT

OK

2.2 AT + CPIN?

查询 SIM 卡状态,返回 READY 则表示SIM卡正常,如果 20 秒后还无法识别 SIM 卡,重新启动模块。

AT+CPIN?

+CPIN: READY

OK

2.3 AT + CREG?

查询模组是否注册上GSM网络,如果 90秒后未能在 CS 上注册域名服务,重新启动模块。
如果返回 1 或 5 ,代表 CS 服务注册成功。
+CREG:0,1 表示已注册上本地网,+CREG:0,5表示注册上漫游网。

AT+CREG?

+CREG: 0,1

OK

2.4 AT + CGREG?

查询模组是否注册上GPRS网络,+CGREG:0,1 表示已注册上本地网,+CGREG:0,5表示注册上漫游网。

AT+CGREG?

+CGREG: 0,1

OK

2.5 AT + QICSGP=1,1,“CMNET”

该命令可用于配置<APN>,<username>,<password>等TCP / IP上下文参数。QoS设置可以由AT + CGQMIN,AT + CGEQMIN,AT + CGQREQ和AT + CGEQREQ配置 。

  • AT+QICSGP=?:查询命令参数。
  • AT+QICSGP=<contextID>:查询 contextID的配置信息。
  • AT+QICSGP=<contextID>[,<context_type>,<APN>[,<username>,<password>)[,<authentication>]]]:配置 contextID信息。
    • <contextID>:整数类型。上下文ID。范围是1-16。
    • <context_type>:整数类型。协议类型。1(IPV4)、2(IPV4V6)。
    • <APN>:字符串类型。接入点名称。移动CMNET,联通UNINET
    • <username>:字符串类型。用户名。
    • <password>:字符串类型。密码。
    • <authentication>:整数类型。身份验证方法。0(没有)、1(PAP)、2(CHAP)、3(PAP或CHAP)。
    • 返回信息:OK 或 ERROR。
AT+QICSGP=1,1,\"CMNET\",\"\",\"\",1

OK

2.6 AT + QIDEACT=1

在激活GPRS场景之前先关闭GPRS场景,确保连接正确

AT+QIDEACT=1

OK

2.7 AT + QIACT=1

激活移动场景

AT+QIACT=1

OK

2.8 AT+QIOPEN

该命令用于打开套接字服务。

  • AT+QIOPEN=?:查询命令参数。
  • AT+QIOPEN=<contextID>,<connectID>,<service_type>,<IP_address>/<domain_name>,<remote_port>[,<local_po CONNECTrt>[,<access_mode>]] :打开 Socket 服务。
    • <contextID> :整数类型。上下文ID。范围是1-16。
    • <connectID> :整数类型。套接字服务索引。范围是0-11。
    • <SERVICE_TYPE>:字符串类型。套接字服务类型。
      • “ TCP ” :作为客户端启动TCP连接
      • “ UDP ”:作为客户端启动UDP连接
      • “TCP LISTENER” :启动TCP服务器以侦听TCP连接
      • “UDP SERVICE” :启动UDP服务
    • <IP_address>:字符串类型。
      • 如果<service_type>是TCP或UDP ,则表示远程服务器的IP地址,例如 “220.180.239.212”。
      • 如果<service_type>是TCP LISTENER或UDP SERVICE 地址,请输入“127.0.0.1”。
    • <domain_name>:字符串类型。远程服务器的域名地址。
    • <remote_port> :远程服务器的端口,仅在<service_type>为“TCP”或“UDP”时有效。范围是0-65535。
    • <LOCAL_PORT> :本地端口。范围是0-65535。
      • 如果<service_type>是“TCP LISTENER”或“UDP SERVICE”,则此参数必须指定。
      • 如果<service_type>是“TCP”或“UDP”。如果<local_port>为0,那么本地端口将是自动分配。否则,将按指定分配本地端口。
    • <access_mode> :整数类型。套接字服务的数据访问模式。
      • 0: 缓冲区访问模式
      • 1:直推模式
      • 2:透明访问模式
    • <err>:整数类型。操作的错误代码。请参阅第4章。
AT+QIOPEN=1,0,\"TCP\",\"180.97.81.180\",53540,0,1

OK

+QIOPEN: 0,0

Buffer模式,Push模式,透传模式。通过参数<access_mode>进行配置。





2.9 AT + QISEND

如果指定套接字服务的<access_mode>是缓冲区访问模式或直接推送模式,则数据可以是通过AT + QISEND发送。如果数据成功发送到模块,将返回“ SEND OK ” 。否则它将返回“ SEND FAIL ” 或“ ERROR ” 。“ SEND FAIL ” 表示发送缓冲区已满客户可以尝试重新发送数据。“ERROR”表示在发送过程中遇到错误 数据。客户应该延迟一段时间来发送数据。最大数据长度为1460字。“SEND OK”并不意味着数据已成功发送到服务器。客户可以查询数据是否通过AT + QISEND = <connectID>,0命令到达服务器。透传模式下不需要AT指令发送数据


三、TCP/IP AT命令拨号流程

四、复位模块

RESET_N 引脚可用于使模块复位。拉低 RESET_N 引脚至少 300 ms 后释放可使模块复位。RESET_N
信号对干扰比较敏感,因此建议在模块接口板上的走线应尽量的短,且需包地处理。


五、移植文件

5.1 board_ec200s.c

/*********************************************************************
 * INCLUDES
 */
#include "stdlib.h"
#include "string.h"
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h" 

#include "board_ec200s.h" 

uint8_t sendCmd(char *pCmd, char *pRes, uint32_t timeOut, uint8_t sendNum);
void clearBuffer(void);
void reset(void);

/*********************************************************************
 * GLOBAL VARIABLES
 */  
uint8_t g_usart2RecvFinish = 0;                                                 // 串口2接收标志串口接收完成标志
char g_ec200sBuf[1024] = {0};                                                   // 接收缓存
uint32_t g_ec200sCnt = 0;                                                       // 接收计数                               

/*********************************************************************
 * PUBLIC FUNCTIONS
 */
/**
 @brief 初始化
 @param 无
 @return 1 - 成功;0 - 失败
*/
uint8_t EC200S_Init(void)
{       
    printf("EC200S_Init\r\n");
    uint8_t result = 0;
    uint8_t step = 0;
    switch(step)
    {
        case 0:
            if(sendCmd("AT\r\n","OK", 10, 5))                                   // 测试AT指令功能是否正常
            {
                step++;
            }
            else
            {
                printf("Err:AT\r\n");
                reset();
                break;
            } 
        case 1:
            if(sendCmd("AT+CPIN?\r\n","+CPIN: READY", 20, 2))                   // 查询SIM卡是否正常,返回ready则表示SIM卡正常
            {
                step++;
            }
            else
            {
                printf("Err:AT+CPIN?\r\n");                                     // 20秒内,无法识别SIM状态,重启模块
                reset();
                break;
            }
        case 2:
            if(sendCmd("AT+CREG?\r\n","+CREG: 0,1", 90, 2))                     // 查询模组是否注册上GSM网络
            {
                step++;                                     
            }
            else
            {
                printf("Err:AT+CREG?\r\n");                                     // 90秒内,没有注册上CS业务,重启模块 
                reset();
                break;
            }
        case 3:
            if(sendCmd("AT+CGREG?\r\n","+CGREG: 0,1", 60, 2))                   // 查询模组是否注册上GPRS网络
            {
                step++;                                                 
            }
            else
            {
                printf("Err:AT+CGREG?\r\n");                                    // 60秒内,没有注册上PS业务
                reset();        
                break;
            }
        case 4:
            if(sendCmd("AT+QICSGP=1,1,\"CMNET\",\"\",\"\",1\r\n", "OK", 40, 3)) // 查询模组是否注册上GPRS网络
            {
                result = EC200S_NetConfig();                          
            }
            else
            {
                printf("Err:AT+QICSGP=1,1\r\n");                                // 如果3次都没停止成功或超过40秒没有回应,则重启模块
                reset();
                break;
            }
    }
    return result;
}

/**
 @brief 网络配置
 @param 无
 @return 无
*/
void EC200S_GpioConfig(void)
{
    GPIO_InitTypeDef gpioInitStructure;     
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);                       // 使能GPIO
    gpioInitStructure.GPIO_Pin = GPIO_Pin_8;                                    // 选择要初始化的GPIOB引脚PB8
    gpioInitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                             // 设置引脚工作模式为通用推挽输出      
    gpioInitStructure.GPIO_Speed = GPIO_Speed_50MHz;                            // 设置引脚输出最大速率为50MHz
    GPIO_Init(GPIOB, &gpioInitStructure);       
}

/**
 @brief 网络配置
 @param 无
 @return 1 - 成功;0 - 失败
*/
uint8_t EC200S_NetConfig(void)
{      
    uint8_t result = 0;
    if(sendCmd("AT+QIDEACT=1\r\n", "OK", 40, 1))                                // 在激活GPRS场景之前先关闭GPRS场景,确保连接正确
    {
        if(sendCmd("AT+QIACT=1\r\n", "OK", 150, 1))                              // 激活移动场景
        {
            EC200S_Connect();
        } 
        else                                                                    // 等待150秒后,没有响应重启模块
        {
            printf("Err:AT+QIACT=1\r\n");                                       // 重启模块
            reset();
        }
    }      
    else                                                                        // 等待40秒后,没有响应重启模块
    {
        printf("Err:AT+QIDEACT=1\r\n");                                         // 重启模块
        reset();
    }     
}

/**
 @brief 连接TCP服务器
 @param 无
 @return 无
*/
void EC200S_Connect(void)
{
    if(sendCmd("AT+QIOPEN=1,0,\"TCP\",\"180.97.81.180\",53540,0,1\r\n", "+QIOPEN:", 150, 5))    
    {
        printf("Connect Success\r\n");
    }      
    else
    {
        printf("Err:AT+QIOPEN=1,0\r\n");
    }       
}

/**
 @brief 发送数据到TCP服务器
 @param pString -[in] 发送数据
 @return 无
*/
void EC200S_Send(char *pString)
{
    if(sendCmd("AT+QISEND=0\r\n", ">", 60, 1)) 
    {
        if(sendCmd("AT+QISEND=0,0\r\n", "OK", 5, 24))                   // 2分钟后(每5秒查询一次,共24次)
        {
            /* 发送数据成功,对方收到数据 */
        }
        else
        {
            printf("Err:AT+QISEND=0\r\n");                                      
            if(sendCmd("AT+QICLOSE=0\r\n", "OK", 10, 1))                // TCP连接出现异常,关闭TCP连接
            {
                printf("AT+QICLOSE\r\n");
                EC200S_Connect();
            }
            else
            {
                reset();                                                // 等待10秒,没有响应重启模块
            } 
        }
    }
    else
    {
        reset();                                                        // 等待60秒,没有响应重启模块
    }
}

/**
 @brief 从TCP服务器接收数据
 @param pRecvDataBuf -[out] 接收数据
 @return 接收数据长度
*/
uint32_t EC200S_Receive(char *pRecvDataBuf)
{
    uint32_t recvDataLen = 0;
    if(g_isUsart2RecvFinish)                                                    // 如果串口接收完成
    {
        if(strstr((const char *)g_ec200sBuf, "+QIURC: \"recv\",0,") != NULL)    // 如果检索到关键词
        {
            memcpy(pRecvDataBuf, g_ec200sBuf, g_ec200sCnt);
            recvDataLen = g_ec200sCnt;
        }
        clearBuffer();
    }   
    return recvDataLen;
}


/*********************************************************************
 * LOCAL FUNCTIONS
 */
/**
 @brief 发送AT命令
 @param pCmd -[in] 命令字符串
 @param pRes -[in] 需要检测的返回命令字符串
 @param timeOut -[in] 等待时间
 @param sendNum -[in] 命令发送次数
 @return 1 - 成功;0 - 失败
*/
uint8_t sendCmd(char *pCmd, char *pRes, uint32_t timeOut, uint8_t sendNum)
{
    uint8_t i = 0;
    uint32_t time;
    clearBuffer();                                                              // 清空缓存 
    for(i = 0; i < sendNum; i++)
    {
        time = timeOut * 10;
        USART_SendString(USART2, pCmd);
        while(time--)
        {
            if(g_usart2RecvFinish)                                              // 如果串口接收完成
            {
                if(strstr((const char *)g_ec200sBuf, pRes) != NULL)             // 如果检索到关键词
                {
                    printf("%s", g_ec200sBuf);
                    return 1;
                }
            }   
            vTaskDelay(100);                                                   // 等待100毫秒
        }
        clearBuffer();
    }
    return 0;
}

/**
 @brief 清空缓存
 @param 无
 @return 无
*/
void clearBuffer(void)
{
    memset(g_ec200sBuf, 0, sizeof(g_ec200sBuf));
    g_ec200sCnt = 0;
    g_usart2RecvFinish = 0;
}

/**
 @brief 重启模块
 @param 无
 @return 无
*/
void reset(void)
{
    printf("reset\n");    
    GPIO_ResetBits(GPIOB, GPIO_Pin_8);
    vTaskDelay(2000);
    GPIO_SetBits(GPIOB, GPIO_Pin_8);
}

/****************************************************END OF FILE****************************************************/

4.2 board_ec200s.h

#ifndef _BOARD_EC200S_H_
#define _BOARD_EC200S_H_

/*********************************************************************
 * INCLUDES
 */
#include "stm32f10x.h"

/*********************************************************************
 * GLOBAL VARIABLES
 */  
extern uint8_t g_usart2RecvFinish;      // 串口2接收标志串口接收完成标志
extern char g_ec200sBuf[1024];          // 接收缓存
extern uint32_t g_ec200sCnt;            // 接收计数

/*********************************************************************
 * API FUNCTIONS
 */
uint8_t EC200S_Init(void);
void EC200S_GpioConfig(void);
uint8_t EC200S_NetConfig(void);
void EC200S_Connect(void);
void EC200S_Send(char *pString);
uint32_t EC200S_Receive(char *pRecvDataBuf);

#endif /* _BOARD_EC200S_H_ */

六、使用方法

EC200S_GpioConfig();
EC200S_Init();
while(1)                                                            // 任务都是一个无限循环,不能返回
{
    EC200S_Send("TEST");
    vTaskDelay(10000);  
    char recvDataBuf[256] = {0};
    int recvDataLen = EC200S_Receive(recvDataBuf);           
}
/**
 @brief 串口2收发中断
 @param 无
 @return 无
*/
void USART2_IRQHandler(void)
{
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)                           // 接收中断
    {
        g_usart2RecvFinish = 1;                                                   // 串口2接收标志

        if(g_ec200sCnt >= sizeof(g_ec200sBuf))
        {
            g_ec200sCnt = 0;                                                        // 防止串口被刷爆
        }

        g_ec200sBuf[g_ec200sCnt++] = USART2->DR;
        
        USART_ClearFlag(USART2, USART_FLAG_RXNE);
    }                                                            
}

• 由 Leung 写于 2020 年 9 月 28 日

• 参考:移远 EC200S 模组(4G Cat.1 通信模组)AT指令测试 TCP/UDP 通信过程
    移远EC20 R2.0 AT指令拨号流程
    Quectel EC20 R2.1 AT指令集(TCP/部分)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容