应用——智能配电箱监控系统

智能配电箱监控系统开发笔记

一、项目概述

这是一个基于多线程邮箱通信机制的智能配电箱监控系统,实现了以下功能:

  1. 多线程通信:使用自定义邮箱系统进行线程间通信

  2. 数据库存储:使用SQLite实时存储传感器数据

  3. 报警功能:实时监测电压、电流、温度等参数,触发报警

  4. 图形显示:使用FrameBuffer在屏幕上显示监控界面

二、核心技术原理

2.1 线程邮箱通信机制

// 核心数据结构 typedef struct { char name_of_sender[32]; // 发送者名称 char data[256]; // 数据内容 } MAIL_DATA; typedef struct { // 邮箱系统相关数据结构 } MBS; // 核心API函数 MBS* create_mail_box_system(); // 创建邮箱系统 void register_to_mail_system(MBS* mbs, const char* name, void* (*func)(void*)); // 注册线程 int send_msg(MBS* mbs, const char* to_name, MAIL_DATA* data); // 发送消息 int recv_msg(MBS* mbs, MAIL_DATA* data); // 接收消息 void wait_all_end(MBS* mbs); // 等待所有线程结束 void destroy_mail_box_system(MBS* mbs); // 销毁邮箱系统

2.2 工作流程

数据线程(data_th) → 生成传感器数据 ↓ (通过邮箱发送) 显示线程(show_th) → 在屏幕上显示数据 ↓ (通过邮箱发送) 数据库 → 保存历史数据 ↓ (检查阈值) 报警系统 → 触发报警记录

三、系统架构设计

3.1 线程设计

1. 显示线程 (show_th)

功能:接收传感器数据并显示在屏幕上
特点

  • 使用FrameBuffer直接写屏

  • 支持中文字符显示

  • 实时更新监控界面

2. 数据线程 (data_th)

功能:生成模拟传感器数据
特点

  • 模拟真实电压、电流、温度波动

  • 支持随机时间间隔

  • 自动触发报警检测

3.2 数据库设计

数据表结构
-- 传感器数据表 CREATE TABLE sensor_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, time DATETIME DEFAULT CURRENT_TIMESTAMP, voltage REAL, -- 电压值 (单位: V) current REAL, -- 电流值 (单位: A) temperature REAL -- 温度值 (单位: °C) ); -- 报警记录表 CREATE TABLE alarm_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, time DATETIME DEFAULT CURRENT_TIMESTAMP, alarm_type TEXT, -- 报警类型: '过压'/'欠压'/'过流'/'高温' value REAL, -- 实际测量值 threshold REAL -- 报警阈值 );

四、最终代码实现

#include "framebuffer.h" #include "head.h" #include "linkque.h" #include "list.h" #include "mailbox.h" #include "utf.h" #include <fcntl.h> #include <pthread.h> #include <signal.h> // 信号头文件 #include <sqlite3.h> // 数据库头文件 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> // ========== 全局变量 ========== MBS *g_mbs; // 邮箱系统句柄 int g_running = 1; // 程序运行标志 sqlite3 *g_db = NULL; // 数据库句柄 // ========== 信号处理 ========== void signal_handler(int sig) { printf("\n收到停止信号,正在退出...\n"); g_running = 0; } // ========== 数据库初始化 ========== void init_database() { int rc = sqlite3_open("sensor.db", &g_db); if (rc != SQLITE_OK) { printf("数据库打开失败\n"); return; } // 创建两个表:传感器数据表和报警记录表 char *sql = // 第一个表:传感器数据表 "CREATE TABLE IF NOT EXISTS sensor_data (" "id INTEGER PRIMARY KEY AUTOINCREMENT," // 第1列:自动编号(1,2,3...) "time DATETIME DEFAULT CURRENT_TIMESTAMP," // 第2列:自动记录时间 "voltage REAL," // 第3列:电压值(小数) "current REAL," // 第4列:电流值(小数) "temperature REAL" // 第5列:温度值(小数) ");" // 第二个表:报警记录表 "CREATE TABLE IF NOT EXISTS alarm_log (" "id INTEGER PRIMARY KEY AUTOINCREMENT," // 第1列:自动编号 "time DATETIME DEFAULT CURRENT_TIMESTAMP," // 第2列:报警时间 "alarm_type TEXT," // 第3列:报警类型(文字,如"高温") "value REAL," // 第4列:实际测量值(如实际温度45) "threshold REAL" // 第5列:报警阈值(如温度阈值40) ");"; char *err_msg = 0; rc = sqlite3_exec(g_db, sql, 0, 0, &err_msg); if (rc != SQLITE_OK) { printf("创建表失败: %s\n", err_msg); sqlite3_free(err_msg); } } // ========== 保存传感器数据到数据库 ========== void save_to_database(float voltage, float current, float temp) { char sql[256]; snprintf(sql, sizeof(sql), "INSERT INTO sensor_data (voltage, current, temperature) " "VALUES (%.2f, %.2f, %.2f);", voltage, current, temp); // 执行插入命令 sqlite3_exec(g_db, sql, 0, 0, NULL); } // ========== 保存报警记录到数据库 ========== void save_alarm_to_database(const char *alarm_type, float value, float threshold) { char sql[256]; snprintf(sql, sizeof(sql), "INSERT INTO alarm_log (alarm_type, value, threshold) " "VALUES ('%s', %.2f, %.2f);", alarm_type, value, threshold); sqlite3_exec(g_db, sql, 0, 0, NULL); } // ========== 显示线程函数 ========== void *show_th(void *arg) { MAIL_DATA data; // 创建一个邮件变量 // 初始化UTF-8字库 UTF8_INFO utf8_info; bzero(&utf8_info, sizeof(UTF8_INFO)); strcpy(utf8_info.path, ZIKUK_FILE_BIG); utf8_info.width = 32; utf8_info.height = 32; init_utf8(&utf8_info); // 初始化FrameBuffer int fb_fd = init_fb("/dev/fb0"); if (fb_fd == -1) { printf("FrameBuffer初始化失败\n"); uninit_utf8(&utf8_info); // 清理字库 return NULL; } while (g_running) { bzero(&data, sizeof(MAIL_DATA)); // 清空邮件内容 // 接收邮件,ret=0表示有邮件,ret=1表示没邮件 int ret = recv_msg(g_mbs, &data); if (1 == ret) { usleep(100000); // 100毫秒,不要用sleep(1) continue; } // 显示位置(每次重置) int x_pos = 50; int y_pos = 50; int line_height = 40; // 清屏为黑色 draw_clear(0x000000); // 显示标题 draw_utf8_str(&utf8_info, x_pos, y_pos, "智能配电箱监控系统", 0xFF0000, 0x000000); y_pos += line_height; // 显示传感器数据 draw_utf8_str(&utf8_info, x_pos, y_pos, data.data, 0xFFFFFF, 0x000000); y_pos += line_height; // 显示时间(绿色字) time_t now = time(NULL); struct tm *tm_info = localtime(&now); char time_str[32]; strftime(time_str, sizeof(time_str), "时间: %Y-%m-%d %H:%M:%S", tm_info); draw_utf8_str(&utf8_info, x_pos, y_pos, time_str, 0x00FF00, 0x0000FF); // 绘制背景图片 draw_bmp(0, 0, "./res/1.bmp", 800, 600); } // 清理显示资源 if (fb_fd != -1) { uninit_utf8(&utf8_info); uninit_fb(fb_fd); } printf("显示线程退出\n"); return NULL; } // ========== 数据生成线程函数 ========== void *data_th(void *arg) { // 设置随机种子 srand(time(NULL)); MAIL_DATA data; int data_count = 0; while (g_running) { // 生成传感器数据(模拟真实波动) float voltage = 220.0 + (rand() % 21 - 10); // 210-230V float current = 5.0 + (rand() % 31) * 0.1; // 5-8A float temperature = 25.0 + (rand() % 21); // 25-45°C // 保存到数据库 save_to_database(voltage, current, temperature); // 检查报警条件 int has_alarm = 0; // 电压报警检查 if (voltage > 235.0) { save_alarm_to_database("过压", voltage, 235.0); has_alarm = 1; printf("⚠️ 过压报警: %.1fV > 235.0V\n", voltage); } if (voltage < 200.0) { save_alarm_to_database("欠压", voltage, 200.0); has_alarm = 1; printf("⚠️ 欠压报警: %.1fV < 200.0V\n", voltage); } // 电流报警检查 if (current > 10.0) { save_alarm_to_database("过流", current, 10.0); has_alarm = 1; printf("⚠️ 过流报警: %.1fA > 10.0A\n", current); } // 温度报警检查 if (temperature > 60.0) { save_alarm_to_database("高温", temperature, 60.0); has_alarm = 1; printf("⚠️ 高温报警: %.1f°C > 60.0°C\n", temperature); } // 发送给显示线程 bzero(&data, sizeof(data)); // 清空邮件内容 sprintf(data.data, "电压:%.1fV 电流:%.1fA 温度:%.1f°C", voltage, current, temperature); // 设置发送者名称 strcpy(data.name_of_sender, "data"); // 发送给show线程 send_msg(g_mbs, "show", &data); // 随机等待0-2秒 sleep(rand() % 3); data_count++; if (data_count % 10 == 0) { printf("✅ 已生成 %d 条传感器数据\n", data_count); } } printf("数据线程退出\n"); return NULL; } // ========== 主函数 ========== int main(int argc, char **argv) { printf("=======================================\n"); printf(" 智能配电箱监控系统 v1.0\n"); printf("=======================================\n"); // 设置信号处理 signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); // 初始化数据库 printf("初始化数据库...\n"); init_database(); // 创建邮箱系统 printf("创建邮箱系统...\n"); g_mbs = create_mail_box_system(); if (!g_mbs) { printf("创建邮箱系统失败!\n"); return -1; } // 注册线程到邮箱系统 printf("注册显示线程...\n"); register_to_mail_system(g_mbs, "show", show_th); printf("注册数据线程...\n"); register_to_mail_system(g_mbs, "data", data_th); printf("\n系统启动完成!\n"); printf("运行中...按 Ctrl+C 停止\n"); printf("=======================================\n\n"); // 等待所有线程结束 wait_all_end(g_mbs); // 清理资源 printf("\n清理资源...\n"); if (g_db) { sqlite3_close(g_db); printf("数据库已关闭\n"); } destroy_mail_box_system(g_mbs); printf("邮箱系统已销毁\n"); printf("程序安全退出\n"); return 0; }

五、编译和运行说明

5.1 编译命令

# 需要链接的库:pthread, sqlite3 gcc -o smart_powerbox main.c mailbox.c linkque.c list.c framebuffer.c utf.c \ -lpthread -lsqlite3 -lm

5.2 运行说明

# 1. 运行程序 ./smart_powerbox # 2. 查看数据库(另一个终端) sqlite3 sensor.db # 3. 在sqlite3中查看数据 sqlite> SELECT * FROM sensor_data; sqlite> SELECT * FROM alarm_log; sqlite> .exit

六、技术要点总结

6.1 多线程通信优势

  1. 解耦:各线程独立工作,通过邮箱通信

  2. 实时性:数据生成和显示分离,互不影响

  3. 扩展性:方便添加新功能模块

6.2 数据库设计要点

  1. 时间戳:自动记录数据时间

  2. 数据类型:使用REAL存储浮点数

  3. 报警记录:单独建表,便于查询分析

6.3 显示技术要点

  1. FrameBuffer:直接操作显示缓冲区

  2. UTF-8支持:显示中文字符

  3. 定时刷新:实时更新显示内容

6.4 报警逻辑

  1. 阈值设置:根据实际需求设定

  2. 实时检测:每次生成数据时检查

  3. 记录保存:所有报警都有历史记录

七、扩展建议

7.1 功能扩展

  1. 增加配置文件:支持参数配置

  2. 添加日志系统:记录程序运行状态

  3. 支持远程访问:添加Web界面

7.2 性能优化

  1. 数据库优化:使用事务批量插入

  2. 内存管理:合理控制内存使用

  3. 线程调度:优化线程优先级

八、注意事项

  1. 权限问题:FrameBuffer操作需要root权限

  2. 资源清理:确保所有资源正确释放

  3. 错误处理:添加更完善的错误处理机制

  4. 信号安全:确保信号处理函数可重入

这个系统展示了如何将多线程、数据库、图形显示等技术综合应用,构建一个完整的嵌入式监控系统。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1141324.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

医疗实时数据用Redis缓存稳预警

&#x1f4dd; 博客主页&#xff1a;jaxzheng的CSDN主页 医疗实时预警系统的稳定性革命&#xff1a;Redis缓存架构的深度优化与实践目录医疗实时预警系统的稳定性革命&#xff1a;Redis缓存架构的深度优化与实践 引言&#xff1a;实时预警的生死线 一、问题与挑战&#xff1a;医…

C++ vector 容器

C vector 容器概述std::vector 是 C 标准模板库&#xff08;STL&#xff09;中的动态数组容器&#xff0c;支持随机访问、动态扩容和高效的元素操作。其底层通过连续内存空间实现&#xff0c;兼具数组的高效性和动态扩展的灵活性。基本用法初始化#include <vector> std::…

STM32驱动8位并口LCD显示屏操作指南

用STM32“硬刚”8位并口LCD&#xff1a;不靠库&#xff0c;不加芯片&#xff0c;照样点亮屏幕你有没有遇到过这种情况&#xff1f;项目做了一半&#xff0c;老板说&#xff1a;“得加个显示功能。”预算一看——零新增BOM成本。这时候&#xff0c;TFT屏太贵&#xff0c;OLED驱动…

C++ 基本语法

变量与数据类型C 支持多种数据类型&#xff0c;包括整数、浮点数、字符和布尔值。整数类型&#xff1a;int&#xff08;4字节&#xff09;、short&#xff08;2字节&#xff09;、long&#xff08;4或8字节&#xff09;、long long&#xff08;8字节&#xff09;。浮点类型&…

操作指南:hal_uartex_receivetoidle_dma配合中断处理异常数据帧

如何用 STM32 的HAL_UARTEx_ReceiveToIdle_DMA实现稳定高效的串口变长帧接收&#xff1f;你有没有遇到过这样的问题&#xff1a;设备通过串口发来的数据帧长度不固定&#xff0c;比如 Modbus RTU 报文、自定义协议包&#xff0c;甚至是一段不定长的传感器上传流&#xff1f;你试…

高频信号处理篇---包络检波电路

包络检波电路&#xff1a;一部三演员的“描边”戏剧让我用一个生动的比喻&#xff0c;带你理解包络检波电路的三个核心部分&#xff1a;&#x1f31f; 核心比喻&#xff1a;山顶看日出记录员想象你要记录日出时山顶的轮廓&#xff1a;云雾快速飘动 高频载波&#xff08;干扰&a…

图片格式转换右键菜单版 - IMGConverter

图片格式转换右键菜单版 - IMGConverter&#xff0c;化繁为简&#xff0c;摒弃传统的复杂转换格式方式IMGConverter&#xff1a;轻量全能的图片格式转换处理神器 ,轻松转换为bmp,gif,heif,ico,jpeg,jpg,png .webp【图片格式转换处理神器 】链接: https://pan.baidu.com/s/1JCcZ…

Multisim示波器带宽限制功能:项目应用实例

用Multisim示波器的带宽限制功能&#xff0c;提前“看到”真实世界的信号你有没有遇到过这样的情况&#xff1a;在仿真里看到开关电源的MOSFET节点上满屏振荡&#xff0c;吓得赶紧加RC吸收电路、改PCB布局&#xff1b;结果一到实验室&#xff0c;用产线那台20MHz带宽的老款示波…

右键图片直接转换图片格式,告别繁琐的格式转换(IMGConverter)

IMGConverter是一款图片格式转换工具&#xff0c;这类的工具其实很多&#xff0c;但是操作起来却比较繁琐。 通常情况下我们要“打开软件”—“上传图片”—“选择转换格式”—“转换”—“保存”&#xff0c;但是这款工具简化了这些不必要的程序。打开软件后&#xff0c;点“…

论文查重优化的现代方法:六款AI工具实现高效文本改写的操作步骤

排名 工具/方法 核心优势 适用场景 1 aibiye 智能降重学术语言优化 初稿完成后深度润色 2 aicheck 多维度查重选题辅助 全程论文质量监控 3 秒篇 一键生成逻辑结构优化 紧急补论文初稿 4 AskPaper 文献解析重点提炼 文献综述与理论支撑 5 知网人工降重 专…

大数据领域数据科学与人工智能的融合之道

大数据领域数据科学与人工智能的融合之道 一、引入与连接 引人入胜的开场 想象一下&#xff0c;在繁华都市的背后&#xff0c;每一辆出租车的行驶轨迹、每一家商店的销售记录、每一位居民的社交动态&#xff0c;这些看似杂乱无章的数据正汇聚成一股强大的力量。比如&#xff0c…

es安装一文说清:关键参数与目录结构解释

Elasticsearch 安装实战指南&#xff1a;从参数调优到目录规划&#xff0c;一文讲透你有没有经历过这样的场景&#xff1f;凌晨两点&#xff0c;日志系统突然告警&#xff0c;Elasticsearch 节点集体失联。登录服务器一看&#xff0c;discovery.seed_hosts配置错了 IP&#xff…

STM32调试接口配置对JLink下载的影响研究

STM32调试接口配置对JLink下载的影响研究&#xff1a;从“无法连接”到稳定烧录的深度解析你有没有遇到过这样的场景&#xff1f;硬件刚上电&#xff0c;信心满满地打开IDE点击“Download”&#xff0c;结果弹出一串红色报错&#xff1a;“Target not responding”、“Connecti…

LCD显示屏驱动入门必看:手把手教你初始化配置

点亮第一块屏&#xff1a;从零搞懂LCD初始化配置 你有没有过这样的经历&#xff1f;买来一块崭新的TFT-LCD屏幕&#xff0c;接上STM32或ESP32&#xff0c;烧录代码后却发现—— 屏幕全黑、花屏、倒置&#xff0c;甚至毫无反应 &#xff1f; 别急&#xff0c;这几乎每个嵌入式…

通过AI技术提升论文原创性:六大智能工具改写文本的实用技巧解析

排名 工具/方法 核心优势 适用场景 1 aibiye 智能降重学术语言优化 初稿完成后深度润色 2 aicheck 多维度查重选题辅助 全程论文质量监控 3 秒篇 一键生成逻辑结构优化 紧急补论文初稿 4 AskPaper 文献解析重点提炼 文献综述与理论支撑 5 知网人工降重 专…

救命神器10个AI论文软件,研究生高效写作必备!

救命神器10个AI论文软件&#xff0c;研究生高效写作必备&#xff01; 论文写作的“救星”&#xff1a;AI 工具如何改变研究生的学术生活 在如今快节奏的学术环境中&#xff0c;研究生们常常面临论文写作的重重压力。从选题到开题&#xff0c;从初稿到修改&#xff0c;每一个环节…

【C/C++】Optional实现

Optional 实现详解 概述 Optional<T> 是一个可能包含值也可能为空的容器&#xff0c;用于显式表达"值可能不存在"的语义。它解决了传统方案的缺陷&#xff1a;用 -1 表示无效 ID、用 nullptr 表示无效指针、用空字符串表示无值——这些都需要额外约定且容易出错…

大数据架构 _ 如何设计一个支持数据版本控制的系统?

大数据架构 | 如何设计一个支持数据版本控制的系统&#xff1f; 一、引言&#xff1a;你可能经历过的「数据失控」时刻 凌晨三点&#xff0c;分析师小周的钉钉突然炸了——运营同学发现今天的「用户复购率」报表比昨天暴跌30%&#xff0c;要求立刻排查问题。小周连忙打开数据仓…

亲测好用!8款AI论文工具测评:研究生开题报告全攻略

亲测好用&#xff01;8款AI论文工具测评&#xff1a;研究生开题报告全攻略 学术写作新选择&#xff1a;AI工具测评全解析 在当前科研环境日益激烈的背景下&#xff0c;研究生群体面临着论文撰写、开题报告准备等多重挑战。传统的写作方式不仅耗时费力&#xff0c;还容易因格式不…

利用AI技术降低论文重复率:六大工具改写文本的高效技巧与策略

排名 工具/方法 核心优势 适用场景 1 aibiye 智能降重学术语言优化 初稿完成后深度润色 2 aicheck 多维度查重选题辅助 全程论文质量监控 3 秒篇 一键生成逻辑结构优化 紧急补论文初稿 4 AskPaper 文献解析重点提炼 文献综述与理论支撑 5 知网人工降重 专…