在本项目中,我们将搭建一个基于 STM32 的 NAS(网络附加存储)私盘,通过网络访问存储在外部 SATA 硬盘上的文件。该项目将使用 STM32 开发板、外接 SATA 硬盘、LwIP 协议栈以及 FATFS 文件系统来实现文件的上传、下载和管理,用户可以通过简单的 Web 界面进行操作。
STM32 开发板
存储介质
网络接口
电源管理
开发环境
固件库
文件系统
网络协议
main.c
或其他相应文件中包含头文件。以下是项目的主要代码实现部分,包括网络初始化、文件操作和 HTTP 服务器的实现。
#include "lwip/init.h" #include "lwip/netif.h" #include "lwip/tcpip.h" #include "ethernetif.h" void init_network(void) { lwip_init(); // 初始化 LwIP struct netif my_netif; ip_addr_t ipaddr, netmask, gw; // 设置网关和子网 IP4_ADDR(&gw, 192, 168, 1, 1); // 网关 IP4_ADDR(&ipaddr, 192, 168, 1, 100); // 设备 IP IP4_ADDR(&netmask, 255, 255, 255, 0); // 子网掩码 netif_add(&my_netif, &ipaddr, &netmask, &gw, NULL, ethernetif_init, tcpip_input); netif_set_default(&my_netif); // 设置为默认网络接口 netif_set_up(&my_netif); // 启动网络接口 }
说明:
lwip_init()
初始化 LwIP(轻量级 IP 协议栈)。netif_add()
添加网络接口,并配置 IP、网关和子网掩码。netif_set_up()
启动网络接口,使其可以进行通信。#include "ff.h" // FATFS 头文件 void create_file(void) { FATFS fs; // 文件系统对象 FIL fil; // 文件对象 FRESULT res; // 文件操作结果 char buffer[] = "Hello, STM32 NAS!"; // 挂载文件系统 res = f_mount(&fs, "", 1); if (res == FR_OK) { // 创建文件并写入数据 res = f_open(&fil, "test.txt", FA_WRITE | FA_CREATE_ALWAYS); if (res == FR_OK) { f_write(&fil, buffer, sizeof(buffer), NULL); // 写入数据 f_close(&fil); // 关闭文件 } } }
说明:
FATFS
是文件系统的结构体,FIL
是文件对象。f_mount()
挂载文件系统,这样就可以对存储设备进行操作。f_open()
创建或打开文件,并使用 f_write()
写入数据。f_close()
关闭文件,以释放资源。#include "httpd.h" // HTTP 服务器头文件 void start_http_server(void) { httpd_init(); // 初始化 HTTP 服务器 } // HTTP 请求处理示例 static void handle_get_request(struct httpd_state *hs) { const char *response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello from STM32 NAS!"; httpd_send(hs, response, strlen(response)); // 发送响应 }
说明:
httpd_init()
初始化 HTTP 服务器,准备接受请求。handle_get_request()
发送一个简单的文本响应。int main(void) { // 初始化系统 HAL_Init(); SystemClock_Config(); // 配置系统时钟 MX_GPIO_Init(); // 初始化 GPIO MX_SPI_Init(); // 初始化 SPI(用于以太网模块) MX_USB_OTG_FS_PCD_Init(); // 初始化 USB OTG(用于 SATA 硬盘) init_network(); // 初始化网络 create_file(); // 创建文件 start_http_server(); // 启动 HTTP 服务器 while (1) { // 处理网络事件 syscheck_timeouts(); } }
说明:
HAL_Init()
初始化硬件抽象层,设置基本的硬件配置。SystemClock_Config()
配置系统时钟,以保证系统的正常运行。init_network()
初始化网络,create_file()
创建文件,start_http_server()
启动 HTTP 服务器。while (1)
循环中,不断处理网络事件,保持系统运行。首先,您需要创建一个简单的项目结构,用于存放前端文件。假设我们将所有的前端文件放在 STM32 的文件系统中的 /www
目录下,项目结构如下:
/www ├── index.html ├── style.css └── script.js
下面是一个简单的 HTML 页面,提供文件上传和下载的功能。
STM32 NAS 私盘 STM32 NAS 私盘
上传文件
文件列表
下面是简单的 CSS 样式,用于美化前端界面。
body { font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 20px; } .container { max-width: 600px; margin: 0 auto; background: #fff; padding: 20px; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); } h1 { text-align: center; } .upload-section, .file-list { margin-bottom: 30px; } button { padding: 10px 15px; background-color: #28a745; color: white; border: none; border-radius: 5px; cursor: pointer; } button:hover { background-color: #218838; }
我们将使用 AJAX 来与 STM32 后端进行交互,实现文件上传和获取文件列表的功能。
document.getElementById('uploadButton').onclick = function() { const fileInput = document.getElementById('fileInput'); const file = fileInput.files[0]; if (!file) { alert('请选择一个文件!'); return; } const formData = new FormData(); formData.append('file', file); fetch('/upload', { // 发送文件到后端 method: 'POST', body: formData }) .then(response => response.text()) .then(data => { alert(data); loadFileList(); // 上传成功后更新文件列表 }) .catch(error => console.error('Error:', error)); }; function loadFileList() { fetch('/files') // 请求文件列表 .then(response => response.json()) .then(files => { const fileList = document.getElementById('fileList'); fileList.innerHTML = ''; // 清空文件列表 files.forEach(file => { const li = document.createElement('li'); li.textContent = file; fileList.appendChild(li); }); }) .catch(error => console.error('Error:', error)); } // 页面加载时获取文件列表 window.onload = loadFileList;
为了使前端能够与后端进行交互,我们需要在 STM32 的 HTTP 服务器中处理文件上传和文件列表请求。
#include "httpd.h" // HTTP 服务器头文件 #include "ff.h" // FATFS 头文件 // 处理文件上传请求 static void handle_file_upload(struct httpd_state *hs) { char buf[512]; FIL fil; FRESULT res; char *filename = "uploaded_file.txt"; // 上传的文件名 // 读取 HTTP 请求体 int bytes_read = httpd_read_request_body(hs, buf, sizeof(buf)); if (bytes_read > 0) { // 创建文件并写入数据 res = f_open(&fil, filename, FA_WRITE | FA_CREATE_ALWAYS); if (res == FR_OK) { f_write(&fil, buf, bytes_read, NULL); // 写入文件 f_close(&fil); // 关闭文件 httpd_send_response(hs, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nFile uploaded successfully!"); // 响应成功 } else { httpd_send_response(hs, "HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n\r\nFailed to open file!"); // 响应失败 } } else { httpd_send_response(hs, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\n\r\nInvalid request body!"); // 响应无效请求 } }
说明:
httpd_read_request_body(hs, buf, sizeof(buf))
读取 HTTP 请求体中的文件数据。f_open()
创建或打开文件,然后使用 f_write()
写入数据。接下来,我们需要实现一个功能来获取当前存储设备中的所有文件。
#include "ff.h" // FATFS 头文件 // 处理文件列表请求 static void handle_file_list(struct httpd_state *hs) { DIR dir; FILINFO fno; FRESULT res; char response[1024]; int response_length = 0; // 打开目录 res = f_opendir(&dir, "/"); // 假设所有文件都在根目录 if (res == FR_OK) { response_length += snprintf(response + response_length, sizeof(response) - response_length, "["); while ((res = f_readdir(&dir, &fno)) == FR_OK && fno.fname[0] != 0) { if (response_length > 1) { response_length += snprintf(response + response_length, sizeof(response) - response_length, ","); } response_length += snprintf(response + response_length, sizeof(response) - response_length, "\"%s\"", fno.fname); } response_length += snprintf(response + response_length, sizeof(response) - response_length, "]"); f_closedir(&dir); httpd_send_response(hs, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n"); httpd_send_response(hs, response); // 发送文件列表 } else { httpd_send_response(hs, "HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain\r\n\r\nFailed to open directory!"); // 响应失败 } }
说明:
f_opendir()
打开根目录,使用 f_readdir()
读取目录中的文件。application/json
。在 HTTP 服务器初始化时,我们需要将上传和文件列表请求的处理函数绑定到相应的 URL。
void start_http_server(void) { httpd_init(); // 初始化 HTTP 服务器 // 绑定请求处理函数 httpd_register_uri("/upload", handle_file_upload, HTTP_POST); // 处理文件上传 httpd_register_uri("/files", handle_file_list, HTTP_GET); // 获取文件列表 }
说明:
httpd_register_uri()
函数用于将请求 URL 与处理函数进行绑定。/upload
URL 用于处理文件上传请求,/files
URL 用于获取文件列表。在本项目中,我们成功地搭建了一个基于 STM32 的 NAS(网络附加存储)私盘,利用 STM32 开发板的强大功能和灵活性,结合 LwIP 协议栈和 FATFS 文件系统,实现了文件的上传、下载和管理。以下是本项目的关键要点和收获:
通过选择适合的 STM32 开发板(如 STM32F407 或 STM32F746),并配合外部 SATA 硬盘和网络模块(如以太网或 Wi-Fi),我们有效地创建了一个功能强大的 NAS 解决方案。硬件部分的选择对于系统的稳定性和性能至关重要,而软件部分则利用了 STM32 HAL 库、FATFS 文件系统和 LwIP 协议栈,使得硬件功能得以充分发挥。
我们成功实现了基本的文件管理功能,包括文件的上传、下载和列表展示。通过使用 FATFS 库,我们能够方便地对外接存储进行文件操作,这为用户在 NAS 上进行文件管理提供了便利。
通过搭建简单的 Web 前端界面,用户能够直观地与 NAS 进行交互。使用 HTML、CSS 和 JavaScript,我们实现了文件上传和文件列表展示功能,使得用户在浏览器中就可以方便地操作存储在 STM32 上的文件。此外,利用 AJAX 技术,我们实现了无刷新数据交互,提升了用户体验。
使用 LwIP 协议栈,我们为 STM32 开发板实现了网络通信功能。通过 HTTP 协议,前端与后端的交互得以顺利进行。我们实现了对文件上传和文件列表请求的处理,使得用户能够通过网络访问 NAS 中的文件。
上一篇:dfs(续做)