STM32毕设项目分享:基于STM32的智能仓库环境监控系统(物联网、FATFS文件操作系统)
一、成品简介
1.实物成品
成品展示:

2.物联网APP
物联网APP界面:

物联网显示界面:

3.SD卡存储
SD卡文本文档打开界面:

二、项目简介
1.功能详解
基于单片机的智能仓库环境监控系统(语音)
-
环境参数采集:使用DHT11温湿度传感器采集仓库内温度和湿度;TVOC-301气体检测模块采集甲醛和CO₂浓度;SR-04超声波测距模块用于模拟货架间距或货物堆放距离测量。
-
本地实时显示:0.96寸OLED屏幕实时显示当前温湿度、气体浓度及距离数值,方便现场巡查。
-
数据本地存储:通过SDIO接口连接Micro SD卡,并移植FATFS文件系统,将环境数据以文本日志形式追加写入
date.txt文件,实现断电不丢失的历史记录存储。 -
远程数据上传:ESP8266 Wi-Fi模块连接无线网络,通过MQTT协议将采集数据上传至OneNet物联网云平台,支持JSON格式数据包定时发送。
-
远程监控与可视化:手机App(基于uni-app框架)通过调用OneNet API接口,实时拉取并显示温度、湿度、甲醛、CO₂等参数,实现远程随时查看仓库环境状态。
-
异常预警与报警:在OneNet平台配置规则引擎,当温湿度或气体浓度超出预设阈值时,自动触发邮件报警,同时本地蜂鸣器发声提醒,实现双重告警。
-
数据可靠性处理:对传感器数据进行校验和检查(如TVOC-301帧校验)及低通滤波(超声波测距),确保采集数据的准确性和稳定性。
硬件框图:

流程图:

2.主要器件
- STM32F103ZeT6单片机
-
DHT11温湿度传感器
-
TVOC-301平面气体传感器模块(可检测甲醛和CO₂)
-
SR-04超声波测距模块
-
ESP8266-01S Wi-Fi模块
-
0.96寸OLED显示屏(I²C接口)
-
Micro SD卡(用于本地数据存储)
-
有源蜂鸣器(用于本地声音报警)
3.原理图设计
该系统供电没有额外设计,将充电宝或者充电线插入单片机输入端即可供电。使用需注意SD卡,上电会先检测SD卡,当SD卡未插入不记录数据。

4.PCB设计

三、主要模块
1.ESP8266物联网模块
ESP8266-01S是一款高度集成的串口转Wi-Fi模块,内置TCP/IP协议栈,通过串口和STM32F103ZET6连接,波特率为115200,通过发送标准AT指令集对模块进行控制
使用中需要注意:模块的串口发送缓冲区有限,单次发送的JSON数据包不可过大,避免发送导致栈或者数组溢出;所有AT指令以“\r\n”结尾,

2.SR-04超声波模块
SR-04是一款利用声波反射原理进行非接触式测距的常用模块,测量范围2cm~300cm,使用时,主控需在Trig引脚产生一个持续10微秒以上的高电平脉冲,模块便会自动发射40kHz的超声波并开始计时;当接收到回波后,Echo引脚会输出一个高电平,其持续时间即为声波往返的时间。根据公式“距离 = 高电平时间 × 声速(340m/s)/ 2”计算出实际距离,单次测量值会出现跳变,因此代码中采用了一阶低通滤波算法对原始距离进行平滑处理。

3.DHT11模块
DHT11是一款数字式温湿度复合传感器,内部集成电容式湿敏元件和热敏电阻,采用单总线(One-Wire)协议与主控通信,能够同时输出温度和湿度数据。该模块对时序精度要求较高,建议使用硬件定时器或精确的微秒级延时函数。

4.TVOC-301平面气体传感器模块
TVOC-301是一款微型空气质量检测模组,可同时检测甲醛(量程0~2000μg/m³)和二氧化碳(量程0~5000ppm)浓度,该模块采用UART串口通信,波特率固定为9600。模块每秒钟输出一帧固定长度为9字节的数据包,帧头固定为0x2C和0xE4,随后依次为TVOC浓度高字节、低字节,甲醛浓度高字节、低字节,CO₂浓度高字节、低字节,以及最后1字节的校验和(计算方法为前面8个字节的累加和取低8位)。STM32通过串口中断逐字节接收,状态机判断当前字节所属字段。

5.Micro SD卡本地存储模块
Micro SD卡作为本地数据存储介质,用于实现环境监测日志的持久化保存,即使在网络中断的情况下也能完整记录历史数据。本系统通过STM32F103ZET6自带的SDIO接口与Micro SD卡进行通信,每次写入操作后必须及时关闭文件,因为FATFS在写入时会将数据暂存在缓存中,若意外断电不关闭文件,不仅当前数据会丢失,还可能导致文件分配表损坏。
6.单片机主控
STM32F103ZET6 是 意法半导体公司所推出的一款基于 ARM Cortex-M3 内核的高性能微控制器,主频具有 72MHz,具备 512KB Flash 和 64KB RAM,支持丰富的通信外设接口,包括多个 UART、I²C、SPI、CAN 以及 SDIO 接口,非常适合本系统中多传感器数据采集、SD 卡存储与 Wi-Fi 通信的需求。

四、写作内容参考
1.摘要参考内容
随着现代物流和仓储行业的快速发展,传统依赖人工巡检的仓库环境监控方式难以满足对温湿度、空气质量等关键参数实时性、准确性和智能化管理的需求。为此,本设计提出一种基于STM32的智能仓库环境监控系统,在实现对仓储环境的全面管理、本地存储与远程预警。
本设计包含两大部分:
第一部分:系统硬件选型设计,以STM32F103ZET6单片机为主控,使用DHT11温湿度传感器、TVOC-301气体检测模块、SR-04超声波测距模块,用于采集环境管理的数据;通过ESP8266 Wi-Fi模块实现与OneNet物联网平台的通信;用 SD卡进行数据本地的存储。
第二部分:系统软件选型设计,完成传感器数据采集、校验与滤波处理;用FATFS文件系统去实现SD卡的日志记录;通过ESP8266模块把数据上传至OneNet平台,通过邮箱实现异常报警的自动邮件告警;通过手机App实现远程数据可视化与实时状态查看。
2.目录参考内容
五、项目主要源码
5.1.单片机源码
5.1.1主程序
#include "bord.h"
void boid_level_init(void)
{
//
}
uint8_t oled_buffer[32];
extern uint64_t Mytotal_size ;
extern uint64_t Myfree_size ;
int8_t wifi_error=0;int8_t mqtt_error=0;
uint32_t co2_value;
uint32_t JiaQuan_value;
uint32_t distance_value;
uint32_t sys_10ms;
uint8_t value_error;
uint8_t distance_error;
//阈值设置
uint16_t dh11_humi_max =90;
uint16_t dh11_temp_min =5;
uint16_t co2_max =1000;
uint16_t disance_max =50;
uint16_t jiaquan_max =100;
void bord_init(void)
{
debug_init();
led_init(&beep_pb1, BEEP_GPIO_Port, BEEP_Pin, 1);
led_off(&beep_pb1);
led_init(&led_pc13, LED_GPIO_Port, LED_Pin, 1);
led_on(&led_pc13);
delay_init();
OLED_Init();
OLED_NewFrame();
OLED_PrintString(0, 0, "系统初始化...", &font16x16, OLED_COLOR_NORMAL);
OLED_PrintString(0, 16, "请等候...", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
HAL_Delay(500);
sdio_fats_init();HAL_Delay(50);
OLED_NewFrame();
sprintf((char *)oled_buffer, "Total: %llu MB", Mytotal_size / (1024 * 1024) );
OLED_PrintString(0, 0,(char *) oled_buffer, &font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffer, "Free: %llu MB", Myfree_size / (1024 * 1024));
OLED_PrintString(0, 16, (char *) oled_buffer, &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
HAL_Delay(1000);
co2_init();
led_off(&led_pc13);
esp8266_rx_init();
OLED_NewFrame();
OLED_PrintString(0, 0, (char *) "OneNetConnect...", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
// if(wifi_init()!=0){wifi_error=1;}
// if(wifi_error==1){OLED_PrintString(0, 16,(char *) "WIFI_Error!", &font16x16, OLED_COLOR_NORMAL);}
// else {OLED_PrintString(0, 16,(char *) "WIFI_OK!", &font16x16, OLED_COLOR_NORMAL);}
wifi_init();
OLED_PrintString(0, 16,(char *) "WIFI_OK!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
mqtt_init();
OLED_PrintString(0, 32,(char *) "MQTT_OK!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
HAL_Delay(500);
OLED_NewFrame();
cs_init();
}
DHT11_Data_TypeDef dh11_temp;
DHT11_Data_TypeDef dh11_date;
int8_t dh11_date_error=0;
int8_t CO2_date_error=0;
int8_t JiaQuan_date_error=0;
extern uint16_t formaldehyde_concentration ; // 甲醛浓度 (ug/m³)
extern uint16_t eco2_concentration ; // 等效eCO2浓度 (PPM)
uint8_t count;
void bord_loop_task(void)
{
// 数据显示
sprintf((char *)oled_buffer,"温度:%d",dh11_date.temp_int);
OLED_PrintString(0, 0, (char *)oled_buffer, &font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffer,"湿度:%d",dh11_date.humi_int);
OLED_PrintString(64, 0, (char *)oled_buffer, &font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffer,"CO2:%d ppm",co2_value);
OLED_PrintString(0, 16, (char *)oled_buffer, &font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffer,"甲醛:%d ug/m",JiaQuan_value);
OLED_PrintString(0, 32, (char *)oled_buffer, &font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffer,"距离:%d cm",distance_value);
OLED_PrintString(0,48, (char *)oled_buffer, &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
// 湿度温度采集
if (DHT11_ReadData(&dh11_temp))
{
// debug_send("Humi%d RH,Temperture%d℃\r\n", dh11_temp.humi_int, dh11_temp.temp_int);
dh11_date = dh11_temp;
sdio_fats_write(dh11_date.temp_int ,dh11_date.humi_int) ;
}
// 距离采集distance
cs_read();
// debug_send("distance%.2f cm\r\n", distance);
if(distance<256)
{
distance_value=low_pass_filter(distance);
}
//CO2采集 甲醛测量
co2_value=eco2_concentration;
JiaQuan_value=formaldehyde_concentration;
// 数据错误处理
if(dh11_date.humi_int>dh11_humi_max||dh11_date.temp_int<dh11_temp_min){dh11_date_error=1;}
else{dh11_date_error=0;}
if(co2_value>co2_max){CO2_date_error=1;} else{CO2_date_error=0;}
if(JiaQuan_value>jiaquan_max){JiaQuan_date_error=1;} else{JiaQuan_date_error=0;}
if(distance_value>disance_max){distance_error=1;} else{distance_error=0;}
// 数据异常
if(dh11_date_error==1||CO2_date_error==1|| JiaQuan_date_error==1|| distance_error==1){value_error=1;}
if(value_error==1)
{
value_error=0;
HAL_Delay(1000);
OLED_NewFrame();
if(dh11_date_error==1)
{OLED_PrintString(0,0, (char *)"温湿度数据错误!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,0, (char *)" ", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,0, (char *)"温湿度数据错误!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,0, (char *)" ", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
HAL_Delay(1000);
}
if(CO2_date_error==1)
{OLED_PrintString(0,16, (char *)"二氧化碳数据错误!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,16, (char *)" ", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,16, (char *)"二氧化碳数据错误!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,16, (char *)" ", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
HAL_Delay(1000);
}
if(JiaQuan_date_error==1)
{OLED_PrintString(0,32, (char *)"甲醛数据错误!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,32, (char *)" ", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,32, (char *)"甲醛数据错误!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,16, (char *)" ", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
HAL_Delay(1000);
}
if(distance_error==1)
{
OLED_PrintString(0,32, (char *)"距离数据错误!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,32, (char *)" ", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,32, (char *)"距离数据错误!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
led_on(&beep_pb1);
HAL_Delay(1000);
led_off(&beep_pb1);
OLED_PrintString(0,16, (char *)" ", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
HAL_Delay(1000);
}
}
HAL_Delay(10);
sys_10ms++;
// WIFI任务
if(sys_10ms>=20)
{sys_10ms=0;
count=(count+1)%4;
switch(count)
{
case 0:esp8266_connect_send("Humi",dh11_date.humi_int, 100) ; break;
case 1:esp8266_connect_send("JiaQuan",JiaQuan_value, 100) ; break;
case 2:esp8266_connect_send("CO2",co2_value, 100) ; break;
case 3:esp8266_connect_send("Temp",dh11_date.temp_int, 100) ; break;
}
}
}
5.1.2 DHT11代码
#include "dt11.h"
static void DHT11_PP_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}
/**
* ************************************************************************
* @brief 将DHT11配置为上拉输入模式
* ************************************************************************
*/
static void DHT11_UP_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉
HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}
/**
* ************************************************************************
* @brief 读取字节
* @return temp
* ************************************************************************
*/
uint8_t DHT11_ReadByte(void)
{
uint8_t i, temp = 0;
for (i = 0; i < 8; i++)
{
while (DHT11_ReadPin == 0); // 等待低电平结束
delay_us(40); // 延时 40 微秒
if (DHT11_ReadPin == 1)
{
while (DHT11_ReadPin == 1); // 等待高电平结束
temp |= (uint8_t)(0X01 << (7 - i)); // 先发送高位
}
else
{
temp &= (uint8_t)~(0X01 << (7 - i));
}
}
return temp;
}
/**
* ************************************************************************
* @brief 读取一次数据
* @param[in] DHT11_Data 定义的结构体变量
* @return 0或1(数据校验是否成功)
* @note 它首先向DHT11发送启动信号,然后等待DHT11的应答。如果DHT11正确应答,
* 则继续读取湿度整数、湿度小数、温度整数、温度小数和校验和数据,
* 并计算校验和以进行数据校验
* ************************************************************************
*/
uint8_t DHT11_ReadData(DHT11_Data_TypeDef *DHT11_Data)
{
DHT11_PP_OUT(); // 主机输出,主机拉低
DHT11_PULL_0;
HAL_Delay(18); // 延时 18 ms
DHT11_PULL_1; // 主机拉高,延时 30 us
delay_us(30);
DHT11_UP_IN(); // 主机输入,获取 DHT11 数据
if (DHT11_ReadPin == 0) // 收到从机应答
{
while (DHT11_ReadPin == 0); // 等待从机应答的低电平结束
while (DHT11_ReadPin == 1); // 等待从机应答的高电平结束
/*开始接收数据*/
DHT11_Data->humi_int = DHT11_ReadByte();
DHT11_Data->humi_dec = DHT11_ReadByte();
DHT11_Data->temp_int = DHT11_ReadByte();
DHT11_Data->temp_dec = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();
DHT11_PP_OUT(); // 读取结束,主机拉高
DHT11_PULL_1;
// 数据校验
if (DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_dec + DHT11_Data->temp_int + DHT11_Data->temp_dec)
{
return 1;
}
else
{
return 0;
}
}
else // 未收到从机应答
{
return 0;
}
}
5.1.3 TVOC-301代码
#include "co2.h"
uint8_t co2_rx; // 存储每次中断接收的字节
uint16_t tvoc_concentration = 0; // TVOC浓度 (ug/m³)
uint16_t formaldehyde_concentration = 0; // 甲醛浓度 (ug/m³)
uint16_t eco2_concentration = 0; // 等效eCO2浓度 (PPM)
uint8_t co2_data_ready = 0; // 数据解析完成标志
void co2_init(void)
{
HAL_UART_Receive_IT(&huart3, &co2_rx, 1);
}
void co2_it_get(void)
{
static uint8_t co2_state = 0;
static uint8_t tvoc_temp[2]; // TVOC高低字节
static uint8_t formaldehyde_temp[2]; // 甲醛高低字节
static uint8_t eco2_temp[2]; // eCO2高低字节
static uint8_t sum = 0; // 校验和(只保留低8位)
switch (co2_state)
{
case 0: // 等待帧头 0x2C
if (co2_rx == 0x2C) {
sum = 0x2C;
co2_state = 1;
}
break;
case 1: // 等待 0xE4
if (co2_rx == 0xE4) {
sum += 0xE4;
co2_state = 2;
} else {
co2_state = 0; // 帧头错误,重置
}
break;
case 2: // TVOC 高字节
tvoc_temp[0] = co2_rx;
sum += co2_rx;
co2_state = 3;
break;
case 3: // TVOC 低字节
tvoc_temp[1] = co2_rx;
sum += co2_rx;
co2_state = 4;
break;
case 4: // 甲醛 高字节
formaldehyde_temp[0] = co2_rx;
sum += co2_rx;
co2_state = 5;
break;
case 5: // 甲醛 低字节
formaldehyde_temp[1] = co2_rx;
sum += co2_rx;
co2_state = 6;
break;
case 6: // eCO2 高字节
eco2_temp[0] = co2_rx;
sum += co2_rx;
co2_state = 7;
break;
case 7: // eCO2 低字节
eco2_temp[1] = co2_rx;
sum += co2_rx;
co2_state = 8;
break;
case 8: // 校验和(第9字节)
sum &= 0xFF; // 只保留低8位(重要!)
if (sum == co2_rx) {
// 解析成功
tvoc_concentration = (tvoc_temp[0] << 8) | tvoc_temp[1];
formaldehyde_concentration = (formaldehyde_temp[0] << 8) | formaldehyde_temp[1];
eco2_concentration = (eco2_temp[0] << 8) | eco2_temp[1];
co2_data_ready = 1;
} else {
co2_data_ready = 0; // 校验失败
}
// 重置状态,准备下一帧
co2_state = 0;
sum = 0;
break;
default:
co2_state = 0;
sum = 0;
break;
}
debug_send("%c",co2_rx);
HAL_UART_Receive_IT(&huart3, &co2_rx, 1); // 启动下一次中断接收
}
5.1.4 SD卡代码
#include "sd.h"
extern uint8_t retSD; /* Return value for SD */
extern char SDPath[4]; /* SD logical drive path */
extern FATFS SDFatFS; /* File system object for SD logical drive */
extern FIL SDFile; /* File object for SD */
uint64_t Mytotal_size ;
uint64_t Myfree_size ;
/**
* @brief SD卡FATFS初始化,挂载SD卡并打印内存信息
*/
void sdio_fats_init() {
FRESULT fre;
DWORD total_clusters, free_clusters;
UINT sector_size;
char info_buf[128];
FATFS *p_fs; // 用于接收f_getfree返回的文件系统指针
// 挂载SD卡
fre = f_mount(&SDFatFS, SDPath, 1);
if (fre == FR_OK) {
HAL_UART_Transmit(&huart1, (uint8_t*)"SD mount ok\r\n", sizeof("SD mount ok\r\n"), 1000);
// 获取SD卡内存信息
fre = f_getfree(SDPath, &free_clusters, &p_fs);
if (fre == FR_OK) {
// 从返回的文件系统指针获取参数,SD卡标准扇区大小为512字节(替代ssize)
total_clusters = (p_fs->n_fatent - 2); // 总簇数(减去保留簇)
sector_size = 512; // SD卡默认扇区大小为512字节,修复ssize不存在的问题
uint64_t total_size = (uint64_t)total_clusters * p_fs->csize * sector_size;
uint64_t free_size = (uint64_t)free_clusters * p_fs->csize * sector_size;
Mytotal_size =total_size;
Myfree_size=free_size ;
// 格式化容量为MB
sprintf(info_buf, "Total: %llu MB, Free: %llu MB\r\n",
total_size / (1024 * 1024),
free_size / (1024 * 1024));
HAL_UART_Transmit(&huart1, (uint8_t*)info_buf, strlen(info_buf), 1000);
} else {
HAL_UART_Transmit(&huart1, (uint8_t*)"Get SD info error\r\n", sizeof("Get SD info error\r\n"), 1000);
}
} else {
HAL_UART_Transmit(&huart1, (uint8_t*)"SD mount error\r\n", sizeof("SD mount error\r\n"), 1000);
}
}
/**
* @brief 向date.txt追加写入温湿度数据
* @param temp 温度值
* @param humi 湿度值
*/
void sdio_fats_write(uint32_t temp, uint32_t humi) {
FRESULT fre;
UINT bw;
char data_buf[64];
// 格式化数据(%lu适配uint32_t)
sprintf(data_buf, "Temp:%d,Humi:%d\r\n", temp, humi);
// 打开文件:不存在则创建,存在则以写模式打开
fre = f_open(&SDFile, "date.txt", FA_OPEN_ALWAYS | FA_WRITE);
if (fre == FR_OK) {
// 移动文件指针到末尾,实现追加效果
f_lseek(&SDFile, f_size(&SDFile));
// 写入数据
fre = f_write(&SDFile, data_buf, strlen(data_buf), &bw);
if (fre == FR_OK && bw == strlen(data_buf)) {
HAL_UART_Transmit(&huart1, (uint8_t*)"Write success\r\n", sizeof("Write success\r\n"), 1000);
} else {
HAL_UART_Transmit(&huart1, (uint8_t*)"Write error\r\n", sizeof("Write error\r\n"), 1000);
}
// 关闭文件
f_close(&SDFile);
} else {
HAL_UART_Transmit(&huart1, (uint8_t*)"Open file error\r\n", sizeof("Open file error\r\n"), 1000);
}
}
六、工程主要内容
工程的具体内容包括但不限于原理图、程序代码、流程图等等。完整工程、原理图、APP 源码我已经开源到 Gitee,需要的同学可以评论区留言或者私信,004-基于STM32的智能仓库环境监控系统。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐




所有评论(0)