编程技术分享

分享编程知识,探讨技术创新

0%

简介:Yap Cat.1物联网通讯终端基于上海合宙物联网出品的Air724模块。 本终端兼具通讯和边缘数据处理功能,数据传输运算等功能,可以胜任多数物联网应用。是您学习物联网的利器,项目完全免费开源

好的,作为一名高级嵌入式软件开发工程师,很高兴能与您一起探讨Yap Cat.1 物联网通讯终端的软件架构设计和实现。这是一个非常棒的项目,它展示了从概念到产品的完整嵌入式系统开发流程,并且完全开源,对于学习和实践物联网技术非常有价值。
关注微信公众号,提前获取相关推文

项目简介回顾:

Yap Cat.1 物联网通讯终端基于上海合宙 Air724 模块,具备通讯和边缘数据处理能力,能够胜任多种物联网应用。项目开源免费,是学习物联网的理想平台。

需求分析:

根据项目简介和图片,我们可以初步分析出以下需求:

  1. 核心功能:

    • Cat.1 物联网通讯: 利用 Air724 模块的 Cat.1 网络连接能力,实现数据上传和接收。
    • 边缘数据处理: 具备一定的本地数据处理能力,例如数据采集、预处理、过滤、简单计算等。
    • 用户交互: 通过按键进行用户输入,通过显示屏(OLED 或 LCD)进行信息展示。
  2. 硬件平台:

    • 主控芯片: Air724 模块内部的处理器 (通常是 ARM Cortex-A 系列),承担系统运行和应用逻辑处理。
    • 通讯模块: Air724 模块,负责 Cat.1 网络连接和数据传输。
    • 显示屏: OLED 或 LCD 显示屏,用于显示系统状态、用户界面和数据信息。
    • 按键: 矩阵键盘或独立按键,用于用户输入操作。
    • 其他外设: 根据具体应用场景,可能需要传感器接口 (例如 I2C, SPI, ADC, GPIO),存储器 (例如 Flash, SD 卡)。
  3. 软件需求:

    • 可靠性: 系统需要稳定可靠运行,保证数据传输的完整性和及时性。
    • 高效性: 代码需要高效执行,充分利用硬件资源,降低功耗。
    • 可扩展性: 软件架构需要易于扩展和维护,方便后续添加新功能和应用。
    • 实时性: 对于某些物联网应用,系统可能需要具备一定的实时响应能力。
    • 安全性: 考虑数据传输和设备自身的安全,例如数据加密、身份认证等 (如果需求明确)。
    • 低功耗: 对于电池供电的物联网终端,低功耗设计至关重要。

最适合的代码设计架构:分层架构 + 模块化设计

考虑到嵌入式系统的复杂性和物联网应用的特点,我推荐采用分层架构结合模块化设计的软件架构。这种架构具有以下优势:

  • 清晰的分层结构: 将系统划分为不同的层次,每一层负责特定的功能,降低了系统的复杂性,提高了可维护性。
  • 良好的模块化: 将每一层进一步细分为独立的模块,模块之间通过定义明确的接口进行交互,提高了代码的复用性和可扩展性。
  • 硬件抽象: 通过 HAL 层 (硬件抽象层) 隔离硬件差异,使得上层应用代码可以独立于具体的硬件平台,提高了代码的可移植性。
  • 易于测试和调试: 模块化的设计使得单元测试更加容易,分层架构也方便进行系统级的调试和集成。
  • 可扩展性强: 当需要添加新功能或应用时,只需要在相应的层次添加新的模块,而不需要修改其他层次的代码。

分层架构设计:

我建议将 Yap Cat.1 物联网终端的软件架构分为以下几个层次 (从底层到高层):

  1. 硬件抽象层 (HAL - Hardware Abstraction Layer):

    • 功能: 封装底层硬件的驱动和接口,向上层提供统一的硬件访问接口。
    • 模块:
      • GPIO 驱动模块: 控制 GPIO 引脚的输入输出。
      • UART 驱动模块: 控制 UART 串口的通信。
      • SPI 驱动模块: 控制 SPI 总线的通信 (如果使用 SPI 外设)。
      • I2C 驱动模块: 控制 I2C 总线的通信 (如果使用 I2C 外设)。
      • ADC 驱动模块: 控制 ADC 模数转换器 (如果使用 ADC)。
      • Timer 驱动模块: 提供定时器功能。
      • Display 驱动模块: 驱动显示屏 (OLED/LCD)。
      • Keypad 驱动模块: 驱动按键 (矩阵键盘/独立按键)。
      • Air724 模块驱动模块: 封装 Air724 模块的 AT 指令接口和数据通道。
      • Power Management 驱动模块: 控制电源管理功能 (例如低功耗模式)。
  2. 操作系统层 (OS Layer - 可选,但强烈推荐):

    • 功能: 提供任务调度、内存管理、同步机制、中断管理等操作系统级别的服务,提高系统的并发性和实时性。
    • 选择: 对于资源有限的嵌入式系统,可以选择轻量级的实时操作系统 (RTOS),例如 FreeRTOS, RT-Thread, uCOS-III 等。 我强烈推荐使用 FreeRTOS,因为它免费、开源、成熟、稳定,并且在嵌入式领域应用广泛。
    • 模块: (如果使用 RTOS)
      • 任务管理模块: 创建、删除、调度任务。
      • 内存管理模块: 动态内存分配和释放。
      • 同步与互斥模块: 信号量、互斥锁、事件标志组等。
      • 队列与消息传递模块: 任务间通信。
      • 中断管理模块: 中断服务例程的管理。
      • 定时器模块: 软件定时器。
  3. 中间件层 (Middleware Layer):

    • 功能: 提供一些通用的、与应用领域相关的服务和组件,简化应用开发。
    • 模块:
      • 网络协议栈模块: 实现 TCP/IP 协议栈,为网络通信提供基础 (Air724 模块通常已经内置 TCP/IP 协议栈,我们可能只需要封装其接口)。
      • MQTT 客户端模块: 实现 MQTT 协议客户端,用于轻量级的物联网消息发布/订阅 (强烈推荐使用 MQTT,它是物联网领域最常用的协议之一)。
      • HTTP 客户端模块: 实现 HTTP 协议客户端,用于与 Web 服务器进行交互 (例如上传数据到云平台,获取配置信息)。
      • 数据编解码模块: 处理数据编码和解码,例如 JSON, Protocol Buffers (根据实际应用选择)。
      • 日志管理模块: 记录系统运行日志,方便调试和故障排查。
      • 配置管理模块: 管理系统配置参数,例如网络配置、服务器地址等。
      • OTA 升级模块: 实现固件在线升级功能 (Over-The-Air)。
  4. 应用层 (Application Layer):

    • 功能: 实现具体的物联网应用逻辑,例如数据采集、边缘计算、数据传输、用户界面等。
    • 模块: 根据具体的应用场景进行模块划分。例如:
      • 数据采集模块: 从传感器或其他外设采集数据。
      • 数据处理模块: 对采集到的数据进行预处理、过滤、计算等边缘计算操作。
      • 数据传输模块: 将处理后的数据通过 Cat.1 网络上传到云平台或服务器。
      • 用户界面模块: 处理用户输入 (按键) 和显示输出 (显示屏),提供用户交互界面。
      • 系统管理模块: 负责系统初始化、运行状态监控、错误处理、电源管理等。

模块化设计:

在每一层内部,我们都应该采用模块化设计,将功能划分为独立的模块,每个模块负责特定的任务,模块之间通过定义明确的接口进行交互。

C 代码实现 (示例,并非完整 3000 行,但足够展示架构和关键代码):

由于 3000 行代码的要求在文本回复中难以完全满足,我将提供关键模块的 C 代码示例,以展示上述架构的设计思想和实现方法。 请注意,这仅仅是示例代码,实际项目中需要根据具体硬件和需求进行完善和优化。

1. HAL 层 (GPIO 驱动模块 - hal_gpio.hhal_gpio.c):

hal_gpio.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef HAL_GPIO_H
#define HAL_GPIO_H

#include <stdint.h>
#include <stdbool.h>

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT
} gpio_mode_t;

typedef enum {
GPIO_LEVEL_LOW,
GPIO_LEVEL_HIGH
} gpio_level_t;

typedef uint32_t gpio_pin_t; // 定义 GPIO 引脚类型,例如使用位掩码表示多个引脚

// 初始化 GPIO 引脚
bool hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode);

// 设置 GPIO 引脚输出电平
bool hal_gpio_write(gpio_pin_t pin, gpio_level_t level);

// 读取 GPIO 引脚输入电平
gpio_level_t hal_gpio_read(gpio_pin_t pin);

#endif // HAL_GPIO_H

hal_gpio.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include "hal_gpio.h"
// 假设 Air724 模块的 GPIO 寄存器定义和操作函数
// (需要参考 Air724 模块的 SDK 或硬件手册)

// 示例:假设 GPIO 寄存器地址定义
#define GPIO_REG_BASE (0x40000000) // 假设的 GPIO 基地址
#define GPIO_MODE_REG (GPIO_REG_BASE + 0x00) // 假设的 GPIO 模式寄存器地址
#define GPIO_OUTPUT_REG (GPIO_REG_BASE + 0x04) // 假设的 GPIO 输出寄存器地址
#define GPIO_INPUT_REG (GPIO_REG_BASE + 0x08) // 假设的 GPIO 输入寄存器地址

bool hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode) {
// 根据 pin 和 mode 配置 GPIO 寄存器
// (具体的寄存器配置操作需要参考 Air724 模块的硬件手册)
// 例如:设置 GPIO_MODE_REG 的相应位为输入或输出模式
// ... 硬件寄存器操作 ...
return true; // 假设初始化成功
}

bool hal_gpio_write(gpio_pin_t pin, gpio_level_t level) {
// 根据 pin 和 level 设置 GPIO 输出寄存器
// (具体的寄存器配置操作需要参考 Air724 模块的硬件手册)
// 例如:设置 GPIO_OUTPUT_REG 的相应位为高电平或低电平
// ... 硬件寄存器操作 ...
return true; // 假设写入成功
}

gpio_level_t hal_gpio_read(gpio_pin_t pin) {
// 读取 GPIO 输入寄存器的值,并根据 pin 返回相应的电平
// (具体的寄存器读取操作需要参考 Air724 模块的硬件手册)
// 例如:读取 GPIO_INPUT_REG 的值,并提取 pin 对应的位
// ... 硬件寄存器操作 ...
// 假设读取到的电平
return GPIO_LEVEL_LOW; // 示例:默认返回低电平
}

2. 设备驱动层 (Keypad 驱动模块 - driver_keypad.hdriver_keypad.c):

driver_keypad.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef DRIVER_KEYPAD_H
#define DRIVER_KEYPAD_H

#include <stdint.h>

typedef enum {
KEY_NONE,
KEY_0, KEY_1, KEY_2, KEY_3,
KEY_4, KEY_5, KEY_6, KEY_7,
KEY_8, KEY_9, KEY_STAR, KEY_HASH,
KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT,
KEY_OK, KEY_CANCEL,
// ... 可以根据实际按键定义更多按键值
} keypad_key_t;

// 初始化键盘驱动
bool keypad_init(void);

// 获取按键输入,阻塞等待按键按下并释放,返回按键值
keypad_key_t keypad_get_key(void);

// 获取按键状态,非阻塞,返回当前按下的按键值,如果没有按键按下则返回 KEY_NONE
keypad_key_t keypad_scan_key(void);

#endif // DRIVER_KEYPAD_H

driver_keypad.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include "driver_keypad.h"
#include "hal_gpio.h" // 使用 HAL 层 GPIO 驱动
#include "FreeRTOS.h" // 如果使用 FreeRTOS,需要包含头文件
#include "task.h"

// 假设使用 4x4 矩阵键盘,定义行和列的 GPIO 引脚
#define KEYPAD_ROW_1_PIN (1 << 0) // 假设 GPIO 引脚定义
#define KEYPAD_ROW_2_PIN (1 << 1)
#define KEYPAD_ROW_3_PIN (1 << 2)
#define KEYPAD_ROW_4_PIN (1 << 3)

#define KEYPAD_COL_1_PIN (1 << 4)
#define KEYPAD_COL_2_PIN (1 << 5)
#define KEYPAD_COL_3_PIN (1 << 6)
#define KEYPAD_COL_4_PIN (1 << 7)

static const gpio_pin_t keypad_rows[] = {KEYPAD_ROW_1_PIN, KEYPAD_ROW_2_PIN, KEYPAD_ROW_3_PIN, KEYPAD_ROW_4_PIN};
static const gpio_pin_t keypad_cols[] = {KEYPAD_COL_1_PIN, KEYPAD_COL_2_PIN, KEYPAD_COL_3_PIN, KEYPAD_COL_4_PIN};

static const keypad_key_t keypad_map[4][4] = {
{KEY_1, KEY_2, KEY_3, KEY_A}, // 假设按键布局
{KEY_4, KEY_5, KEY_6, KEY_B},
{KEY_7, KEY_8, KEY_9, KEY_C},
{KEY_STAR, KEY_0, KEY_HASH, KEY_D}
};

bool keypad_init(void) {
// 初始化行引脚为输出,列引脚为输入
for (int i = 0; i < 4; i++) {
hal_gpio_init(keypad_rows[i], GPIO_MODE_OUTPUT);
hal_gpio_write(keypad_rows[i], GPIO_LEVEL_HIGH); // 初始输出高电平
}
for (int i = 0; i < 4; i++) {
hal_gpio_init(keypad_cols[i], GPIO_MODE_INPUT);
}
return true;
}

keypad_key_t keypad_get_key(void) {
keypad_key_t key = KEY_NONE;
while (key == KEY_NONE) {
key = keypad_scan_key();
vTaskDelay(pdMS_TO_TICKS(10)); // 简单延时去抖动 (如果使用 FreeRTOS)
}
while (keypad_scan_key() != KEY_NONE) { // 等待按键释放
vTaskDelay(pdMS_TO_TICKS(10));
}
return key;
}

keypad_key_t keypad_scan_key(void) {
for (int row = 0; row < 4; row++) {
hal_gpio_write(keypad_rows[row], GPIO_LEVEL_LOW); // 拉低当前行
for (int col = 0; col < 4; col++) {
if (hal_gpio_read(keypad_cols[col]) == GPIO_LEVEL_LOW) { // 检测到列为低电平
hal_gpio_write(keypad_rows[row], GPIO_LEVEL_HIGH); // 恢复行电平
return keypad_map[row][col]; // 返回按键值
}
}
hal_gpio_write(keypad_rows[row], GPIO_LEVEL_HIGH); // 恢复行电平
}
return KEY_NONE; // 没有按键按下
}

3. 中间件层 (MQTT 客户端模块 - middleware_mqtt.hmiddleware_mqtt.c):

middleware_mqtt.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#ifndef MIDDLEWARE_MQTT_H
#define MIDDLEWARE_MQTT_H

#include <stdint.h>
#include <stdbool.h>

// MQTT 连接配置
typedef struct {
char *client_id;
char *server_ip;
uint16_t server_port;
char *username;
char *password;
} mqtt_config_t;

// 初始化 MQTT 客户端
bool mqtt_client_init(const mqtt_config_t *config);

// 连接 MQTT 服务器
bool mqtt_client_connect(void);

// 断开 MQTT 连接
bool mqtt_client_disconnect(void);

// 发布 MQTT 消息
bool mqtt_client_publish(const char *topic, const char *payload, size_t payload_len);

// 订阅 MQTT 主题
bool mqtt_client_subscribe(const char *topic);

// 设置 MQTT 消息接收回调函数
typedef void (*mqtt_message_callback_t)(const char *topic, const char *payload, size_t payload_len);
void mqtt_client_set_message_callback(mqtt_message_callback_t callback);

#endif // MIDDLEWARE_MQTT_H

middleware_mqtt.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include "middleware_mqtt.h"
#include "air724_module.h" // 假设 Air724 模块驱动头文件 (需要根据实际情况修改)
#include <string.h>
#include <stdio.h>

static mqtt_config_t current_config;
static mqtt_message_callback_t message_callback = NULL;

bool mqtt_client_init(const mqtt_config_t *config) {
memcpy(&current_config, config, sizeof(mqtt_config_t));
return true;
}

bool mqtt_client_connect(void) {
// 使用 Air724 模块的 AT 指令或 SDK 函数建立 MQTT 连接
// (具体的 AT 指令或 SDK 函数需要参考 Air724 模块的文档)
char connect_cmd[256];
snprintf(connect_cmd, sizeof(connect_cmd),
"AT+QMTCFG=0,0,\"%s\",%d,1\r\n" // 假设的 AT 指令格式 (需要查阅 Air724 文档)
"AT+QMTOPEN=0\r\n"
"AT+QMTCONN=0,\"%s\",\"%s\",\"%s\"\r\n",
current_config.server_ip, current_config.server_port,
current_config.client_id, current_config.username, current_config.password);

if (air724_module_send_at_command(connect_cmd, "OK", 5000)) { // 假设 air724_module_send_at_command 函数存在
return true;
} else {
return false;
}
}

bool mqtt_client_disconnect(void) {
// 使用 Air724 模块的 AT 指令断开 MQTT 连接
// (具体的 AT 指令需要参考 Air724 模块的文档)
if (air724_module_send_at_command("AT+QMTDISC=0\r\n", "OK", 5000)) {
return true;
} else {
return false;
}
}

bool mqtt_client_publish(const char *topic, const char *payload, size_t payload_len) {
// 使用 Air724 模块的 AT 指令发布 MQTT 消息
// (具体的 AT 指令需要参考 Air724 模块的文档)
char publish_cmd[512]; // 预留足够空间
snprintf(publish_cmd, sizeof(publish_cmd),
"AT+QMTPUB=0,0,0,0,\"%s\",%d\r\n", // 假设的 AT 指令格式
topic, payload_len);

if (air724_module_send_at_command(publish_cmd, ">", 2000)) { // 等待 ">" 提示符
if (air724_module_send_data((const uint8_t *)payload, payload_len, "OK", 5000)) { // 发送数据
return true;
}
}
return false;
}

bool mqtt_client_subscribe(const char *topic) {
// 使用 Air724 模块的 AT 指令订阅 MQTT 主题
// (具体的 AT 指令需要参考 Air724 模块的文档)
char subscribe_cmd[256];
snprintf(subscribe_cmd, sizeof(subscribe_cmd),
"AT+QMTSUB=0,1,\"%s\",0\r\n", // 假设的 AT 指令格式
topic);

if (air724_module_send_at_command(subscribe_cmd, "OK", 5000)) {
return true;
} else {
return false;
}
}

void mqtt_client_set_message_callback(mqtt_message_callback_t callback) {
message_callback = callback;
// 需要在 Air724 模块驱动中处理 MQTT 消息接收事件,并调用此回调函数
// (具体实现方式取决于 Air724 模块的 SDK 或驱动接口)
}

// 假设在 Air724 模块驱动中,当接收到 MQTT 消息时,会调用此函数
void mqtt_message_received_handler(const char *topic, const char *payload, size_t payload_len) {
if (message_callback != NULL) {
message_callback(topic, payload, payload_len);
}
}

4. 应用层 (数据采集模块 - app_data_acquisition.happ_data_acquisition.c):

app_data_acquisition.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef APP_DATA_ACQUISITION_H
#define APP_DATA_ACQUISITION_H

#include <stdint.h>
#include <stdbool.h>

// 初始化数据采集模块
bool data_acquisition_init(void);

// 采集数据
typedef struct {
float temperature;
float humidity;
// ... 其他传感器数据 ...
} sensor_data_t;

bool data_acquisition_get_data(sensor_data_t *data);

#endif // APP_DATA_ACQUISITION_H

app_data_acquisition.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "app_data_acquisition.h"
#include "hal_adc.h" // 假设使用 ADC 采集传感器数据
#include "hal_i2c.h" // 假设使用 I2C 接口传感器
#include "driver_sensor_sht30.h" // 假设使用 SHT30 温湿度传感器驱动

bool data_acquisition_init(void) {
// 初始化 ADC 和 I2C 总线 (如果需要)
// 初始化传感器驱动
sht30_init(); // 初始化 SHT30 传感器
return true;
}

bool data_acquisition_get_data(sensor_data_t *data) {
// 从传感器读取数据
if (sht30_read_temp_humidity(&data->temperature, &data->humidity)) {
// 数据读取成功
return true;
} else {
// 数据读取失败
return false;
}
}

5. 应用层 (主应用逻辑 - main.c):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "driver_keypad.h"
#include "driver_display.h"
#include "middleware_mqtt.h"
#include "app_data_acquisition.h"
#include "app_data_processing.h" // 假设存在数据处理模块
#include "app_user_interface.h" // 假设存在用户界面模块

// MQTT 配置信息
mqtt_config_t mqtt_cfg = {
.client_id = "YapCat1_Client1",
.server_ip = "your_mqtt_broker_ip", // 替换为你的 MQTT Broker IP 地址
.server_port = 1883,
.username = "your_mqtt_username", // 替换为你的 MQTT 用户名
.password = "your_mqtt_password" // 替换为你的 MQTT 密码
};

// MQTT 消息接收回调函数
void mqtt_message_callback(const char *topic, const char *payload, size_t payload_len) {
printf("MQTT Message Received:\r\n");
printf("Topic: %s\r\n", topic);
printf("Payload: %.*s\r\n", payload_len, payload);
// 在这里处理接收到的 MQTT 消息,例如控制设备行为
}

void app_task(void *pvParameters) {
keypad_key_t key;
sensor_data_t sensor_data;
char display_buffer[32];
char mqtt_payload[128];

// 初始化各个模块
keypad_init();
display_init();
mqtt_client_init(&mqtt_cfg);
mqtt_client_set_message_callback(mqtt_message_callback);
data_acquisition_init();

display_clear();
display_print("Yap Cat.1 IoT\nTerminal\nConnecting...\n");

if (mqtt_client_connect()) {
display_clear();
display_print("MQTT Connected!\nSubscribing...\n");
mqtt_client_subscribe("yapcat1/control"); // 订阅控制主题

while (1) {
key = keypad_scan_key();
if (key != KEY_NONE) {
printf("Key Pressed: %d\r\n", key);
// 根据按键值执行相应操作 (例如菜单切换、参数设置等)
app_ui_handle_keypad_input(key); // 调用用户界面模块处理按键

}

if (data_acquisition_get_data(&sensor_data)) {
// 数据采集成功
app_data_processing(&sensor_data); // 数据预处理 (假设存在数据处理模块)

snprintf(mqtt_payload, sizeof(mqtt_payload),
"{\"temp\":%.2f,\"humidity\":%.2f}",
sensor_data.temperature, sensor_data.humidity);
mqtt_client_publish("yapcat1/data", mqtt_payload, strlen(mqtt_payload)); // 发布数据到 MQTT

snprintf(display_buffer, sizeof(display_buffer),
"Temp: %.1fC\nHumidity: %.1f%%\n",
sensor_data.temperature, sensor_data.humidity);
display_clear();
display_print(display_buffer);

} else {
// 数据采集失败
display_clear();
display_print("Data Read Error!\n");
}

vTaskDelay(pdMS_TO_TICKS(2000)); // 2 秒采集和上传一次数据
}
} else {
display_clear();
display_print("MQTT Connect Fail!\n");
while(1); // 错误处理,可以考虑重启或重试连接
}
}

int main() {
// 系统初始化 (例如时钟、外设初始化) - 这部分代码需要根据 Air724 模块的 SDK 进行编写
system_init(); // 假设的系统初始化函数

// 创建应用任务
xTaskCreate(app_task, "AppTask", 2048, NULL, 2, NULL); // 假设堆栈大小为 2048 字节

// 启动 FreeRTOS 调度器
vTaskStartScheduler();

// 理论上不会执行到这里
return 0;
}

项目中采用的技术和方法:

  1. 分层架构和模块化设计: 如上所述,提高代码的可维护性、可扩展性、可移植性。
  2. 实时操作系统 (FreeRTOS): 提高系统的并发性和实时性,方便任务管理和资源调度。
  3. C 语言编程: 高效、灵活、底层控制能力强,适合嵌入式系统开发。
  4. 硬件抽象层 (HAL): 隔离硬件差异,提高代码的可移植性。
  5. MQTT 协议: 轻量级、发布/订阅模式,适合物联网数据传输。
  6. AT 指令 (Air724 模块): 通过 AT 指令控制 Air724 模块进行 Cat.1 网络连接和数据传输。
  7. 事件驱动编程: 例如按键事件、MQTT 消息接收事件,提高系统响应速度。
  8. 低功耗设计: 在 HAL 层和应用层都考虑功耗优化 (例如使用低功耗模式、优化数据传输频率)。
  9. 日志管理: 方便调试和故障排查。
  10. 版本控制 (Git): 进行代码版本管理,方便团队协作和代码维护 (虽然代码示例中没有体现,但在实际项目中非常重要)。
  11. 测试和验证: 单元测试、集成测试、系统测试,保证代码质量和系统稳定性。

总结:

以上代码示例和架构设计方案为 Yap Cat.1 物联网通讯终端项目提供了一个可靠、高效、可扩展的系统平台的基础框架。 实际项目中,还需要根据具体的硬件细节、应用需求和 Air724 模块的 SDK 文档,进行更深入的开发和完善。

后续步骤和建议:

  1. 详细阅读 Air724 模块的硬件手册和 SDK 文档: 了解模块的硬件资源、AT 指令集、SDK 函数库,这是进行代码开发的基础。
  2. 搭建开发环境: 安装 Air724 模块的开发工具链 (例如编译器、调试器),配置开发环境。
  3. 编写 HAL 层驱动: 根据 Air724 模块的硬件手册,编写 GPIO、UART、SPI、I2C 等 HAL 层驱动,封装底层硬件操作。
  4. 移植 FreeRTOS (如果选择使用): 根据 Air724 模块的平台,移植 FreeRTOS 操作系统,配置 RTOS 环境。
  5. 完善设备驱动层: 编写显示屏、按键、传感器等设备驱动,基于 HAL 层接口。
  6. 实现中间件层模块: 编写 MQTT 客户端、HTTP 客户端、数据编解码等中间件模块,简化应用开发。
  7. 开发应用层功能: 根据具体的物联网应用需求,开发数据采集、边缘计算、数据传输、用户界面等应用层模块。
  8. 进行充分的测试和验证: 编写单元测试用例,进行模块级和系统级测试,确保代码质量和系统稳定性。
  9. 持续维护和升级: 关注项目运行状态,进行 bug 修复和功能升级,考虑 OTA 升级方案。

希望这个详细的解答和代码示例能够帮助您理解 Yap Cat.1 物联网通讯终端的软件架构设计和实现。 请记住,实际的嵌入式系统开发是一个复杂而迭代的过程,需要不断学习、实践和优化。 祝您的项目顺利成功!

欢迎关注我的其它发布渠道