文档
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 工程文件