美文网首页物联网loT从业者
NRF52832学习笔记(35)——4G模块EC200S使用

NRF52832学习笔记(35)——4G模块EC200S使用

作者: Leung_ManWah | 来源:发表于2020-12-04 15:53 被阅读0次

    一、简介

    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服务器。

    二、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命令拨号流程

    四、程序大致流程

    主要开了三个定时器
    sendCmdTimer:发送命令定时器
    sendDataTimer:发送数据定时器(用于建立TCP连接后发送数据)
    recvCmdTimer:统一接收命令定时器

    五、移植文件

    5.1 board_ec200s.c

    /*********************************************************************
     * INCLUDES
     */
    #include "stdlib.h"
    #include "string.h"
    #include "app_timer.h"
    #include "nrf_log.h"
    
    #include "board_uart.h"
    #include "board_ec200s.h" 
    #include "common.h"
    
    static void clearBuffer(void);
    static void reset(void);
    static void timer_sendCmdCallback(void *arg);
    static void timer_sendDataCallback(void *arg);
    static void timer_recvCmdCallback(void *arg);
    static void timer_resetCallback(void *arg);
    static void sendData(char *pCmd);
    
    /*********************************************************************
     * GLOBAL VARIABLES
     */  
    char g_ec200sBuf[MAX_RECV_BUF_SIZE] = {0};                                      // 接收缓存
    uint32_t g_ec200sCnt = 0;                                                       // 接收计数   
    uint8_t g_isEc200sInit = 0;   
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    APP_TIMER_DEF(s_sendCmdTimer);                                                  // 发送命令的定时器
    APP_TIMER_DEF(s_sendDataTimer);                                                 // 发送数据的定时器
    APP_TIMER_DEF(s_recvCmdTimer);                                                  // 接收命令的定时器
    APP_TIMER_DEF(s_resetTimer);                                                    // 重启的定时器
    static uint8_t s_sendCmdResult = 0;                                             // 发送命令结果
    static uint32_t s_waitCmdTime = 0;                                              // 等待命令时间
    static uint8_t s_waitCmdNum = 0;                                                // 等待命令次数
    static bool s_sendCmdFlag = false;
    static uint8_t s_sendCmdStep = 0;
    static char s_waitCmdBuf[30] = {0};                                             // 等待比较命令
    static bool s_sendDataFlag = false;
    static uint8_t s_sendDataStep = 0;
    static char s_sendDataBuf[MAX_RECV_BUF_SIZE] = {0};          
    static char s_recvDataBuf[MAX_RECV_BUF_SIZE] = {0};  
    static uint32_t s_recvDataLen = 0;
    static uint8_t s_isReset = 0;
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    /**
     @brief 初始化
     @param 无
     @return 1 - 成功;0 - 失败
    */
    uint8_t EC200S_Init(void)
    {       
        if((s_sendCmdResult == 0) && (s_isReset == 0))
        {
            NRF_LOG_INFO("EC200S_Init");
            s_sendCmdStep = 0;  
            StartSendCmdTimer();
            StartRecvCmdTimer();
            s_sendCmdResult = 2;
        }
        
        if(s_sendCmdResult == 1)
        {
            s_sendCmdResult = 0;
            return 1;
        }
        
        return 0;
    }
    
    /**
     @brief 引脚配置
     @param 无
     @return 无
    */
    void EC200S_GpioConfig(void)
    {
        nrf_gpio_cfg_output(EC200S_GPIO_PIN);
        nrf_gpio_pin_write(EC200S_GPIO_PIN, 1);
    }
    
    /**
     @brief 发送数据到TCP服务器
     @param pString -[in] 发送数据
     @return 无
    */
    void EC200S_Send(char *pString)
    {
        if(g_isEc200sInit == 1)
        {   
            sprintf(s_sendDataBuf, "%s\x1A", pString);
            s_sendDataStep = 0;
            NRF_LOG_INFO("%s", pString); 
            StartSendDataTimer();
            StartRecvCmdTimer();
        }
    }
    
    /**
     @brief 从TCP服务器接收数据
     @param pRecvDataBuf -[out] 接收数据
     @return 接收数据长度
    */
    uint32_t EC200S_Receive(char *pRecvDataBuf)
    {
        uint32_t recvDataLen = 0;
    
        if(s_recvDataLen > 0)
        {
            memcpy(pRecvDataBuf, s_recvDataBuf, s_recvDataLen);
            recvDataLen = s_recvDataLen;
            memset(s_recvDataBuf, 0, s_recvDataLen);
            s_recvDataLen = 0;
        }
       
        return recvDataLen;
    }
    
    /**
     @brief 创建发送命令的定时器
     @param 无
     @return 无
    */
    void CreateSendCmdTimer(void)
    {
        app_timer_create(&s_sendCmdTimer, APP_TIMER_MODE_REPEATED, timer_sendCmdCallback);
    }
    
    /**
     @brief 开启发送命令的定时器
     @param 无
     @return 无
    */
    void StartSendCmdTimer(void)
    {       
        app_timer_start(s_sendCmdTimer, SEND_CMD_PERIOD, NULL);
    }
    
    /**
     @brief 关闭发送命令的定时器
     @param 无
     @return 无
    */
    void StopSendCmdTimer(void)
    {   
        app_timer_stop(s_sendCmdTimer);        
    }
    
    /**
     @brief 创建发送数据的定时器
     @param 无
     @return 无
    */
    void CreateSendDataTimer(void)
    {
        app_timer_create(&s_sendDataTimer, APP_TIMER_MODE_REPEATED, timer_sendDataCallback);
    }
    
    /**
     @brief 开启发送数据的定时器
     @param 无
     @return 无
    */
    void StartSendDataTimer(void)
    {       
        app_timer_start(s_sendDataTimer, SEND_DATA_PERIOD, NULL);
    }
    
    /**
     @brief 关闭发送数据的定时器
     @param 无
     @return 无
    */
    void StopSendDataTimer(void)
    {   
        app_timer_stop(s_sendDataTimer);        
    }
    
    /**
     @brief 创建接收命令的定时器
     @param 无
     @return 无
    */
    void CreateRecvCmdTimer(void)
    {
        app_timer_create(&s_recvCmdTimer, APP_TIMER_MODE_REPEATED, timer_recvCmdCallback);
    }
    
    /**
     @brief 开启接收命令的定时器
     @param 无
     @return 无
    */
    void StartRecvCmdTimer(void)
    {       
        app_timer_start(s_recvCmdTimer, RECV_CMD_PERIOD, NULL);
    }
    
    /**
     @brief 关闭接收命令的定时器
     @param 无
     @return 无
    */
    void StopRecvCmdTimer(void)
    {   
        app_timer_stop(s_recvCmdTimer);        
    }
    
    /**
     @brief 创建重启的定时器
     @param 无
     @return 无
    */
    void CreateResetTimer(void)
    {
        app_timer_create(&s_resetTimer, APP_TIMER_MODE_SINGLE_SHOT, timer_resetCallback);
    }
    
    /**
     @brief 处理接收命令
     @param 无
     @return 1 - 成功;0 - 失败
    */
    uint8_t ReceiveCommandHandler(void)
    {  
        if(strstr((const char *)g_ec200sBuf, "SEND OK") != NULL)                    // 如果检索到关键词SEND OK
        {
            s_sendDataStep++;
            s_sendDataFlag = false;
            clearBuffer(); 
            return 1;
        }
        else if(strstr((const char *)g_ec200sBuf, "+QISEND:") != NULL)              // 如果检索到关键词+QISEND:
        {
            s_sendDataStep++;
            s_sendDataFlag = false;
            clearBuffer();
            return 1;        
        }
        else if(strstr((const char *)g_ec200sBuf, "+CPIN: READY") != NULL)          // 如果检索到关键词+CPIN: READY
        {
            s_sendCmdStep++;
            s_sendCmdFlag = false;
            clearBuffer(); 
            return 1;
        }
        else if(strstr((const char *)g_ec200sBuf, "+CREG: 0,1") != NULL)            // 如果检索到关键词+CREG: 0,1
        {
            s_sendCmdStep++;
            s_sendCmdFlag = false;
            clearBuffer(); 
            return 1;
        }
        else if(strstr((const char *)g_ec200sBuf, "+CGREG: 0,1") != NULL)           // 如果检索到关键词+CGREG: 0,1
        {
            s_sendCmdStep++;
            s_sendCmdFlag = false;
            clearBuffer(); 
            return 1;
        }
        else if(strstr((const char *)g_ec200sBuf, "OK") != NULL)                    // 如果检索到关键词OK
        {
            s_sendDataStep++;
            s_sendDataFlag = false;
            s_sendCmdStep++;
            s_sendCmdFlag = false;
            clearBuffer();
            return 1;
        }
        else if(strstr((const char *)g_ec200sBuf, "+QIOPEN:") != NULL)              // 如果检索到关键词+QIOPEN:
        {
            NRF_LOG_INFO("Connect Success");
            s_sendCmdResult = 1;
            s_sendCmdStep++;
            s_sendCmdFlag = false;
            clearBuffer(); 
            StopSendCmdTimer();
            StopRecvCmdTimer();
            return 1;
        }   
        else if(strstr((const char *)g_ec200sBuf, "ERROR") != NULL)                 // 如果检索到关键词ERROR
        {
            NRF_LOG_INFO("connect error\n");
            reset();
            clearBuffer();
            return 1;
        }
        else if(strstr((const char *)g_ec200sBuf, "POWERED DOWN") != NULL)          // 如果检索到关键词POWERED DOWN
        {
            NRF_LOG_INFO("power down\n");
        }
        
        return 0;
    }
    
    /**
     @brief 处理接收数据
     @param 无
     @return 1 - 成功;0 - 失败
    */
    uint8_t ReceiveDataHandler(void)
    {
        static bool s_isRecvData;
        if(strstr((const char *)g_ec200sBuf, "+QIURC: \"recv\",0,") != NULL)        // 如果检索到关键词+QIURC: \"recv\",0,
        {
            s_isRecvData = true;
            clearBuffer();
            return 1;
        }
        if(s_isRecvData)
        {
            memcpy(s_recvDataBuf, g_ec200sBuf, g_ec200sCnt);
            s_recvDataLen = g_ec200sCnt;
            clearBuffer();
            s_isRecvData = false;
            return 1;
        }
        
        return 0;
    }
    
    
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    /**
     @brief 清空缓存
     @param 无
     @return 无
    */
    static void clearBuffer(void)
    {
        memset(g_ec200sBuf, 0, sizeof(g_ec200sBuf));
        memset(s_waitCmdBuf, 0, sizeof(s_waitCmdBuf));
        g_ec200sCnt = 0;
    }
    
    /**
     @brief 重启模块
     @param 无
     @return 无
    */
    static void reset(void)
    {
        NRF_LOG_INFO("reset\n");
        s_isReset = 1;
        g_isEc200sInit = 0;
        s_sendCmdResult = 0;
        s_sendCmdFlag = false;
        s_sendDataFlag = false;
        StopSendCmdTimer();
        StopSendDataTimer();
        StopRecvCmdTimer();
        
        nrf_gpio_pin_write(EC200S_GPIO_PIN, 0);                                     // 拉低
        app_timer_start(s_resetTimer, RESET_PERIOD, NULL);                          // 等待2s,再拉高
    }
    
    /**
     @brief 发送命令定时器的回调函数
     @param 无
     @return 无
    */
    static void timer_sendCmdCallback(void *arg)
    {
        if(s_sendCmdStep == 0 && s_sendCmdFlag == false)                            // 测试AT指令功能是否正常
        {
            sendData("AT\r\n");  
            s_waitCmdTime = 10 * 10;                                                // 10秒
            s_sendCmdFlag = true;        
        }
        else if(s_sendCmdStep == 1 && s_sendCmdFlag == false)                       // 查询SIM卡是否正常,返回ready则表示SIM卡正常
        {
            sendData("AT+CPIN?\r\n");
            s_waitCmdTime = 20 * 10;                                                // 20秒
            s_sendCmdFlag = true;
        }
        else if(s_sendCmdStep == 3 && s_sendCmdFlag == false)                       // 查询模组是否注册上GSM网络
        {
            sendData("AT+CREG?\r\n");
            s_waitCmdTime = 90 * 10;                                                // 90秒
            s_sendCmdFlag = true;
        }
        else if(s_sendCmdStep == 5 && s_sendCmdFlag == false)                       // 查询模组是否注册上GPRS网络
        {
            sendData("AT+CGREG?\r\n");
            s_waitCmdTime = 60 * 10;                                                // 60秒
            s_sendCmdFlag = true;
        }
        else if(s_sendCmdStep == 7 && s_sendCmdFlag == false)                       // 配置PDP场景
        {
            sendData("AT+QICSGP=1,1,\"CMNET\",\"\",\"\",1\r\n");
            s_waitCmdTime = 40 * 10;                                                // 40秒
            s_sendCmdFlag = true;
        }
        else if(s_sendCmdStep == 8 && s_sendCmdFlag == false)                       // 在激活GPRS场景之前先关闭GPRS场景,确保连接正确
        {
            sendData("AT+QIDEACT=1\r\n");
            s_waitCmdTime = 40 * 10;                                                // 40秒
            s_sendCmdFlag = true;
        }
        else if(s_sendCmdStep == 9 && s_sendCmdFlag == false)                       // 在激活GPRS场景之前先关闭GPRS场景,确保连接正确
        {
            sendData("AT+QIACT=1\r\n");
            s_waitCmdTime = 150 * 10;                                               // 150秒
            s_sendCmdFlag = true;
        }
        else if(s_sendCmdStep == 10 && s_sendCmdFlag == false)                      // 连接服务器
        {                           
            sendData("AT+QIOPEN=1,0,\"TCP\",\"180.97.81.180\",59889,0,1\r\n");
            s_waitCmdTime = 150 * 10;                                               // 150秒
            s_sendCmdFlag = true;
        }
        
        if(s_waitCmdTime == 0)                                                      // 没有响应重启模块 
        {        
            reset();                                                        
        }
    }
    
    /**
     @brief 发送数据定时器的回调函数
     @param 无
     @return 无
    */
    static void timer_sendDataCallback(void *arg)
    {
        if(s_sendDataStep == 0)                                                     // 发送长度可变数据格式
        {
            sendData("AT+QISEND=0\r\n");                                            // >会被断包,这里特殊处理
            s_waitCmdTime = 60 * 10;                                                // 60秒
            s_sendDataStep++;
        }
        else if(s_sendDataStep == 1 && s_sendDataFlag == false)                     // 发送实际数据
        {
            sendData(s_sendDataBuf);
            memset(s_sendDataBuf, 0, MAX_RECV_BUF_SIZE);
            s_waitCmdTime = 60 * 10;                                                // 60秒
            s_sendDataFlag = true;
        }
        else if(s_sendDataStep == 2 && s_sendDataFlag == false)                     // 查询数据是否达到服务器
        {
            sendData("AT+QISEND=0,0\r\n");
            s_waitCmdTime = 5 * 10;                                                 // 5秒
            s_waitCmdNum = 23;
            s_sendDataFlag = true;
        }
        else if(s_sendDataStep == 4)                                                // 完成发送
        {
            StopSendDataTimer();
            StopRecvCmdTimer();
        }
        
        if(s_waitCmdTime == 0)                                                      // 等待60秒,没有响应重启模块 
        {
            s_waitCmdNum--;
            if(s_waitCmdNum > 0)                                                    // 2分钟后(每5秒查询一次,共24次),没有响应重启模块 
            {
                sendData("AT+QISEND=0,0\r\n");
                s_waitCmdTime = 5 * 10;
                s_sendDataStep = 2;
                s_sendDataFlag = true;
                return;
            }
            
            reset();                                                        
        }
    }
    
    /**
     @brief 接收命令定时器的回调函数
     @param 无
     @return 无
    */
    static void timer_recvCmdCallback(void *arg)
    {
        if(s_waitCmdTime == 0)
        {
            StopRecvCmdTimer();
            return; 
        }
    
        s_waitCmdTime--;
    }
    
    /**
     @brief 重启定时器的回调函数
     @param 无
     @return 无
    */
    static void timer_resetCallback(void *arg)
    {
        nrf_gpio_pin_write(EC200S_GPIO_PIN, 1);
        s_isReset = 0;
    }
    
    /**
     @brief 发送数据
     @param pCmd -[in] 命令字符串
     @return 无
    */
    static void sendData(char *pCmd)
    {  
        UART_WriteData((uint8_t *)pCmd, strlen(pCmd));
    }
    

    5.2 board_ec200s.h

    #ifndef _BOARD_EC200S_H_
    #define _BOARD_EC200S_H_
    
    /*********************************************************************
     * INCLUDES
     */
    
    /*********************************************************************
     * DEFINITIONS
     */
    #define EC200S_GPIO_PIN             7
    
    #define MAX_RECV_BUF_SIZE           256
    
    #define SEND_CMD_PERIOD             APP_TIMER_TICKS(98)      // 98ms
    #define SEND_DATA_PERIOD            APP_TIMER_TICKS(98)      // 98ms
    #define RECV_CMD_PERIOD             APP_TIMER_TICKS(100)     // 100ms
    #define RESET_PERIOD                APP_TIMER_TICKS(3000)    // 3s
    
    /*********************************************************************
     * GLOBAL VARIABLES
     */  
    extern char g_ec200sBuf[MAX_RECV_BUF_SIZE];     // 接收缓存
    extern uint32_t g_ec200sCnt;                    // 接收计数
    extern uint8_t g_isEc200sInit;
    
    /*********************************************************************
     * API FUNCTIONS
     */
    uint8_t EC200S_Init(void);
    void EC200S_GpioConfig(void);
    void EC200S_Send(char *pString);
    uint32_t EC200S_Receive(char *pRecvDataBuf);
    void CreateSendCmdTimer(void);
    void StartSendCmdTimer(void);
    void StopSendCmdTimer(void);
    void CreateSendDataTimer(void);
    void StartSendDataTimer(void);
    void StopSendDataTimer(void);
    void CreateRecvCmdTimer(void);
    void StartRecvCmdTimer(void);
    void StopRecvCmdTimer(void);
    void CreateResetTimer(void);
    uint8_t ReceiveCommandHandler(void);
    uint8_t ReceiveDataHandler(void);
    
    #endif /* _BOARD_EC200S_H_ */
    

    5.3 board_uart.c

    查看 NRF52832学习笔记(12)——UART接口使用

    /*********************************************************************
     * INCLUDES
     */
    #include "nrf_uart.h"
    #include "app_uart.h"
    
    #include "board_ec200s.h"
    #include "board_uart.h"
    #include "user_uart.h"
    
    #include "nrf_log.h"
    
    static void uart_handleEvent(app_uart_evt_t *pEvent);
    
    /*********************************************************************
     * LOCAL VARIABLES
     */
    static uint8_t s_uartReadDataBuffer[UART_RX_BUF_SIZE] = {0};
    static uint8_t s_index = 0;
    static bool s_begin = false;
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    /**
     @brief 串口驱动初始化
     @param 无
     @return 无
    */
    void UART_Init(void)
    {
        uint32_t errCode;
        app_uart_comm_params_t const commParams =
        {
            .rx_pin_no    = BOARD_UART_RX_IO,
            .tx_pin_no    = BOARD_UART_TX_IO,
            .rts_pin_no   = BOARD_UART_RTS_IO,
            .cts_pin_no   = BOARD_UART_CTS_IO,                     
            .flow_control = APP_UART_FLOW_CONTROL_DISABLED,     // 关掉流控
            .use_parity   = false,
    #if defined (UART_PRESENT)
            .baud_rate    = NRF_UART_BAUDRATE_115200            // 波特率
    #else
            .baud_rate    = NRF_UARTE_BAUDRATE_115200
    #endif
        };
        
        APP_UART_FIFO_INIT(&commParams, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE,
                            uart_handleEvent, APP_IRQ_PRIORITY_LOWEST, errCode);
        APP_ERROR_CHECK(errCode);
    }
    /**
     @brief 串口写数据函数
     @param pData -[in] 写入数据
     @param dataLen -[in] 写入数据长度
     @return 无
    */
    void UART_WriteData(uint8_t *pData, uint8_t dataLen)
    {
        uint8_t i;
        for(i = 0; i < dataLen; i++)
        {
            app_uart_put(pData[i]);
        }
    }
    
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    /**
     @brief 串口读取数据处理函数
     @param pEvent -[in] 串口事件
     @return 无
    */
    static void uart_handleEvent(app_uart_evt_t *pEvent)
    {
        uint8_t dataChar = 0;
        
        switch(pEvent->evt_type)
        {
            // 已接收到UART数据
            case APP_UART_DATA_READY:
            {
                UNUSED_VARIABLE(app_uart_get(&dataChar));
                
                // 不是回车符或换行符则开始   
                if(dataChar != '\n' && dataChar != '\r')
                {
                    s_begin = true;
                }
                if(s_begin)
                {
                    s_uartReadDataBuffer[s_index] = dataChar;
                    s_index++;
                }
    
                // 遇到回车符或换行符结束      
                if((s_uartReadDataBuffer[s_index - 1] == '\n') ||
                   (s_uartReadDataBuffer[s_index - 1] == '\r') ||
                   (s_index >= MAX_RECV_BUF_SIZE))
                {
    //                NRF_LOG_HEXDUMP_INFO(s_uartReadDataBuffer, s_index);  
                    memcpy(g_ec200sBuf, s_uartReadDataBuffer, s_index); // 接收缓存
                    g_ec200sCnt = s_index;                              // 接收计数   
                    if(!ReceiveCommandHandler())
                    {
                        ReceiveDataHandler();
                    }
    
                    memset(s_uartReadDataBuffer, 0, s_index); 
                    s_index = 0;
                    s_begin = false;                
                }
            } break;
    
            // 接收过程中发生通信错误
            case APP_UART_COMMUNICATION_ERROR:
                APP_ERROR_HANDLER(pEvent->data.error_communication);
                break;
    
            // app_uart模块使用的FIFO模块中出现错误
            case APP_UART_FIFO_ERROR:
                APP_ERROR_HANDLER(pEvent->data.error_code);
                break;
     
            default:
                break;
        }
    }
    
    /****************************************************END OF FILE****************************************************/
    

    5.4 board_uart.h

    #ifndef _BOARD_UART_H_
    #define _BOARD_UART_H_
    
    /*********************************************************************
     * INCLUDES
     */
    
    /*********************************************************************
     * DEFINITIONS
     */
    #define UART_TX_BUF_SIZE                256     // UART TX buffer size
    #define UART_RX_BUF_SIZE                256     // UART RX buffer size
    
    #define BOARD_UART_TX_IO                6       // 发送引脚  
    #define BOARD_UART_RX_IO                8       // 接收引脚
    #define BOARD_UART_CTS_IO               7       // 流量控制发送清除、低有效
    #define BOARD_UART_RTS_IO               9       // 流量控制发送请求、低有效
    
    /*********************************************************************
     * API FUNCTIONS
     */
    void UART_Init(void);
    void UART_WriteData(uint8_t *pData, uint8_t dataLen);
    
    #endif /* _BOARD_UART_H_ */
    

    五、使用方法

    #include "board_ec200s.h"
    #include "board_uart.h"
    
    int main(void)
    {
        log_init();
        timers_init();
        EC200S_GpioConfig();                                                        // 4G模块PWK引脚初始化                       
        UART_Init();                                                                // 串口驱动初始化
    
        power_management_init();
        ble_stack_init();                                                           // 协议栈初始化
        gap_params_init();
        gatt_init();                                                                
        services_init();                                                            // 服务初始化
        advertising_init();                                                         // 广播初始化
        conn_params_init();                                                         // 连接参数初始化
    
        advertising_start();                                                        // 开启广播
        application_timers_start();                                                 // 定时器应用开启
    
        // Enter main loop.
        for(;;)
        {
            idle_state_handle();
        }
    }
    

    创建一个定时器每200毫秒进入一次回调函数

    /**
     @brief 检查网络定时器的回调函数
     @param 无
     @return 无
    */
    static void timer_checkNetworkCallback(void *arg)
    {
        UNUSED_PARAMETER(arg);
        
        if(g_isEc200sInit == 0)
        {
            g_isEc200sInit = EC200S_Init();                                 // 初始化4G模块
            if(g_isEc200sInit == 1)
            {
                EC200S_Send("hello");     
            }
        }
        else if(g_isEc200sInit == 1)
        {
            char recvDataBuf[256] = {0};
            int recvDataLen = EC200S_Receive(recvDataBuf);                  // 接收服务器数据
            if(recvDataLen > 0)
            {
                // 进入处理
            }
        }
    }
    

    • 由 Leung 写于 2020 年 12 月 4 日

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

    相关文章

      网友评论

        本文标题:NRF52832学习笔记(35)——4G模块EC200S使用

        本文链接:https://www.haomeiwen.com/subject/mdhiwktx.html