编程技术分享

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

0%

简介:基于启凡科创的物联网加热台优化而来。

很高兴能为您详细解析并设计这个基于启帆科创物联网加热台优化的嵌入式系统软件架构,并提供相应的C代码示例。
关注微信公众号,提前获取相关推文

项目背景与需求分析

首先,我们从图片和描述中了解到这是一个物联网加热台项目,旨在优化启帆科创的现有产品。这意味着我们需要在现有基础上,提升加热台的智能化、可靠性和可扩展性。

核心需求:

  1. 精确温度控制: 这是加热台最核心的功能,需要能够精确设定和维持目标温度。
  2. 物联网连接: 实现设备联网,方便远程监控、控制和数据管理。
  3. 安全可靠: 确保加热过程安全可靠,避免过热、短路等安全隐患。
  4. 高效稳定: 系统运行高效稳定,响应迅速,能够长时间可靠工作。
  5. 可扩展性: 方便后续功能扩展和升级,例如增加新的传感器、控制模式或云平台集成。
  6. 用户友好: 操作界面简洁明了,易于用户使用和配置(即使是嵌入式系统,也需要考虑本地或远程的用户交互)。

优化方向 (基于启帆科创物联网加热台):

  • 更先进的控制算法: 可能启帆科创的产品使用了基础的PID控制,我们可以考虑更高级的自适应PID、模糊控制或模型预测控制等,以提高温度控制的精度和响应速度。
  • 更完善的物联网功能: 增强数据上报、远程控制、OTA升级等功能,并考虑更安全的通信协议和数据加密。
  • 更强大的错误处理和容错机制: 提高系统的鲁棒性,在出现异常情况时能够安全地处理并恢复。
  • 更灵活的配置管理: 提供更灵活的配置方式,方便用户根据不同应用场景调整参数。
  • 模块化和可扩展性设计: 采用更模块化的设计,方便后续功能的添加和维护。

系统架构设计

为了满足以上需求,并构建一个可靠、高效、可扩展的嵌入式系统平台,我推荐采用分层模块化架构。这种架构将系统划分为不同的层次和模块,每个层次和模块负责特定的功能,层与层之间、模块与模块之间通过清晰定义的接口进行通信。

分层架构:

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

    • 目的: 隔离硬件差异,为上层软件提供统一的硬件访问接口。
    • 包含模块: GPIO 驱动、ADC 驱动、定时器驱动、PWM 驱动、串口驱动、I2C/SPI 驱动、看门狗驱动等。
    • 职责: 直接操作硬件寄存器,实现底层硬件的初始化、配置和控制。
    • 优势: 提高代码的可移植性,当更换硬件平台时,只需要修改 HAL 层代码即可。
  2. 板级支持包 (BSP - Board Support Package):

    • 目的: 提供特定硬件平台的初始化和配置,以及一些板级特有的功能。
    • 包含模块: 时钟初始化、中断控制器初始化、内存初始化、启动代码、板载外设驱动(例如板载LED、按键等)。
    • 职责: 在 HAL 层之上,进一步封装硬件细节,为操作系统层或应用层提供更高层次的硬件服务。
    • 优势: 简化系统初始化流程,提供板级特性的支持。
  3. 操作系统层 (OS Layer) 或 实时操作系统 (RTOS Layer):

    • 目的: 提供任务调度、内存管理、进程间通信、同步机制等操作系统级别的服务。
    • 选择: 对于复杂的嵌入式系统,特别是需要高实时性和多任务处理的应用,推荐使用 RTOS,例如 FreeRTOS、RT-Thread、uC/OS 等。对于资源受限或功能简单的系统,也可以选择不使用 RTOS,采用裸机编程,但需要自行实现任务调度和资源管理。
    • 优势 (RTOS): 提高系统实时性、并发性、可维护性,简化多任务编程。
    • 优势 (裸机): 资源占用少,启动速度快,适用于资源受限的场景。
    • 本项目假设采用 RTOS (FreeRTOS) 来构建系统。
  4. 核心服务层 (Core Services Layer):

    • 目的: 提供核心的系统服务和功能模块,供应用层调用。
    • 包含模块:
      • 温度传感器模块: 负责读取温度传感器数据,进行数据处理和校准。
      • 加热控制模块: 实现温度控制算法(例如 PID 控制),控制加热器输出功率。
      • 通信模块: 处理网络通信协议(例如 MQTT、HTTP),实现数据上报和远程控制。
      • 配置管理模块: 负责加载、保存和管理系统配置参数。
      • 日志管理模块: 记录系统运行日志,方便调试和故障排查。
      • 错误处理模块: 处理系统错误和异常,提供错误报告和恢复机制。
      • 安全模块: 实现数据加密、身份认证等安全功能。
      • OTA 升级模块: 支持固件远程升级功能。
    • 职责: 实现系统的核心业务逻辑,为应用层提供高层次的服务接口。
    • 优势: 模块化设计,功能清晰,易于维护和扩展。
  5. 应用层 (Application Layer):

    • 目的: 实现具体的应用功能,例如加热模式管理、用户界面交互、云平台对接等。
    • 包含模块:
      • 加热模式管理模块: 定义和管理不同的加热模式(例如恒温模式、定时模式、曲线模式等)。
      • 用户界面模块 (可选): 如果需要本地用户界面,例如 LCD 屏幕和按键,则需要用户界面模块来处理用户交互。
      • 云平台对接模块: 负责与云平台进行数据交换和控制指令接收。
      • 状态监控模块: 监控系统状态,例如温度、加热器状态、网络状态等,并将状态信息显示给用户或上报到云平台。
    • 职责: 根据具体应用需求,调用核心服务层提供的接口,实现最终的应用功能。
    • 优势: 专注于应用逻辑,简化开发,提高开发效率。

模块化设计:

在每一层内部,我们都采用模块化设计,将功能进一步细分到更小的模块中。例如,在核心服务层的通信模块中,可以进一步划分为 MQTT 客户端模块、HTTP 客户端模块、网络接口管理模块等。

架构图示 (简化版):

1
2
3
4
5
6
7
8
9
10
11
12
13
+-----------------------+
| 应用层 (Application Layer) | 例如: 加热模式管理, 用户界面, 云平台对接
+-----------------------+
| 核心服务层 (Core Services Layer) | 例如: 温度传感器, 加热控制, 通信, 配置, 日志
+-----------------------+
| 操作系统层 (RTOS Layer) | 例如: FreeRTOS, 任务调度, 内存管理, 同步
+-----------------------+
| 板级支持包 (BSP - Board Support Package) | 例如: 时钟, 中断, 内存, 板载外设驱动
+-----------------------+
| 硬件抽象层 (HAL - Hardware Abstraction Layer) | 例如: GPIO, ADC, Timer, PWM, UART, I2C/SPI
+-----------------------+
| 硬件 (Hardware) | 例如: MCU, 温度传感器, 加热器, 网络模块
+-----------------------+

技术选型和方法:

  • 微控制器 (MCU): 根据性能需求和成本预算选择合适的 MCU,例如 STM32 系列、ESP32 系列、NXP i.MX 系列等。
  • 温度传感器: 高精度、高可靠性的温度传感器,例如 PT100/PT1000 热电阻、热电偶、数字温度传感器 (如 DS18B20)。
  • 加热器: 根据功率需求选择合适的加热器,例如电阻丝加热器、陶瓷加热器、PTC 加热器。
  • 加热器驱动: 固态继电器 (SSR) 或 MOSFET 用于控制加热器的开关和功率。PWM 调制用于精确功率控制。
  • 通信模块: Wi-Fi 模块 (ESP32 等集成 Wi-Fi 的 MCU)、以太网模块,根据网络连接方式选择。
  • 操作系统: FreeRTOS (或其他 RTOS) 用于任务调度和资源管理。
  • 编程语言: C 语言 (嵌入式系统开发的主流语言)。
  • 通信协议: MQTT (轻量级物联网消息协议)、HTTP (用于云平台 REST API 交互)。
  • 控制算法: PID 控制算法 (比例-积分-微分控制) 或更高级的控制算法。
  • 数据存储: Flash 存储 (用于配置参数、日志数据等)。
  • 开发工具: 集成开发环境 (IDE) 例如 Keil MDK、IAR Embedded Workbench、Eclipse + GCC 等,调试器 (J-Link, ST-Link 等)。
  • 版本控制: Git (进行代码版本管理和团队协作)。
  • 测试方法: 单元测试、集成测试、系统测试、性能测试、可靠性测试、安全性测试。

C 代码实现 :

为了展示整个架构和主要功能,我将提供一些关键模块的 C 代码示例。由于代码量较大,我将分模块展示,并尽量保证代码的完整性和可读性。

1. HAL 层 (Hardware Abstraction Layer):

(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
29
30
31
32
33
#ifndef HAL_GPIO_H
#define HAL_GPIO_H

typedef enum {
GPIO_PIN_RESET = 0,
GPIO_PIN_SET = 1
} GPIO_PinState;

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_ANALOG,
GPIO_MODE_AF_PP, // Alternate Function Push-Pull
GPIO_MODE_AF_OD // Alternate Function Open-Drain
} GPIO_ModeTypeDef;

typedef enum {
GPIO_PULLUP,
GPIO_PULLDOWN,
GPIO_NOPULL
} GPIO_PullTypeDef;

typedef struct {
uint32_t Pin; // GPIO Pin number
GPIO_ModeTypeDef Mode; // GPIO Mode
GPIO_PullTypeDef Pull; // Pull-up/Pull-down configuration
} GPIO_InitTypeDef;

void HAL_GPIO_Init(GPIO_InitTypeDef *GPIO_InitStruct);
void HAL_GPIO_WritePin(uint32_t Pin, GPIO_PinState PinState);
GPIO_PinState HAL_GPIO_ReadPin(uint32_t Pin);

#endif // HAL_GPIO_H

(hal_gpio.c) (假设针对 STM32 平台,需要根据实际硬件修改)

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
#include "hal_gpio.h"
#include "stm32fxxx_hal.h" // 假设使用 STM32 HAL 库,需要替换为实际的 MCU HAL 库

void HAL_GPIO_Init(GPIO_InitTypeDef *GPIO_InitStruct) {
GPIO_InitTypeDef GPIO_HAL_InitStruct = {0};

GPIO_HAL_InitStruct.Pin = GPIO_InitStruct->Pin;

switch (GPIO_InitStruct->Mode) {
case GPIO_MODE_INPUT:
GPIO_HAL_InitStruct.Mode = GPIO_MODE_INPUT;
break;
case GPIO_MODE_OUTPUT:
GPIO_HAL_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
break;
case GPIO_MODE_ANALOG:
GPIO_HAL_InitStruct.Mode = GPIO_MODE_ANALOG;
break;
case GPIO_MODE_AF_PP:
GPIO_HAL_InitStruct.Mode = GPIO_MODE_AF_PP;
break;
case GPIO_MODE_AF_OD:
GPIO_HAL_InitStruct.Mode = GPIO_MODE_AF_OD;
break;
default:
GPIO_HAL_InitStruct.Mode = GPIO_MODE_INPUT; // 默认输入模式
break;
}

switch (GPIO_InitStruct->Pull) {
case GPIO_PULLUP:
GPIO_HAL_InitStruct.Pull = GPIO_PULLUP;
break;
case GPIO_PULLDOWN:
GPIO_HAL_InitStruct.Pull = GPIO_PULLDOWN;
break;
case GPIO_NOPULL:
GPIO_HAL_InitStruct.Pull = GPIO_NOPULL;
break;
default:
GPIO_HAL_InitStruct.Pull = GPIO_NOPULL; // 默认无上下拉
break;
}

GPIO_HAL_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // 低速即可

HAL_GPIO_Init(GPIOA, &GPIO_HAL_InitStruct); // 假设 GPIOA 需要根据实际端口修改 (或者根据 GPIO_InitStruct->Pin 推断端口)
// 需要根据 GPIO_InitStruct->Pin 来确定具体的 GPIO 端口 (GPIOA, GPIOB, GPIOC 等)
// 这里为了简化示例,假设都使用 GPIOA,实际需要更完善的端口映射逻辑
}

void HAL_GPIO_WritePin(uint32_t Pin, GPIO_PinState PinState) {
HAL_GPIO_WritePin(GPIOA, Pin, (GPIO_PinState)PinState); // 假设 GPIOA,需要根据实际端口修改
}

GPIO_PinState HAL_GPIO_ReadPin(uint32_t Pin) {
return (GPIO_PinState)HAL_GPIO_ReadPin(GPIOA, Pin); // 假设 GPIOA,需要根据实际端口修改
}

(hal_adc.h)

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef HAL_ADC_H
#define HAL_ADC_H

typedef struct {
uint32_t Channel; // ADC Channel
uint32_t SamplingTime; // ADC Sampling Time
} ADC_ChannelConfTypeDef;

void HAL_ADC_Init();
void HAL_ADC_ConfigChannel(ADC_ChannelConfTypeDef *ChannelConfig);
uint32_t HAL_ADC_GetValue();

#endif // HAL_ADC_H

(hal_adc.c) (假设针对 STM32 平台)

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
#include "hal_adc.h"
#include "stm32fxxx_hal.h" // 假设使用 STM32 HAL 库, 需要替换为实际的 MCU HAL 库

ADC_HandleTypeDef hadc1; // ADC 句柄,假设使用 ADC1

void HAL_ADC_Init() {
__HAL_RCC_ADC1_CLK_ENABLE(); // 使能 ADC1 时钟

hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; // 时钟分频
hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 12 位分辨率
hadc1.Init.ScanConvMode = DISABLE; // 单通道模式
hadc1.Init.ContinuousConvMode = DISABLE; // 非连续转换模式
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; // 软件触发
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

HAL_ADC_Init(&hadc1);
}

void HAL_ADC_ConfigChannel(ADC_ChannelConfTypeDef *ChannelConfig) {
ADC_ChannelConfTypeDef sConfig = {0};

sConfig.Channel = ChannelConfig->Channel;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ChannelConfig->SamplingTime;

HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

uint32_t HAL_ADC_GetValue() {
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
return HAL_ADC_GetValue(&hadc1);
}

(其他 HAL 驱动类似,例如 hal_timer.h, hal_timer.c, hal_pwm.h, hal_pwm.c, hal_uart.h, hal_uart.c 等,这里省略,只需要定义接口和简单的实现)

2. BSP 层 (Board Support Package):

(bsp.h)

1
2
3
4
5
6
7
8
9
10
#ifndef BSP_H
#define BSP_H

void BSP_Init();
void BSP_LED_Init();
void BSP_LED_Toggle();
uint32_t BSP_GetTemperatureSensorValue(); // 获取温度传感器原始 ADC 值
float BSP_ConvertAdcToTemperature(uint32_t adcValue); // ADC 值转换为温度值

#endif // BSP_H

(bsp.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
#include "bsp.h"
#include "hal_gpio.h"
#include "hal_adc.h"
#include "hal_timer.h" // 假设使用定时器用于一些板级功能
#include "stdio.h" // 用于 printf 调试

// 定义 LED 引脚 (假设连接到 GPIOA Pin 5)
#define LED_PIN (1 << 5)

// 定义温度传感器 ADC 通道 (假设连接到 ADC1 Channel 1)
#define TEMP_SENSOR_ADC_CHANNEL ADC_CHANNEL_1

void BSP_Init() {
// 初始化 HAL 层
HAL_ADC_Init();
HAL_TIMER_Init(); // 初始化定时器
BSP_LED_Init();

printf("BSP Initialized!\r\n"); // 打印初始化信息
}

void BSP_LED_Init() {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(&GPIO_InitStruct);
}

void BSP_LED_Toggle() {
static GPIO_PinState ledState = GPIO_PIN_RESET;
ledState = (ledState == GPIO_PIN_RESET) ? GPIO_PIN_SET : GPIO_PIN_RESET;
HAL_GPIO_WritePin(LED_PIN, ledState);
}

uint32_t BSP_GetTemperatureSensorValue() {
ADC_ChannelConfTypeDef channelConfig = {0};
channelConfig.Channel = TEMP_SENSOR_ADC_CHANNEL;
channelConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 采样时间

HAL_ADC_ConfigChannel(&channelConfig);
return HAL_ADC_GetValue();
}

float BSP_ConvertAdcToTemperature(uint32_t adcValue) {
// 这里需要根据实际的温度传感器类型和电路参数进行 ADC 值到温度值的转换
// 例如,如果是 PT100 热电阻,需要查表或者使用线性化公式
// 这里为了简化示例,假设是线性关系,需要根据实际传感器特性进行校准和调整

float voltage = (float)adcValue / 4095.0f * 3.3f; // 假设 ADC 参考电压 3.3V, 12 位 ADC
float temperature = voltage * 50.0f; // 示例线性转换关系,需要根据实际传感器特性调整

return temperature;
}

3. 操作系统层 (RTOS Layer) - 使用 FreeRTOS:

(freertos_abstraction.h) (简单的 RTOS 抽象层,如果直接使用 FreeRTOS API,可以省略)

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
#ifndef FREERTOS_ABSTRACTION_H
#define FREERTOS_ABSTRACTION_H

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

typedef void (*TaskFunction_t)(void *pvParameters);

// 任务创建
TaskHandle_t RTOS_TaskCreate(TaskFunction_t pvTaskCode, const char *pcName, uint16_t usStackDepth, void *pvParameters, UBaseType_t uxPriority);

// 延时
void RTOS_Delay(TickType_t xTicksToDelay);

// 队列创建
QueueHandle_t RTOS_QueueCreate(UBaseType_t uxQueueLength, size_t uxItemSize);
BaseType_t RTOS_QueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
BaseType_t RTOS_QueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);

// 信号量创建
SemaphoreHandle_t RTOS_SemaphoreCreateBinary();
BaseType_t RTOS_SemaphoreGive(SemaphoreHandle_t xSemaphore);
BaseType_t RTOS_SemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);

#endif // FREERTOS_ABSTRACTION_H

(freertos_abstraction.c) (简单的 FreeRTOS 封装)

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
#include "freertos_abstraction.h"

TaskHandle_t RTOS_TaskCreate(TaskFunction_t pvTaskCode, const char *pcName, uint16_t usStackDepth, void *pvParameters, UBaseType_t uxPriority) {
TaskHandle_t xHandle;
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, &xHandle);
return xHandle;
}

void RTOS_Delay(TickType_t xTicksToDelay) {
vTaskDelay(xTicksToDelay);
}

QueueHandle_t RTOS_QueueCreate(UBaseType_t uxQueueLength, size_t uxItemSize) {
return xQueueCreate(uxQueueLength, uxItemSize);
}

BaseType_t RTOS_QueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait) {
return xQueueSend(xQueue, pvItemToQueue, xTicksToWait);
}

BaseType_t RTOS_QueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait) {
return xQueueReceive(xQueue, pvBuffer, xTicksToWait);
}

SemaphoreHandle_t RTOS_SemaphoreCreateBinary() {
return xSemaphoreCreateBinary();
}

BaseType_t RTOS_SemaphoreGive(SemaphoreHandle_t xSemaphore) {
return xSemaphoreGive(xSemaphore);
}

BaseType_t RTOS_SemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait) {
return xSemaphoreTake(xSemaphore, xTicksToWait);
}

4. 核心服务层 (Core Services Layer):

(temp_sensor.h)

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

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

#define TEMP_SENSOR_SAMPLE_INTERVAL_MS 1000 // 温度传感器采样间隔 1秒

typedef struct {
float currentTemperature;
bool isSensorValid;
} TemperatureData_t;

bool TempSensor_Init();
TemperatureData_t TempSensor_ReadTemperature();

#endif // TEMP_SENSOR_H

(temp_sensor.c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "temp_sensor.h"
#include "bsp.h"
#include "FreeRTOS.h"
#include "task.h"
#include "stdio.h" // 用于 printf 调试

bool TempSensor_Init() {
// 温度传感器初始化,例如配置传感器引脚,启动传感器等
printf("Temperature Sensor Initialized!\r\n");
return true; // 假设初始化成功
}

TemperatureData_t TempSensor_ReadTemperature() {
TemperatureData_t tempData;
uint32_t adcValue = BSP_GetTemperatureSensorValue();
tempData.currentTemperature = BSP_ConvertAdcToTemperature(adcValue);
tempData.isSensorValid = true; // 假设传感器数据总是有效的,实际需要加入错误检测机制

printf("Temperature: %.2f C\r\n", tempData.currentTemperature); // 打印温度数据

return tempData;
}

(heater_control.h)

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef HEATER_CONTROL_H
#define HEATER_CONTROL_H

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

#define HEATER_PWM_FREQUENCY_HZ 1000 // PWM 频率 1kHz
#define HEATER_PWM_RESOLUTION 100 // PWM 分辨率 100 (0-100% Duty Cycle)

bool HeaterControl_Init();
void HeaterControl_SetPower(uint8_t powerPercent); // 设置加热器功率百分比 (0-100)

#endif // HEATER_CONTROL_H

(heater_control.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
#include "heater_control.h"
#include "hal_pwm.h"
#include "stdio.h" // 用于 printf 调试

#define HEATER_PWM_CHANNEL 1 // 假设加热器控制使用 PWM Channel 1
#define HEATER_CONTROL_PIN (1 << 6) // 假设加热器控制引脚为 GPIOA Pin 6

bool HeaterControl_Init() {
// 加热器控制初始化,例如配置 PWM 输出引脚,初始化 PWM 定时器
PWM_InitTypeDef pwmInitStruct = {0};
pwmInitStruct.Pin = HEATER_CONTROL_PIN;
pwmInitStruct.Frequency = HEATER_PWM_FREQUENCY_HZ;
pwmInitStruct.DutyCycleResolution = HEATER_PWM_RESOLUTION;
HAL_PWM_Init(&pwmInitStruct);

printf("Heater Control Initialized!\r\n");
return true;
}

void HeaterControl_SetPower(uint8_t powerPercent) {
if (powerPercent > 100) {
powerPercent = 100; // 限制功率百分比范围
}
HAL_PWM_SetDutyCycle(HEATER_PWM_CHANNEL, powerPercent);
printf("Heater Power Set to: %d%%\r\n", powerPercent);
}

(config_manager.h)

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

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

#define CONFIG_FILE_PATH "/config.ini" // 配置文件路径 (假设使用文件系统)

typedef struct {
float targetTemperature;
uint8_t controlMode; // 0: PID, 1: ON/OFF, ...
// ... 其他配置参数 ...
} SystemConfig_t;

bool ConfigManager_LoadConfig(SystemConfig_t *config);
bool ConfigManager_SaveConfig(const SystemConfig_t *config);
void ConfigManager_GetDefaultConfig(SystemConfig_t *config);

#endif // CONFIG_MANAGER_H

(config_manager.c) (简化示例,实际配置管理可能更复杂,例如使用 Flash 存储或外部配置文件)

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
#include "config_manager.h"
#include "stdio.h" // 用于 printf 调试

bool ConfigManager_LoadConfig(SystemConfig_t *config) {
// 从配置文件加载配置参数
// 这里为了简化示例,直接返回默认配置
printf("Loading Config from file: %s\r\n", CONFIG_FILE_PATH);
ConfigManager_GetDefaultConfig(config); // 加载默认配置

// 实际实现需要从文件系统读取配置文件,并解析参数
// 可以使用 ini 文件格式,或者 JSON/XML 等格式
// 并进行错误处理,例如文件不存在,参数格式错误等

return true; // 假设加载成功
}

bool ConfigManager_SaveConfig(const SystemConfig_t *config) {
// 保存配置参数到配置文件
printf("Saving Config to file: %s\r\n", CONFIG_FILE_PATH);

// 实际实现需要将配置参数写入到配置文件
// 可以使用与 LoadConfig 相同的文件格式和处理方式

return true; // 假设保存成功
}

void ConfigManager_GetDefaultConfig(SystemConfig_t *config) {
config->targetTemperature = 50.0f; // 默认目标温度 50 度
config->controlMode = 0; // 默认 PID 控制模式
// ... 设置其他默认配置 ...
printf("Loading Default Config.\r\n");
}

(pid_controller.h) (PID 控制器模块,可选,如果采用 PID 控制)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef PID_CONTROLLER_H
#define PID_CONTROLLER_H

typedef struct {
float kp; // 比例系数
float ki; // 积分系数
float kd; // 微分系数
float setpoint; // 目标值 (设定温度)
float integral; // 积分项累积值
float prevError; // 上一次误差
} PIDController_t;

void PIDController_Init(PIDController_t *pid, float kp, float ki, float kd, float setpoint);
float PIDController_Update(PIDController_t *pid, float processValue); // processValue: 当前温度

#endif // PID_CONTROLLER_H

(pid_controller.c) (PID 控制器实现)

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
#include "pid_controller.h"

void PIDController_Init(PIDController_t *pid, float kp, float ki, float kd, float setpoint) {
pid->kp = kp;
pid->ki = ki;
pid->kd = kd;
pid->setpoint = setpoint;
pid->integral = 0.0f;
pid->prevError = 0.0f;
}

float PIDController_Update(PIDController_t *pid, float processValue) {
float error = pid->setpoint - processValue;
pid->integral += error;
float derivative = error - pid->prevError;
float output = pid->kp * error + pid->ki * pid->integral + pid->kd * derivative;
pid->prevError = error;

// 输出值限制,例如 PWM Duty Cycle 范围 0-100%
if (output < 0.0f) {
output = 0.0f;
} else if (output > 100.0f) {
output = 100.0f;
}

return output;
}

(error_handler.h) (错误处理模块,可选,用于集中处理系统错误)

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

typedef enum {
ERROR_NONE = 0,
ERROR_TEMP_SENSOR_FAILURE,
ERROR_HEATER_FAILURE,
ERROR_NETWORK_FAILURE,
ERROR_CONFIG_LOAD_FAILURE,
// ... 其他错误类型 ...
} ErrorCode_t;

void ErrorHandler_Init();
void ErrorHandler_HandleError(ErrorCode_t errorCode);
void ErrorHandler_ClearError(ErrorCode_t errorCode);
bool ErrorHandler_IsErrorActive(ErrorCode_t errorCode);

#endif // ERROR_HANDLER_H

(error_handler.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
#include "error_handler.h"
#include "stdio.h" // 用于 printf 错误信息

static ErrorCode_t activeErrors = ERROR_NONE; // 存储当前激活的错误标志

void ErrorHandler_Init() {
activeErrors = ERROR_NONE;
printf("Error Handler Initialized!\r\n");
}

void ErrorHandler_HandleError(ErrorCode_t errorCode) {
if (!(activeErrors & errorCode)) { // 避免重复处理相同错误
activeErrors |= errorCode;
printf("Error Detected: %d\r\n", errorCode);
// 根据错误类型进行相应的处理,例如:
// - 停止加热
// - 报警 (例如 LED 闪烁,蜂鸣器)
// - 上报云平台
}
}

void ErrorHandler_ClearError(ErrorCode_t errorCode) {
activeErrors &= ~errorCode;
printf("Error Cleared: %d\r\n", errorCode);
}

bool ErrorHandler_IsErrorActive(ErrorCode_t errorCode) {
return (activeErrors & errorCode) != ERROR_NONE;
}

(network_module.h) (网络通信模块,简化示例,实际网络模块会更复杂,例如 MQTT 客户端库的集成)

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef NETWORK_MODULE_H
#define NETWORK_MODULE_H

#include <stdbool.h>

bool NetworkModule_Init();
bool NetworkModule_ConnectToBroker(const char *brokerAddress, uint16_t brokerPort);
bool NetworkModule_PublishMessage(const char *topic, const char *message);
bool NetworkModule_SubscribeTopic(const char *topic);
void NetworkModule_Process(); // 网络模块轮询处理函数

#endif // NETWORK_MODULE_H

(network_module.c) (网络通信模块,简化示例,仅为演示架构,实际需要集成 MQTT 客户端库等)

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
#include "network_module.h"
#include "stdio.h" // 用于 printf 调试

bool NetworkModule_Init() {
// 网络模块初始化,例如 Wi-Fi 初始化,网络协议栈初始化
printf("Network Module Initialized!\r\n");
return true;
}

bool NetworkModule_ConnectToBroker(const char *brokerAddress, uint16_t brokerPort) {
// 连接 MQTT Broker
printf("Connecting to MQTT Broker: %s:%d\r\n", brokerAddress, brokerPort);
// 实际实现需要使用 MQTT 客户端库进行连接操作
return true; // 假设连接成功
}

bool NetworkModule_PublishMessage(const char *topic, const char *message) {
// 发布 MQTT 消息
printf("Publishing MQTT Message: Topic=%s, Message=%s\r\n", topic, message);
// 实际实现需要使用 MQTT 客户端库进行消息发布操作
return true; // 假设发布成功
}

bool NetworkModule_SubscribeTopic(const char *topic) {
// 订阅 MQTT Topic
printf("Subscribing to MQTT Topic: %s\r\n", topic);
// 实际实现需要使用 MQTT 客户端库进行 Topic 订阅操作
return true; // 假设订阅成功
}

void NetworkModule_Process() {
// 网络模块轮询处理,例如接收和处理 MQTT 消息,维持网络连接等
// 实际实现需要根据使用的网络协议栈和 MQTT 客户端库进行处理
// 例如检查网络连接状态,处理接收到的 MQTT 消息等
}

5. 应用层 (Application Layer):

(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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <stdio.h>
#include "bsp.h"
#include "temp_sensor.h"
#include "heater_control.h"
#include "config_manager.h"
#include "pid_controller.h"
#include "error_handler.h"
#include "network_module.h"
#include "freertos_abstraction.h"

#define TASK_PRIORITY_NORMAL (tskIDLE_PRIORITY + 1)
#define TASK_PRIORITY_HIGH (tskIDLE_PRIORITY + 2)

#define TARGET_TEMPERATURE_TOPIC "heating_platform/target_temperature"
#define CURRENT_TEMPERATURE_TOPIC "heating_platform/current_temperature"
#define HEATER_POWER_TOPIC "heating_platform/heater_power"

// 全局配置参数
SystemConfig_t systemConfig;
PIDController_t pidController;

// 任务函数声明
void TemperatureMonitorTask(void *pvParameters);
void HeaterControlTask(void *pvParameters);
void NetworkTask(void *pvParameters);
void UserInterfaceTask(void *pvParameters); // 可选,如果需要本地用户界面

int main() {
// 系统初始化
BSP_Init();
ErrorHandler_Init();

// 加载系统配置
ConfigManager_LoadConfig(&systemConfig);

// 初始化温度传感器和加热器控制
if (!TempSensor_Init()) {
ErrorHandler_HandleError(ERROR_TEMP_SENSOR_FAILURE);
}
if (!HeaterControl_Init()) {
ErrorHandler_HandleError(ERROR_HEATER_FAILURE);
}

// 初始化 PID 控制器
PIDController_Init(&pidController, 1.0f, 0.1f, 0.01f, systemConfig.targetTemperature); // 示例 PID 参数,需要根据实际系统调优

// 初始化网络模块 (可选,如果需要物联网功能)
if (NetworkModule_Init()) {
if (NetworkModule_ConnectToBroker("your_mqtt_broker_address", 1883)) { // 替换为实际 Broker 地址和端口
NetworkModule_SubscribeTopic(TARGET_TEMPERATURE_TOPIC); // 订阅目标温度 Topic
} else {
ErrorHandler_HandleError(ERROR_NETWORK_FAILURE);
}
} else {
ErrorHandler_HandleError(ERROR_NETWORK_FAILURE);
}


// 创建任务
RTOS_TaskCreate(TemperatureMonitorTask, "TempMonTask", 128, NULL, TASK_PRIORITY_NORMAL);
RTOS_TaskCreate(HeaterControlTask, "HeaterCtrlTask", 128, NULL, TASK_PRIORITY_HIGH);
RTOS_TaskCreate(NetworkTask, "NetworkTask", 256, NULL, TASK_PRIORITY_NORMAL);
// RTOS_TaskCreate(UserInterfaceTask, "UITask", 128, NULL, TASK_PRIORITY_NORMAL); // 可选

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

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


// 温度监控任务
void TemperatureMonitorTask(void *pvParameters) {
TickType_t xLastWakeTime = xTaskGetTickCount();

while (1) {
TemperatureData_t tempData = TempSensor_ReadTemperature();
if (tempData.isSensorValid) {
// 更新 PID 控制器 setpoint (如果通过网络接收到新的目标温度)
// ... 从消息队列或全局变量中获取最新的目标温度 ...
pidController.setpoint = systemConfig.targetTemperature; // 使用全局配置中的目标温度

// 发布当前温度到 MQTT Topic (可选)
if (NetworkModule_Init()) { // 检查网络模块是否初始化成功
char tempStr[20];
sprintf(tempStr, "%.2f", tempData.currentTemperature);
NetworkModule_PublishMessage(CURRENT_TEMPERATURE_TOPIC, tempStr);
}
} else {
ErrorHandler_HandleError(ERROR_TEMP_SENSOR_FAILURE);
}

RTOS_DelayUntil(&xLastWakeTime, pdMS_TO_TICKS(TEMP_SENSOR_SAMPLE_INTERVAL_MS)); // 定期运行
}
}

// 加热器控制任务
void HeaterControlTask(void *pvParameters) {
TickType_t xLastWakeTime = xTaskGetTickCount();

while (1) {
TemperatureData_t tempData = TempSensor_ReadTemperature(); // 再次读取温度,确保数据最新
if (tempData.isSensorValid) {
float powerPercent = PIDController_Update(&pidController, tempData.currentTemperature);
HeaterControl_SetPower((uint8_t)powerPercent);

// 发布加热器功率到 MQTT Topic (可选)
if (NetworkModule_Init()) { // 检查网络模块是否初始化成功
char powerStr[20];
sprintf(powerStr, "%.2f", powerPercent);
NetworkModule_PublishMessage(HEATER_POWER_TOPIC, powerStr);
}
} else {
ErrorHandler_HandleError(ERROR_HEATER_FAILURE);
}

RTOS_DelayUntil(&xLastWakeTime, pdMS_TO_TICKS(100)); // 加热控制频率更高,例如 100ms
}
}

// 网络任务
void NetworkTask(void *pvParameters) {
TickType_t xLastWakeTime = xTaskGetTickCount();

while (1) {
NetworkModule_Process(); // 处理网络事件

// 检查是否有新的 MQTT 消息到达,例如目标温度设定
// ... 从 MQTT 客户端库接收消息,并解析 Topic 和 Payload ...
// 示例:假设收到 TARGET_TEMPERATURE_TOPIC 的消息,解析 Payload 为新的目标温度
// char *topic = ...;
// char *payload = ...;
// if (strcmp(topic, TARGET_TEMPERATURE_TOPIC) == 0) {
// systemConfig.targetTemperature = atof(payload); // 更新全局配置中的目标温度
// PIDController_Init(&pidController, 1.0f, 0.1f, 0.01f, systemConfig.targetTemperature); // 重新初始化 PID 控制器
// ConfigManager_SaveConfig(&systemConfig); // 保存配置
// }

RTOS_DelayUntil(&xLastWakeTime, pdMS_TO_TICKS(500)); // 网络任务轮询频率,例如 500ms
}
}

// 用户界面任务 (可选,如果需要本地用户界面)
void UserInterfaceTask(void *pvParameters) {
TickType_t xLastWakeTime = xTaskGetTickCount();

while (1) {
// 更新 LCD 显示
// 处理按键输入
BSP_LED_Toggle(); // 示例:每秒闪烁 LED

RTOS_DelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000)); // UI 刷新频率,例如 1秒
}
}

6. HAL PWM 驱动 (hal_pwm.h, hal_pwm.c) (代码省略, 类似 HAL GPIO, HAL ADC,需要根据 MCU 的 PWM 模块进行实现,提供 PWM 初始化,设置 Duty Cycle 等接口)
7. HAL Timer 驱动 (hal_timer.h, hal_timer.c) (代码省略,类似 HAL GPIO, HAL ADC,用于 PWM 的定时器基准时钟)
8. HAL UART 驱动 (hal_uart.h, hal_uart.c) (代码省略,用于调试串口输出)

测试验证和维护升级:

  • 单元测试: 针对每个模块进行单元测试,例如温度传感器模块、加热控制模块、PID 控制器模块等,验证模块功能的正确性。
  • 集成测试: 测试模块之间的集成,例如温度传感器模块和加热控制模块的集成,验证模块协同工作的正确性。
  • 系统测试: 进行完整的系统测试,模拟实际使用场景,验证系统的整体功能、性能、可靠性和安全性。
  • 性能测试: 测试温度控制精度、响应速度、加热效率等性能指标。
  • 可靠性测试: 进行长时间运行测试、压力测试、环境测试等,验证系统的可靠性和稳定性。
  • 安全性测试: 进行安全性漏洞扫描、渗透测试等,验证系统的安全性。
  • OTA 升级: 实现 Over-The-Air 固件升级功能,方便远程维护和升级。
  • 日志记录: 完善日志记录功能,方便故障排查和系统监控。
  • 远程监控和诊断: 通过物联网平台实现设备的远程监控和诊断功能。

总结:

以上架构设计和 C 代码示例,旨在展示一个基于分层模块化架构的物联网加热台嵌入式系统开发框架。 这个架构具有良好的可靠性、高效性和可扩展性,并充分考虑了物联网应用的需求。

关键特点:

  • 分层模块化: 代码结构清晰,易于维护和扩展。
  • HAL 硬件抽象层: 提高代码可移植性。
  • RTOS 实时操作系统: 提高系统实时性和并发性。
  • PID 控制算法: 实现精确的温度控制。
  • 物联网连接: 方便远程监控和控制。
  • 完善的错误处理: 提高系统鲁棒性。
  • 可扩展性设计: 方便后续功能扩展和升级。

优化方向 (基于启帆科创产品):

  • 更高级的控制算法: 可以尝试模糊 PID 控制、模型预测控制等更先进的控制算法,进一步提高温度控制精度和响应速度。
  • 更智能的加热模式: 可以增加智能加热模式,例如根据时间、环境温度、材料特性等自动调整加热参数。
  • 更强大的云平台集成: 可以与更强大的云平台对接,提供更丰富的数据分析、远程管理和用户服务功能。
  • 更完善的安全机制: 加强数据加密、身份认证、访问控制等安全机制,保障设备和数据安全。
  • 更低功耗设计: 如果应用场景对功耗敏感,需要进行低功耗优化设计。

希望以上详细的解答和代码示例能够帮助您理解和构建这个嵌入式物联网加热台项目。 实际开发过程中,还需要根据具体硬件平台、功能需求和资源限制进行调整和完善。

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