NRF52832學習筆記(35)——4G模塊EC200S使用

一、簡介

EC200S-CN 是移遠通信最近推出的 LTE Cat 1 無線通信模塊遗座,支持最大下行速率 10Mbps 和最大上行速率 5Mbps,具有超高的性價比;同時在封裝上兼容移遠通信多網(wǎng)絡制式 LTE Standard EC2x(EC25、EC21挣惰、EC20 R2.0、EC20 R2.1)和 EC200T/EG25-G/EG21-G 模塊以及 UMTS/HSPA+ UC20/UC200T 模塊殴边,實現(xiàn)了 3G 網(wǎng)絡與 4G 網(wǎng)絡之間的無縫切換憎茂。EC200S-CN 還支持標準的 Mini PCIe 封裝,以滿足不同行業(yè)產(chǎn)品應用需求锤岸。

Quectel EC2x 模塊具有嵌入式 TCP/IP堆棧竖幔,使主機可以通過 AT 命令直接上網(wǎng)∈峭担可以實現(xiàn)TCP客戶端拳氢、UDP客戶端、TCP服務器和UDP服務器蛋铆。

二馋评、AT指令

2.1 AT

測試AT指令功能是否正常,等待模塊返回 OK戒职。

AT

OK

2.2 AT + CPIN?

查詢 SIM 卡狀態(tài)栗恩,返回 READY 則表示SIM卡正常,如果 20 秒后還無法識別 SIM 卡,重新啟動模塊磕秤。

AT+CPIN?

+CPIN: READY

OK

2.3 AT + CREG?

查詢模組是否注冊上GSM網(wǎng)絡乳乌,如果 90秒后未能在 CS 上注冊域名服務,重新啟動模塊市咆。
如果返回 1 或 5 汉操,代表 CS 服務注冊成功。
+CREG:0,1 表示已注冊上本地網(wǎng)蒙兰,+CREG:0,5表示注冊上漫游網(wǎng)磷瘤。

AT+CREG?

+CREG: 0,1

OK

2.4 AT + CGREG?

查詢模組是否注冊上GPRS網(wǎng)絡,+CGREG:0,1 表示已注冊上本地網(wǎng)搜变,+CGREG:0,5表示注冊上漫游網(wǎng)采缚。

AT+CGREG?

+CGREG: 0,1

OK

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

該命令可用于配置<APN>,<username>挠他,<password>等TCP / IP上下文參數(shù)扳抽。QoS設置可以由AT + CGQMIN,AT + CGEQMIN殖侵,AT + CGQREQ和AT + CGEQREQ配置 贸呢。

  • AT+QICSGP=?:查詢命令參數(shù)。
  • AT+QICSGP=<contextID>:查詢 contextID的配置信息拢军。
  • AT+QICSGP=<contextID>[,<context_type>,<APN>[,<username>,<password>)[,<authentication>]]]:配置 contextID信息楞陷。
    • <contextID>:整數(shù)類型。上下文ID茉唉。范圍是1-16固蛾。
    • <context_type>:整數(shù)類型。協(xié)議類型赌渣。1(IPV4)魏铅、2(IPV4V6)。
    • <APN>:字符串類型坚芜。接入點名稱览芳。移動CMNET,聯(lián)通UNINET
    • <username>:字符串類型鸿竖。用戶名沧竟。
    • <password>:字符串類型。密碼缚忧。
    • <authentication>:整數(shù)類型悟泵。身份驗證方法。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=?:查詢命令參數(shù)衡招。
  • AT+QIOPEN=<contextID>,<connectID>,<service_type>,<IP_address>/<domain_name>,<remote_port>[,<local_po CONNECTrt>[,<access_mode>]] :打開 Socket 服務篱昔。
    • <contextID> :整數(shù)類型。上下文ID始腾。范圍是1-16州刽。
    • <connectID> :整數(shù)類型。套接字服務索引浪箭。范圍是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”蜻势,則此參數(shù)必須指定撑刺。
      • 如果<service_type>是“TCP”或“UDP”。如果<local_port>為0握玛,那么本地端口將是自動分配够傍。否則,將按指定分配本地端口挠铲。
    • <access_mode> :整數(shù)類型冕屯。套接字服務的數(shù)據(jù)訪問模式。
      • 0: 緩沖區(qū)訪問模式
      • 1:直推模式
      • 2:透明訪問模式
    • <err>:整數(shù)類型拂苹。操作的錯誤代碼安聘。請參閱第4章。
AT+QIOPEN=1,0,\"TCP\",\"180.97.81.180\",53540,0,1

OK

+QIOPEN: 0,0

Buffer模式,Push模式浴韭,透傳模式带迟。通過參數(shù)<access_mode>進行配置。





2.9 AT + QISEND

如果指定套接字服務的<access_mode>是緩沖區(qū)訪問模式或直接推送模式囱桨,則數(shù)據(jù)可以是通過AT + QISEND發(fā)送仓犬。如果數(shù)據(jù)成功發(fā)送到模塊,將返回“ SEND OK ” 舍肠。否則它將返回“ SEND FAIL ” 或“ ERROR ” 搀继。“ SEND FAIL ” 表示發(fā)送緩沖區(qū)已滿客戶可以嘗試重新發(fā)送數(shù)據(jù)翠语∵辞“ERROR”表示在發(fā)送過程中遇到錯誤 數(shù)據(jù)〖±ǎ客戶應該延遲一段時間來發(fā)送數(shù)據(jù)点骑。最大數(shù)據(jù)長度為1460字〉玻“SEND OK”并不意味著數(shù)據(jù)已成功發(fā)送到服務器黑滴。客戶可以查詢數(shù)據(jù)是否通過AT + QISEND = <connectID>紧索,0命令到達服務器袁辈。透傳模式下不需要AT指令發(fā)送數(shù)據(jù)


三、TCP/IP AT命令撥號流程

四珠漂、程序大致流程

主要開了三個定時器
sendCmdTimer:發(fā)送命令定時器
sendDataTimer:發(fā)送數(shù)據(jù)定時器(用于建立TCP連接后發(fā)送數(shù)據(jù))
recvCmdTimer:統(tǒng)一接收命令定時器

五晚缩、移植文件

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;                                                       // 接收計數(shù)   
uint8_t g_isEc200sInit = 0;   

/*********************************************************************
 * LOCAL VARIABLES
 */
APP_TIMER_DEF(s_sendCmdTimer);                                                  // 發(fā)送命令的定時器
APP_TIMER_DEF(s_sendDataTimer);                                                 // 發(fā)送數(shù)據(jù)的定時器
APP_TIMER_DEF(s_recvCmdTimer);                                                  // 接收命令的定時器
APP_TIMER_DEF(s_resetTimer);                                                    // 重啟的定時器
static uint8_t s_sendCmdResult = 0;                                             // 發(fā)送命令結果
static uint32_t s_waitCmdTime = 0;                                              // 等待命令時間
static uint8_t s_waitCmdNum = 0;                                                // 等待命令次數(shù)
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 發(fā)送數(shù)據(jù)到TCP服務器
 @param pString -[in] 發(fā)送數(shù)據(jù)
 @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服務器接收數(shù)據(jù)
 @param pRecvDataBuf -[out] 接收數(shù)據(jù)
 @return 接收數(shù)據(jù)長度
*/
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 創(chuàng)建發(fā)送命令的定時器
 @param 無
 @return 無
*/
void CreateSendCmdTimer(void)
{
    app_timer_create(&s_sendCmdTimer, APP_TIMER_MODE_REPEATED, timer_sendCmdCallback);
}

/**
 @brief 開啟發(fā)送命令的定時器
 @param 無
 @return 無
*/
void StartSendCmdTimer(void)
{       
    app_timer_start(s_sendCmdTimer, SEND_CMD_PERIOD, NULL);
}

/**
 @brief 關閉發(fā)送命令的定時器
 @param 無
 @return 無
*/
void StopSendCmdTimer(void)
{   
    app_timer_stop(s_sendCmdTimer);        
}

/**
 @brief 創(chuàng)建發(fā)送數(shù)據(jù)的定時器
 @param 無
 @return 無
*/
void CreateSendDataTimer(void)
{
    app_timer_create(&s_sendDataTimer, APP_TIMER_MODE_REPEATED, timer_sendDataCallback);
}

/**
 @brief 開啟發(fā)送數(shù)據(jù)的定時器
 @param 無
 @return 無
*/
void StartSendDataTimer(void)
{       
    app_timer_start(s_sendDataTimer, SEND_DATA_PERIOD, NULL);
}

/**
 @brief 關閉發(fā)送數(shù)據(jù)的定時器
 @param 無
 @return 無
*/
void StopSendDataTimer(void)
{   
    app_timer_stop(s_sendDataTimer);        
}

/**
 @brief 創(chuàng)建接收命令的定時器
 @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 創(chuàng)建重啟的定時器
 @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 處理接收數(shù)據(jù)
 @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 發(fā)送命令定時器的回調函數(shù)
 @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網(wǎng)絡
    {
        sendData("AT+CREG?\r\n");
        s_waitCmdTime = 90 * 10;                                                // 90秒
        s_sendCmdFlag = true;
    }
    else if(s_sendCmdStep == 5 && s_sendCmdFlag == false)                       // 查詢模組是否注冊上GPRS網(wǎng)絡
    {
        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 發(fā)送數(shù)據(jù)定時器的回調函數(shù)
 @param 無
 @return 無
*/
static void timer_sendDataCallback(void *arg)
{
    if(s_sendDataStep == 0)                                                     // 發(fā)送長度可變數(shù)據(jù)格式
    {
        sendData("AT+QISEND=0\r\n");                                            // >會被斷包滋觉,這里特殊處理
        s_waitCmdTime = 60 * 10;                                                // 60秒
        s_sendDataStep++;
    }
    else if(s_sendDataStep == 1 && s_sendDataFlag == false)                     // 發(fā)送實際數(shù)據(jù)
    {
        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)                     // 查詢數(shù)據(jù)是否達到服務器
    {
        sendData("AT+QISEND=0,0\r\n");
        s_waitCmdTime = 5 * 10;                                                 // 5秒
        s_waitCmdNum = 23;
        s_sendDataFlag = true;
    }
    else if(s_sendDataStep == 4)                                                // 完成發(fā)送
    {
        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 接收命令定時器的回調函數(shù)
 @param 無
 @return 無
*/
static void timer_recvCmdCallback(void *arg)
{
    if(s_waitCmdTime == 0)
    {
        StopRecvCmdTimer();
        return; 
    }

    s_waitCmdTime--;
}

/**
 @brief 重啟定時器的回調函數(shù)
 @param 無
 @return 無
*/
static void timer_resetCallback(void *arg)
{
    nrf_gpio_pin_write(EC200S_GPIO_PIN, 1);
    s_isReset = 0;
}

/**
 @brief 發(fā)送數(shù)據(jù)
 @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;                    // 接收計數(shù)
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 串口寫數(shù)據(jù)函數(shù)
 @param pData -[in] 寫入數(shù)據(jù)
 @param dataLen -[in] 寫入數(shù)據(jù)長度
 @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 串口讀取數(shù)據(jù)處理函數(shù)
 @param pEvent -[in] 串口事件
 @return 無
*/
static void uart_handleEvent(app_uart_evt_t *pEvent)
{
    uint8_t dataChar = 0;
    
    switch(pEvent->evt_type)
    {
        // 已接收到UART數(shù)據(jù)
        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;                              // 接收計數(shù)   
                if(!ReceiveCommandHandler())
                {
                    ReceiveDataHandler();
                }

                memset(s_uartReadDataBuffer, 0, s_index); 
                s_index = 0;
                s_begin = false;                
            }
        } break;

        // 接收過程中發(fā)生通信錯誤
        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(pEvent->data.error_communication);
            break;

        // app_uart模塊使用的FIFO模塊中出現(xiàn)錯誤
        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       // 發(fā)送引腳  
#define BOARD_UART_RX_IO                8       // 接收引腳
#define BOARD_UART_CTS_IO               7       // 流量控制發(fā)送清除第租、低有效
#define BOARD_UART_RTS_IO               9       // 流量控制發(fā)送請求、低有效

/*********************************************************************
 * 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();                                                           // 協(xié)議棧初始化
    gap_params_init();
    gatt_init();                                                                
    services_init();                                                            // 服務初始化
    advertising_init();                                                         // 廣播初始化
    conn_params_init();                                                         // 連接參數(shù)初始化

    advertising_start();                                                        // 開啟廣播
    application_timers_start();                                                 // 定時器應用開啟

    // Enter main loop.
    for(;;)
    {
        idle_state_handle();
    }
}

創(chuàng)建一個定時器每200毫秒進入一次回調函數(shù)

/**
 @brief 檢查網(wǎng)絡定時器的回調函數(shù)
 @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);                  // 接收服務器數(shù)據(jù)
        if(recvDataLen > 0)
        {
            // 進入處理
        }
    }
}

? 由 Leung 寫于 2020 年 12 月 4 日

? 參考:移遠 EC200S 模組(4G Cat.1 通信模組)AT指令測試 TCP/UDP 通信過程
    移遠EC20 R2.0 AT指令撥號流程
    Quectel EC20 R2.1 AT指令集(TCP/部分)

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末慎宾,一起剝皮案震驚了整個濱河市丐吓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌趟据,老刑警劉巖券犁,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異汹碱,居然都是意外死亡粘衬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門咳促,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稚新,“玉大人,你說我怎么就攤上這事跪腹」由荆” “怎么了?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵冲茸,是天一觀的道長屯阀。 經(jīng)常有香客問我,道長轴术,這世上最難降的妖魔是什么难衰? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮膳音,結果婚禮上召衔,老公的妹妹穿的比我還像新娘。我一直安慰自己祭陷,他們只是感情好,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布趣席。 她就那樣靜靜地躺著兵志,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宣肚。 梳的紋絲不亂的頭發(fā)上想罕,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機與錄音霉涨,去河邊找鬼按价。 笑死,一個胖子當著我的面吹牛笙瑟,可吹牛的內(nèi)容都是我干的楼镐。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼往枷,長吁一口氣:“原來是場噩夢啊……” “哼框产!你這毒婦竟也來了凄杯?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤秉宿,失蹤者是張志新(化名)和其女友劉穎戒突,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體描睦,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡膊存,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了忱叭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膝舅。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖窑多,靈堂內(nèi)的尸體忽然破棺而出仍稀,到底是詐尸還是另有隱情,我是刑警寧澤埂息,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布技潘,位于F島的核電站,受9級特大地震影響千康,放射性物質發(fā)生泄漏享幽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一拾弃、第九天 我趴在偏房一處隱蔽的房頂上張望值桩。 院中可真熱鬧,春花似錦豪椿、人聲如沸奔坟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咳秉。三九已至,卻和暖如春鸯隅,著一層夾襖步出監(jiān)牢的瞬間澜建,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工蝌以, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留炕舵,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓跟畅,卻偏偏與公主長得像咽筋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子碍彭,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內(nèi)容