当前位置: 首页 > news >正文

基于 W55MH32Q-EVB 实现 FatFs 文件系统+FTP 服务器

目录

1 前言

2 项目环境

2.1 硬件准备

2.2 软件环境

3 硬件连接和方案

3.1 W55MH32Q-EVB 硬件连接

3.2 方案图示

4 例程修改

5.运行结果

6.总结


1 前言

FTP(File Transfer Protocol,文件传输协议)是遵循文件传输协议(FTP),在网络中提供文件传输服务的重要组件。它采用客户端 - 服务器架构,工作模式分为主动和被动。主动模式下,服务器主动发起数据连接;被动模式中,由客户端发起数据连接。用户访问时,需进行身份验证,常见方式是输入用户名和密码,部分服务器也支持匿名登录。

W55MH32Q-EVB 是基于 W55MH32Q芯片开发的一款开发板,主频为 216MHz,1MB 的闪存以及 96KB 的 SRAM,同时还具有一个完整的硬件 TCP/IP 卸载引擎,只需要简单的 socket 编程即可实现以太网应用。 具有以下特点:

  • 增强型、真随机数、硬件加密算法单元
  • 32 位 Arm® Cortex®-M3 核心的片上
  • 1024K 字节闪存的微控制器
  • 10/100M 以太网 MAC 和 PHY、集成完整的全硬件 TCP/IP 协议栈引擎
  • USB、CAN、17 个定时器
  • 3 个 ADC、2 个 DAC、12 个通信接口

产品链接:商品详情

2 项目环境

2.1 硬件准备

  • W55MH32Q-EVB 模块
  • 杜邦线若干
  • 交换机或路由器
  • W25Q64 模块
  • 一根网线

2.2 软件环境

  • 例程链接:https://www.w5500.com/w55mh32.html
  • FreeAT_2.2.0.0.exe
  • Keil5
  • FatFs源码

3 硬件连接和方案

3.1 W55MH32Q-EVB 硬件连接

1.W55MH32Q-EVB_3.3V ---> W25Q64_VCC
2.W55MH32Q-EVB_GND ---> W25Q64_GND
3.W55MH32Q-EVB_PA4 ---> OLED_CS
4.W55MH32Q-EVB_PA5 ---> OLED_SCK
5.W55MH32Q-EVB_PA6 ---> OLED_MISO
6.W55MH32Q-EVB_PA7 ---> OLED_MOSI

3.2 方案图示

4 例程修改

本次以 FTP_Server 例程为例。

由于 ftp.c 文件代码较长,修改较多,且分散,所以我上传到了百度网盘,访问链接获取 ftpd.c 文件。

将下载好的文件替换掉例程中的 ftpd.c 文件,并在 ftpd.h 中启用 F_FILESYSTEM 这个宏定义。

创建文件 w25qxx.c,用于驱动 W25Q64,代码如下:

#include "w25qxx.h"
#include "delay.h"u16 W25QXX_TYPE = W25Q128; // The default is W25Q128.// SPIx reads and writes a byte
// TxData: Bytes to write
// Return value: bytes read
u8 SPI_ReadWriteByte(u8 TxData)
{
    u8 retry = 0;while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) // Check whether the specified SPI flag is set or not: Send cache null flag{
        retry++;if (retry > 200)return 0;}SPI_I2S_SendData(SPI1, TxData); // Send a data via peripheral SPIx
    retry = 0;while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) // Check whether the specified SPI flag is set or not: Accept cache non-empty flags{
        retry++;if (retry > 200)return 0;}return SPI_I2S_ReceiveData(SPI1); // Returns the most recently received data via SPIx
}void SPI_InitTest(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // PORT Aclock enableRCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);  // SPI1 clock enable    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA, GPIO_Pin_4);W25QXX_CS = 1; // SPI FLASH not selected    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // PA/5/6/7 Multiplexed push-pull output
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); // Initialize GPIOAGPIO_SetBits(GPIOA, GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7); // PA5/6/7 pull up    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;   // Set SPI to one-way or two-way data mode: SPI is set to 2 lines full duplex
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                        // Set SPI working mode: Set the Master
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                    // Set the data size of the SPI: SPI sends and receives 8-bit frame structures
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                          // The idle state of the serial synchronous clock is high
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                         // The second hop edge (up or down) of the serial synchronization clock is sampled
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                            // NSS signals are managed by hardware (NSS pins) or software (using SSI bits): Internal NSS signals are controlled by SSI bits
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; // Define the value of the baud rate prescaler: The baud rate prescaler is 256.
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                   // Specify whether the data transfer starts with the MSB bit or the LSB bit: Data transfer starts with the MSB bit
    SPI_InitStructure.SPI_CRCPolynomial = 7;                             // Polynomial for CRC Value CalculationSPI_Init(SPI1, &SPI_InitStructure);                                  // Initializes peripheral SPIx registers according to the parameters specified in the SPI_InitStructSPI_Cmd(SPI1, ENABLE); // enable SPI peripheralsSPI_ReadWriteByte(0xff); // Initiate transfer
}
// SPI speed setting function
// SpeedSet:
// SPI_BaudRatePrescaler_2   2 division
// SPI_BaudRatePrescaler_8   8 division
// SPI_BaudRatePrescaler_16  16 division
// SPI_BaudRatePrescaler_256 256 divisionvoid SPI_SetSpeed(u8 SPI_BaudRatePrescaler)
{assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));SPI1->CR1 &= 0XFFC7;SPI1->CR1 |= SPI_BaudRatePrescaler;SPI_Cmd(SPI1, ENABLE);
}// Read the status register of the W25QXX
// BIT7 6 5 4 3 2 1 0
// SPR RV TB BP2 BP1 BP0 WEL BUSY
// SPR: default 0, status register protection bit, used with WP
// TB, BP2, BP1, BP0: FLASH regional write protection settings
// WEL: Write enable lock
// BUSY: busy flag bit (1, busy; 0, idle)
// Default: 0x00
u8 W25QXX_ReadSR(void)
{
    u8 byte = 0;W25QXX_CS = 0;                         // enable deviceSPI_ReadWriteByte(W25X_ReadStatusReg); // Send read status register command
    byte = SPI_ReadWriteByte(0Xff);        // Read a byteW25QXX_CS = 1;                         // Cancel selectionreturn byte;
}
// Write the W25QXX status register
// Only SPR, TB, BP2, BP1, BP0 (bit 7, 5, 4, 3, 2) can be written!!!
void W25QXX_Write_SR(u8 sr)
{W25QXX_CS = 0;                          // enable deviceSPI_ReadWriteByte(W25X_WriteStatusReg); // Send write status register commandSPI_ReadWriteByte(sr);                  // Write a byteW25QXX_CS = 1;                          // Cancel selection
}
// W25QXX write enable
// set WEL
void W25QXX_Write_Enable(void)
{W25QXX_CS = 0;                       // enable deviceSPI_ReadWriteByte(W25X_WriteEnable); // Send write enableW25QXX_CS = 1;                       // Cancel selection
}
// W25QXX write disabled
// Clear WEL
void W25QXX_Write_Disable(void)
{W25QXX_CS = 0;                        // enable deviceSPI_ReadWriteByte(W25X_WriteDisable); // Send write ban commandW25QXX_CS = 1;                        // Cancel selection
}
// Read the chip ID
// The return value is as follows:
// 0XEF13, indicating that the chip model is W25Q80.
// 0XEF14, indicating that the chip model is W25Q16.
// 0XEF15, indicating that the chip model is W25Q32
// 0XEF16, indicating that the chip model is W25Q64.
// 0XEF17, indicating that the chip model is W25Q128
u16 W25QXX_ReadID(void)
{
    u16 Temp = 0;W25QXX_CS = 0;SPI_ReadWriteByte(0x90); // Send Read ID commandSPI_ReadWriteByte(0x00);SPI_ReadWriteByte(0x00);SPI_ReadWriteByte(0x00);
    Temp |= SPI_ReadWriteByte(0xFF) << 8;
    Temp |= SPI_ReadWriteByte(0xFF);W25QXX_CS = 1;return Temp;
}
// read SPI FLASH
// Start reading data of the specified length at the specified address
// pBuffer: data store
// ReadAddr: Address to start reading (24bit)
// NumByteToRead: The number of bytes to read (max. 65535)
void W25QXX_Read(u8 *pBuffer, u32 ReadAddr, u16 NumByteToRead)
{
    u16 i;W25QXX_CS = 0;                             // enable deviceSPI_ReadWriteByte(W25X_ReadData);          // Send read commandSPI_ReadWriteByte((u8)((ReadAddr) >> 16)); // Send 24bit addressSPI_ReadWriteByte((u8)((ReadAddr) >> 8));SPI_ReadWriteByte((u8)ReadAddr);for (i = 0; i < NumByteToRead; i++){
        pBuffer[i] = SPI_ReadWriteByte(0XFF); // cyclic reading}W25QXX_CS = 1;
}
// SPI writes less than 256 bytes of data in one page (0~ 65535)
// Start writing data up to 256 bytes at the specified address
// pBuffer: data store
// WriteAddr: Address to start writing (24bit)
// NumByteToWrite: The number of bytes to write (max 256), which should not exceed the number of bytes remaining on the page!!!
void W25QXX_Write_Page(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
    u16 i;W25QXX_Write_Enable();                      // SET WELW25QXX_CS = 0;                              // enable deviceSPI_ReadWriteByte(W25X_PageProgram);        // Send page write commandSPI_ReadWriteByte((u8)((WriteAddr) >> 16)); // Send 24bit addressSPI_ReadWriteByte((u8)((WriteAddr) >> 8));SPI_ReadWriteByte((u8)WriteAddr);for (i = 0; i < NumByteToWrite; i++)SPI_ReadWriteByte(pBuffer[i]); // write loopW25QXX_CS = 1;                     // Cancel selectionW25QXX_Wait_Busy();                // Wait for write to finish
}
// Write SPI FLASH without test
// You must ensure that all data within the written address range is 0XFF, otherwise data written at non-0XFF will fail!
// with automatic page feed function
// Start writing data of the specified length at the specified address, but make sure the address does not exceed the limit!
// pBuffer: data store
// WriteAddr: Address to start writing (24bit)
// NumByteToWrite: The number of bytes to write (max. 65535)
// CHECK OK
void W25QXX_Write_NoCheck(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
    u16 pageremain;
    pageremain = 256 - WriteAddr % 256; // The number of bytes remaining on a single pageif (NumByteToWrite <= pageremain)
        pageremain = NumByteToWrite; // No more than 256 byteswhile (1){W25QXX_Write_Page(pBuffer, WriteAddr, pageremain);if (NumByteToWrite == pageremain)break; // Write is overelse       // NumByteToWrite>pageremain{
            pBuffer += pageremain;
            WriteAddr += pageremain;            NumByteToWrite -= pageremain; // Subtract the number of bytes that have been writtenif (NumByteToWrite > 256)
                pageremain = 256; // 256 bytes can be written at a timeelse
                pageremain = NumByteToWrite; // Not enough 256 bytes}};
}
// write SPI FLASH
// Start writing data of the specified length at the specified address
// This function has an erase operation!
// pBuffer: data store
// WriteAddr: Address to start writing (24bit)
// NumByteToWrite: The number of bytes to write (max. 65535)
u8 W25QXX_BUFFER[4096];
void SPI_FLASH_BufferWrite(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
    u32 secpos;
    u16 secoff;
    u16 secremain;
    u16 i;
    u8 *W25QXX_BUF;W25QXX_BUF = W25QXX_BUFFER;
    secpos = WriteAddr / 4096; // sector address
    secoff = WriteAddr % 4096; // Offset within a sector
    secremain = 4096 - secoff; // Sector free space size// printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//for testingif (NumByteToWrite <= secremain)
        secremain = NumByteToWrite; // No more than 4096 byteswhile (1){W25QXX_Read(W25QXX_BUF, secpos * 4096, 4096); // Read the content of the entire sectorfor (i = 0; i < secremain; i++)               // validation data{if (W25QXX_BUF[secoff + i] != 0XFF)break; // Need to erase}if (i < secremain) // Need to erase{SPI_FLASH_SectorErase(secpos);    // Erase this sectorfor (i = 0; i < secremain; i++) // copy{W25QXX_BUF[i + secoff] = pBuffer[i];}W25QXX_Write_NoCheck(W25QXX_BUF, secpos * 4096, 4096); // Write entire sector}elseW25QXX_Write_NoCheck(pBuffer, WriteAddr, secremain); // Write what has been erased, directly write the remaining section of the sector.if (NumByteToWrite == secremain)break; // Write is overelse       // Write not finished{
            secpos++;   // sector address+1
            secoff = 0; // The offset position is 0.            pBuffer += secremain;        // pointer offset
            WriteAddr += secremain;      // write address offset
            NumByteToWrite -= secremain; // Decrementing Bytesif (NumByteToWrite > 4096)
                secremain = 4096; // I can't finish writing the next sector.else
                secremain = NumByteToWrite; // The next sector can be written}};
}
// Erase the entire chip
// Waiting time is too long...
void W25QXX_Erase_Chip(void)
{W25QXX_Write_Enable(); // SET WELW25QXX_Wait_Busy();W25QXX_CS = 0;                     // enable deviceSPI_ReadWriteByte(W25X_ChipErase); // Send slice erase commandW25QXX_CS = 1;                     // Cancel selectionW25QXX_Wait_Busy();                // Wait for chip erase to finish
}
// erase a sector
// Dst_Addr: sector address is set according to actual capacity
// Minimum time to erase a mountain: 150ms
void SPI_FLASH_SectorErase(u32 Dst_Addr)
{// Monitor falsh erasure, testW25QXX_Write_Enable(); // SET WELW25QXX_Wait_Busy();W25QXX_CS = 0;                             // enable deviceSPI_ReadWriteByte(W25X_SectorErase);       // Send sector erase commandSPI_ReadWriteByte((u8)((Dst_Addr) >> 16)); // Send 24bit addressSPI_ReadWriteByte((u8)((Dst_Addr) >> 8));SPI_ReadWriteByte((u8)Dst_Addr);W25QXX_CS = 1;      // Cancel selectionW25QXX_Wait_Busy(); // Wait for erase to complete
}
// Enter power-down mode
void W25QXX_Wait_Busy(void)
{while ((W25QXX_ReadSR() & 0x01) == 0x01); // Wait for the BUSY bit to clear
}
// Enter power-down mode
void W25QXX_PowerDown(void)
{W25QXX_CS = 0;                     // enable deviceSPI_ReadWriteByte(W25X_PowerDown); // Send power down commandW25QXX_CS = 1;                     // Cancel selectiondelay_us(3);                       // Waiting for TPD
}
// wake up
void W25QXX_WAKEUP(void)
{W25QXX_CS = 0;                            // enable deviceSPI_ReadWriteByte(W25X_ReleasePowerDown); //  send W25X_PowerDown comand 0xABW25QXX_CS = 1;                            // Cancel selectiondelay_us(3);                              // Wait for TRES1
}

创建 w25qxx.h 头文件,代码如下:

#ifndef __FLASH_H
#define __FLASH_H
#include "w55mh32.h"// W25X series/Q series chip list
// W25Q80  ID  0XEF13
// W25Q16  ID  0XEF14
// W25Q32  ID  0XEF15
// W25Q64  ID  0XEF16
// W25Q128 ID  0XEF17
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17extern u16 W25QXX_TYPE; // Define the W25QXX chip model#define W25QXX_CS PAout(4) // W25QXX chip selection signal////////////////////////////////////////////////////////////////////////////
// IO port operation macro definition
#define BITBAND(addr, bitnum) ((addr & 0xF0000000) + 0x2000000 + ((addr & 0xFFFFF) << 5) + (bitnum << 2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
// IO port address mapping
#define GPIOA_ODR_Addr (GPIOA_BASE + 12) // 0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE + 12) // 0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE + 12) // 0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE + 12) // 0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE + 12) // 0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE + 12) // 0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE + 12) // 0x40011E0C#define GPIOA_IDR_Addr (GPIOA_BASE + 8) // 0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE + 8) // 0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE + 8) // 0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE + 8) // 0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE + 8) // 0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE + 8) // 0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE + 8) // 0x40011E08// IO port operation, only for a single IO port!
// Make sure the value of n is less than 16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr, n) // output
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr, n)  // input#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr, n) // output
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr, n)  // input#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr, n) // output
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr, n)  // input#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr, n) // output
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr, n)  // input#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr, n) // output
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr, n)  // input#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr, n) // output
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr, n)  // input#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr, n) // output
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr, n)  // input// instruction list
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9Fvoid SPI_InitTest(void);
u16 W25QXX_ReadID(void);         // Read Flash ID
u8 W25QXX_ReadSR(void);          // Read status register
void W25QXX_Write_SR(u8 sr);     // Write status register
void W25QXX_Write_Enable(void);  // write enable
void W25QXX_Write_Disable(void); // write protection
void W25QXX_Write_NoCheck(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite);
void W25QXX_Read(u8 *pBuffer, u32 ReadAddr, u16 NumByteToRead);             // Read flash
void SPI_FLASH_BufferWrite(u8 *pBuffer, u32 WriteAddr, u16 NumByteToWrite); // Write flash
void W25QXX_Erase_Chip(void);                                               // Whole piece erase
void SPI_FLASH_SectorErase(u32 Dst_Addr);                                   // sector erase
void W25QXX_Wait_Busy(void);                                                // Wait for idle
void W25QXX_PowerDown(void);                                                // Enter power-down mode
void W25QXX_WAKEUP(void);                                                   // wake up
#endif

修改主函数 main.c,代码如下:

#include "bsp_rcc.h"
#include "bsp_tim.h"
#include "bsp_uart.h"
#include "delay.h"
#include "diskio.h"
#include "ftpd.h"
#include "wiz_interface.h"
#include "wizchip_conf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define SOCKET_ID 0
#define ETHERNET_BUF_MAX_SIZE (1024 * 4)/* network information */
wiz_NetInfo default_net_info = {
    .mac = {0x00, 0x08, 0xdc, 0x12, 0x22, 0x12},
    .ip = {192, 168, 1, 30},
    .gw = {192, 168, 1, 1},
    .sn = {255, 255, 255, 0},
    .dns = {8, 8, 8, 8},
    .dhcp = NETINFO_DHCP};FATFS fs; /* FatFs 文件系统对象 */
uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0};void mount_flash(void)
{
    FRESULT res_flash;    // 在外部 SPI Flash 挂载文件系统,文件系统挂载时会对 SPI 设备初始化
    res_flash = f_mount(&fs, "1:", 1);
    if (res_flash == FR_NO_FILESYSTEM)
    {
        printf("FLASH not has a file system yet and to do formatting\r\n");
        /* 格式化 */
        res_flash = f_mkfs("1:", 0, 0);        if (res_flash == FR_OK)
        {
            printf("FLASH file system has been successfully formatted.\r\n");
            /* 格式化后,先取消挂载 */
            res_flash = f_mount(NULL, "1:", 1);
            if (res_flash != FR_OK)
            {
                printf("Unmount failed with error: %d\r\n", res_flash);
                while (1)
                    ;
            }
            else
                printf("Unremount success\r\n");            /* 重新挂载 */
            res_flash = f_mount(&fs, "1:", 1);
            if (res_flash != FR_OK)
            {
                printf("Remount failed with error: %d\r\n", res_flash);
                while (1)
                    ;
            }
            else
                printf("Remount success\r\n");
        }
        else
        {
            printf("format fail\r\n");
            while (1)
                ;
        }
    }
    else if (res_flash != FR_OK)
    {
        printf("remount fail,error code:(%d)\r\n", res_flash);
        while (1)
            ;
    }
    else
    {
        printf("mount success!\r\n");
    }    // 更改当前驱动器
    res_flash = f_chdrive("1:");
    if (res_flash != FR_OK)
    {
        printf("change fail,error code:%d\r\n", res_flash);
    }
}int main(void)
{
    wiz_NetInfo net_info;
    /* hardware initialization */
    rcc_clk_config();
    delay_init();
    // unsigned char *asd = NULL;
    // int qwe = 0;    console_usart_init(115200);    mount_flash();    tim3_init();    printf("%s FTP Server example\r\n", _WIZCHIP_ID_);    /* wiztoe init */
    wiz_toe_init();    wiz_phy_link_check();    network_init(ethernet_buf, &default_net_info);    wizchip_getnetinfo(&net_info);
    ftpd_init(net_info.ip);
    while (1)
    {
        ftpd_run(ethernet_buf);
    }

5.运行结果

目前的 FatFs 文件系统支持删除,上传服务器文件,也支持删除和上传目录。当前文件系统仅支持英文,如果需要支持中文,需要在 ffconf.h 中修改_CODE_PAGE 宏定义为 936 并使用 cc936.c 文件即可。

由于FatFs不支持访问权限一功能所以代码预定义一个访问权限全部设为可读可写执行客户端这边显示就是rwxrwxrwx另外当前不支持修改时间如果需要设备上电访问sntp服务器启用RTC时钟即可

客户端使用 filezilla 做测试,访问FileZilla - The free FTP solution下载。

目前我的文件系统有一些文件,当使用 filezilla 访问服务器时,会显示如下文件:

删除目录操作如下:

由于操作较多,其他操作就不演示了。可自行测试。

6.总结

本文详细介绍了如何利用 W55Mh32Q-EVB 实现 FTP 服务器,通过移植 FatFs 文件系统来存储文件,可用于存储日志信息等。感谢大家的耐心阅读!如果您在阅读过程中有任何疑问,或者希望进一步了解这款产品及其应用,欢迎随时通过私信或评论区留言。我们会尽快回复您的消息,为您提供更详细的解答和帮助!

http://www.dtcms.com/a/351528.html

相关文章:

  • C++ SNIFE
  • 数据结构——链表(2)——双向链表
  • 【图像处理 - 基础知识】ISP(Image Signal Processor)处理
  • 深度学习之卷积神经网络
  • 组件版本升级 - MySQL_8.4对比MySQL_8.0
  • 用 mem0 构建一个简单的 AI Healthcare 助手
  • 基于Vue通用组件定制化的场景解决
  • UNet改进(35):基于WGAM模块的PyTorch实战
  • Qt在Linux下编译发布 -- linuxdeployqt的使用
  • 第十九节:阴影进阶 - 软阴影与性能平衡技术
  • FileMenu Tools for Win:突破 Windows 文件管理困境的利器
  • Git:基本使用
  • 数字化转型三阶段:从信息化、数字化到数智化的战略进化
  • Leetcode+Java+动态规划II
  • 知行——同为科技24周年庆典
  • Thingsboard 租户管理员权限,增加租户普通用户权限
  • Go errgroup:高效并发控制与错误处理
  • WPF基于LiveCharts2图形库,实现:折线图,柱状图,饼状图
  • 03. 协程入门_Android异步处理机制
  • 系统架构设计师备考第7天——网络协议中间件软件构件
  • WebSocket简单了解
  • 线性代数之深入理解旋转矩阵
  • lesson46-2:Linux 高级指令全解析:从文件操作到系统管理
  • mybatisplus 配置二级缓存
  • 【系统编程】线程简介
  • 【人工智能】2025年AI代理开源革命:社区驱动的智能体生态重塑未来
  • Linux--seLinux的概述
  • FRET、PLA、Co-IP和GST pull-down有何区别? 应该如何选择?
  • 原型模式系统开发中的原型分类全景:水平、垂直、抛弃式与演化式
  • nvm切换node版本之后报错,无法将“node”项识别为 cmdlet、函数、脚本文件或可运行程序的名称