主循环

知识库
知识库文档
/firmware/通信模块/DX-CT511N-B/DX-CT511N-B STM32 HAL 驱动代码例程 - HTTP/GNSS/初始化/主循环.md

文档

DX-CT511N-B 驱动实现(下篇):HTTP、GNSS、初始化与主循环

接上篇 module_4g.c,以下为 HTTP、GNSS、网络状态、模块初始化及主循环示例。


2. 驱动实现 module_4g.c(下篇)

/* ================================================================
 *  HTTP 操作
 * ================================================================ */

int HTTP_Post(const char *url, const char *body,
              char *resp, uint16_t resp_size)
{
    int ret;
    ret = AT_SendCmd("AT+HTTPINIT", at_resp_buf, sizeof(at_resp_buf),
                     AT_TIMEOUT, "OK");
    if (ret != 0) goto http_exit;

    {
        char cmd[512];
        snprintf(cmd, sizeof(cmd), "AT+HTTPPARA=\"URL\",\"%s\"", url);
        ret = AT_SendCmd(cmd, at_resp_buf, sizeof(at_resp_buf),
                         AT_TIMEOUT, "OK");
        if (ret != 0) goto http_exit;
    }

    ret = AT_SendCmd("AT+HTTPPARA=\"CONTENT\",\"application/json\"",
                     at_resp_buf, sizeof(at_resp_buf),
                     AT_TIMEOUT, "OK");
    if (ret != 0) goto http_exit;

    {
        char cmd[64];
        uint16_t body_len = (uint16_t)strlen(body);
        snprintf(cmd, sizeof(cmd), "AT+HTTPDATA=%d,10000", body_len);
        ret = AT_SendCmd(cmd, at_resp_buf, sizeof(at_resp_buf),
                         AT_TIMEOUT, "DOWNLOAD");
        if (ret != 0) goto http_exit;
    }

    HAL_UART_Transmit(&huart2, (uint8_t *)body, strlen(body), 2000);
    HAL_Delay(300);

    ret = AT_SendCmd("AT+HTTPACTION=1", at_resp_buf, sizeof(at_resp_buf),
                     AT_LONG_TIMEOUT, "+HTTPACTION:");
    if (ret != 0) goto http_exit;

    ret = AT_SendCmd("AT+HTTPREAD", at_resp_buf, sizeof(at_resp_buf),
                     AT_LONG_TIMEOUT, "OK");
    if (resp && resp_size > 0) {
        strncpy(resp, at_resp_buf, resp_size - 1);
        resp[resp_size - 1] = '\0';
    }

http_exit:
    AT_SendCmd("AT+HTTPTERM", at_resp_buf, sizeof(at_resp_buf),
               AT_TIMEOUT, "OK");
    return ret;
}

int HTTP_Get(const char *url, char *resp, uint16_t resp_size)
{
    int ret;
    ret = AT_SendCmd("AT+HTTPINIT", at_resp_buf, sizeof(at_resp_buf),
                     AT_TIMEOUT, "OK");
    if (ret != 0) goto http_exit;

    {
        char cmd[512];
        snprintf(cmd, sizeof(cmd), "AT+HTTPPARA=\"URL\",\"%s\"", url);
        ret = AT_SendCmd(cmd, at_resp_buf, sizeof(at_resp_buf),
                         AT_TIMEOUT, "OK");
        if (ret != 0) goto http_exit;
    }

    ret = AT_SendCmd("AT+HTTPACTION=0", at_resp_buf, sizeof(at_resp_buf),
                     AT_LONG_TIMEOUT, "+HTTPACTION:");
    if (ret != 0) goto http_exit;

    ret = AT_SendCmd("AT+HTTPREAD", at_resp_buf, sizeof(at_resp_buf),
                     AT_LONG_TIMEOUT, "OK");
    if (resp && resp_size > 0) {
        strncpy(resp, at_resp_buf, resp_size - 1);
        resp[resp_size - 1] = '\0';
    }

http_exit:
    AT_SendCmd("AT+HTTPTERM", at_resp_buf, sizeof(at_resp_buf),
               AT_TIMEOUT, "OK");
    return ret;
}

/* ================================================================
 *  GNSS/GPS 操作
 *  响应格式: +CGPSINFO: lat,NS,lon,EW,date,time,alt,speed,course
 *  例: +CGPSINFO: 2232.4567,N,11356.7890,E,240225,143000,45.2,0.0,180.5
 * ================================================================ */

int GPS_Enable(void)
{
    return AT_SendCmd("AT+CGPS=1", at_resp_buf, sizeof(at_resp_buf),
                      AT_TIMEOUT, "OK");
}

int GPS_Disable(void)
{
    return AT_SendCmd("AT+CGPS=0", at_resp_buf, sizeof(at_resp_buf),
                      AT_TIMEOUT, "OK");
}

int GPS_GetPosition(float *lat, float *lon, float *alt,
                    float *speed, float *course)
{
    int ret = AT_SendCmd("AT+CGPSINFO", at_resp_buf, sizeof(at_resp_buf),
                         AT_TIMEOUT, "+CGPSINFO:");
    if (ret != 0) return -1;

    char *p = strstr(at_resp_buf, "+CGPSINFO:");
    if (p == NULL) return -1;
    p += strlen("+CGPSINFO:");
    while (*p == ' ') p++;

    if (strncmp(p, ",,,,,,,", 7) == 0) return -1;

    char token[32];
    int  deg;
    float minutes;
    char *comma;

    /* 纬度 ddmm.mmmm */
    comma = strchr(p, ',');
    if (comma == NULL) return -1;
    memcpy(token, p, comma - p);
    token[comma - p] = '\0';
    deg = atoi(token) / 100;
    minutes = atof(token + (deg >= 10 ? 2 : 1));
    *lat = deg + minutes / 60.0f;
    p = comma + 1;

    /* N/S */
    comma = strchr(p, ',');
    if (comma == NULL) return -1;
    if (*p == 'S') *lat = -*lat;
    p = comma + 1;

    /* 经度 dddmm.mmmm */
    comma = strchr(p, ',');
    if (comma == NULL) return -1;
    memcpy(token, p, comma - p);
    token[comma - p] = '\0';
    deg = atoi(token) / 100;
    minutes = atof(token + (deg >= 100 ? 3 : 2));
    *lon = deg + minutes / 60.0f;
    p = comma + 1;

    /* E/W */
    comma = strchr(p, ',');
    if (comma == NULL) return -1;
    if (*p == 'W') *lon = -*lon;
    p = comma + 1;

    /* 跳过 date, time */
    p = strchr(p, ','); if (p) p++;
    p = strchr(p, ','); if (p) p++;

    /* 海拔 */
    comma = strchr(p, ',');
    if (comma) {
        memcpy(token, p, comma - p);
        token[comma - p] = '\0';
        *alt = atof(token);
        p = comma + 1;
    } else { *alt = 0; }

    /* 速度 */
    comma = strchr(p, ',');
    if (comma) {
        memcpy(token, p, comma - p);
        token[comma - p] = '\0';
        *speed = atof(token);
        p = comma + 1;
    } else { *speed = 0; }

    /* 方位角 */
    *course = atof(p);
    return 0;
}

/* ================================================================
 *  网络状态查询
 * ================================================================ */

int Network_GetSignalQuality(int *rssi, int *ber)
{
    int ret = AT_SendCmd("AT+CSQ", at_resp_buf, sizeof(at_resp_buf),
                         AT_TIMEOUT, "+CSQ:");
    if (ret != 0) return -1;

    char *p = strstr(at_resp_buf, "+CSQ:");
    if (p == NULL) return -1;
    int r, b;
    if (sscanf(p, "+CSQ: %d,%d", &r, &b) == 2) {
        if (rssi) *rssi = (r == 99) ? -113 : (-113 + r * 2);
        if (ber)  *ber  = b;
        return 0;
    }
    return -1;
}

int Network_GetIP(char *ip, uint16_t size)
{
    int ret = AT_SendCmd("AT+CIFSR", at_resp_buf, sizeof(at_resp_buf),
                         AT_TIMEOUT, ".");
    if (ret != 0) return -1;
    if (ip && size > 0) {
        strncpy(ip, at_resp_buf, size - 1);
        ip[size - 1] = '\0';
    }
    return 0;
}

/* ================================================================
 *  模块初始化 (上电 → AT测试 → SIM → 注网 → MQTT → GNSS)
 * ================================================================ */

int Module4G_Init(void)
{
    LOG("Module4G Init start...");

    /* 1. PWRKEY 开机:拉低 1.2s 后释放 */
    HAL_GPIO_WritePin(PWRKEY_PORT, PWRKEY_PIN, GPIO_PIN_RESET);
    HAL_Delay(1200);
    HAL_GPIO_WritePin(PWRKEY_PORT, PWRKEY_PIN, GPIO_PIN_SET);

    /* 2. 等待模块启动 */
    LOG("Waiting for module boot...");
    HAL_Delay(6000);

    /* 3. 启动中断接收 */
    UART4G_StartReceive();

    /* 4. AT 测试 */
    if (AT_SendCmd("AT", at_resp_buf, sizeof(at_resp_buf),
                   AT_TIMEOUT, "OK") != 0) {
        LOG("Module AT test FAILED!");
        return -1;
    }
    LOG("AT test OK");

    /* 5. SIM 卡检测 */
    if (AT_SendCmd("AT+CPIN?", at_resp_buf, sizeof(at_resp_buf),
                   AT_TIMEOUT, "+CPIN: READY") != 0) {
        LOG("SIM card not ready!");
        return -2;
    }
    LOG("SIM card ready");

    /* 6. 信号强度 */
    {
        int rssi;
        if (Network_GetSignalQuality(&rssi, NULL) == 0)
            LOG("Signal RSSI: %d dBm", rssi);
    }

    /* 7. 网络注册 */
    AT_SendCmd("AT+CGREG?", at_resp_buf, sizeof(at_resp_buf),
               AT_TIMEOUT, "OK");

    /* 8. 设置 APN */
    if (AT_SendCmd("AT+CSTT=\"CMNET\"", at_resp_buf, sizeof(at_resp_buf),
                   AT_TIMEOUT, "OK") != 0) {
        LOG("APN set failed");
        return -3;
    }

    /* 9. 激活 PDP */
    if (AT_SendCmd("AT+CIICR", at_resp_buf, sizeof(at_resp_buf),
                   AT_LONG_TIMEOUT, "OK") != 0) {
        LOG("PDP activation failed");
        return -4;
    }
    g_device.network_ready = true;
    LOG("Network ready");

    /* 10. 获取 IP */
    {
        char ip[32];
        if (Network_GetIP(ip, sizeof(ip)) == 0)
            LOG("Device IP: %s", ip);
    }

    /* 11. 连接 MQTT */
    {
        char client_id[48];
        snprintf(client_id, sizeof(client_id), "dev_%s", g_device.mac_addr);
        if (MQTT_Connect(SERVER_HOST, SERVER_PORT, client_id, 60) == 0) {
            g_device.mqtt_connected = true;
            LOG("MQTT connected to %s:%d", SERVER_HOST, SERVER_PORT);
        } else {
            LOG("MQTT connect failed");
        }
    }

    /* 12. 开启 GNSS */
    GPS_Enable();
    LOG("GNSS enabled");
    LOG("Module4G Init complete!");
    return 0;
}

int Module4G_Reset(void)
{
    LOG("Resetting module...");
    if (g_device.mqtt_connected) {
        MQTT_Disconnect();
        g_device.mqtt_connected = false;
    }
    AT_SendCmd("AT+CFUN=0", at_resp_buf, sizeof(at_resp_buf),
               AT_TIMEOUT, "OK");
    HAL_Delay(1000);
    AT_SendCmd("AT+CFUN=1", at_resp_buf, sizeof(at_resp_buf),
               AT_TIMEOUT, "OK");
    HAL_Delay(5000);
    g_device.network_ready = false;
    return 0;
}

void Module4G_Poll(void)
{
    if (g_device.mqtt_connected) {
        char topic[64];
        char payload[256];
        if (MQTT_HasMessage(topic, sizeof(topic),
                            payload, sizeof(payload))) {
            LOG("MQTT CMD: %s -> %s", topic, payload);
            /* 在此处理下行业务指令 */
        }
    }
}

3. 主程序示例 main.c

#include "main.h"
#include "module_4g.h"
#include <stdio.h>

UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
extern device_ctx_t g_device;

/* ---- 外设初始化 (由 CubeMX 生成骨架) ---- */

static void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitStruct.Pin   = GPIO_PIN_9;
    GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull  = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);
}

static void MX_USART2_UART_Init(void)
{
    huart2.Instance          = USART2;
    huart2.Init.BaudRate     = 115200;
    huart2.Init.WordLength   = UART_WORDLENGTH_8B;
    huart2.Init.StopBits     = UART_STOPBITS_1;
    huart2.Init.Parity       = UART_PARITY_NONE;
    huart2.Init.Mode         = UART_MODE_TX_RX;
    huart2.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
    huart2.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&huart2);
}

static void MX_USART1_UART_Init(void)
{
    huart1.Instance          = USART1;
    huart1.Init.BaudRate     = 115200;
    huart1.Init.WordLength   = UART_WORDLENGTH_8B;
    huart1.Init.StopBits     = UART_STOPBITS_1;
    huart1.Init.Parity       = UART_PARITY_NONE;
    huart1.Init.Mode         = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl    = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&huart1);
}

/* ============== 主函数 ============== */

int main(void)
{
    HAL_Init();
    SystemClock_Config();   /* CubeMX 生成 */

    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_USART2_UART_Init();

    /* 设置设备唯一标识 */
    strcpy(g_device.mac_addr, "AABBCCDDEEFF");

    printf("=== DX-CT511N-B 4G+GNSS Demo ===\r\n");

    /* 初始化模块,失败则复位重试 */
    if (Module4G_Init() != 0) {
        printf("[ERR] Init failed, retrying...\r\n");
        Module4G_Reset();
        HAL_Delay(3000);
        Module4G_Init();
    }

    /* 订阅指令主题 */
    if (g_device.mqtt_connected) {
        char cmd_topic[64];
        snprintf(cmd_topic, sizeof(cmd_topic),
                 "dev/%s/cmd", g_device.mac_addr);
        MQTT_Subscribe(cmd_topic);
    }

    /* ============== 主循环 ============== */
    uint32_t last_report = 0;
    uint32_t last_gps    = 0;

    while (1) {
        uint32_t now = HAL_GetTick();

        /* 后台轮询 MQTT 消息 */
        Module4G_Poll();

        /* 每 30s 上报遥测 */
        if (g_device.mqtt_connected && (now - last_report) >= 30000) {
            last_report = now;
            int rssi;
            Network_GetSignalQuality(&rssi, NULL);
            char payload[256];
            snprintf(payload, sizeof(payload),
                     "{\"rssi\":%d,\"uptime\":%lu}", rssi, now / 1000);
            char tele_topic[64];
            snprintf(tele_topic, sizeof(tele_topic),
                     "dev/%s/telemetry", g_device.mac_addr);
            MQTT_Publish(tele_topic, payload);
        }

        /* 每 5s 获取 GPS 并上报 */
        if (g_device.mqtt_connected && (now - last_gps) >= 5000) {
            last_gps = now;
            float lat = 0, lon = 0, alt = 0, speed = 0, course = 0;
            if (GPS_GetPosition(&lat, &lon, &alt, &speed, &course) == 0) {
                char gps_payload[256];
                snprintf(gps_payload, sizeof(gps_payload),
                         "{\"lat\":%.6f,\"lon\":%.6f,\"alt\":%.1f,"
                         "\"speed\":%.1f,\"course\":%.1f}",
                         lat, lon, alt, speed, course);
                char gps_topic[64];
                snprintf(gps_topic, sizeof(gps_topic),
                         "dev/%s/gps", g_device.mac_addr);
                MQTT_Publish(gps_topic, gps_payload);
            }
        }

        HAL_Delay(100);
    }
}

4. 关键调试技巧

问题 排查方法
AT 无响应 检查 TX/RX 是否交叉、共地、波特率 115200
SIM 卡不识别 测 SIM_VCC 是否为 1.8V/3V,检查 SIM 座焊接
注网失败 AT+CSQ 看信号,AT+CGREG? 看注册状态
MQTT 连不上 先用 AT+PING=broker_ip 测网络可达性
GPS 不定位 确认天线为有源天线,放到室外开阔处冷启动需 30s~2min
HTTP 超时 AT_LONG_TIMEOUT 至少 15s,弱信号环境可能更长

5. 工程结构建议

Project/
├── Core/
│   ├── Inc/
│   │   └── module_4g.h
│   └── Src/
│       ├── main.c
│       ├── module_4g.c
│       └── stm32f1xx_it.c      ← HAL_UART_RxCpltCallback 在此
├── Drivers/
│   └── STM32F1xx_HAL_Driver/
└── .ioc                          ← CubeMX 工程文件

信息

路径
/firmware/通信模块/DX-CT511N-B/DX-CT511N-B STM32 HAL 驱动代码例程 - HTTP/GNSS/初始化/主循环.md
更新时间
2026/5/26