二、串行FLASH文件系统FatFs移植

经过上一节的分析,我们对文件系统有一定的理解了,这一节给大家介绍怎么把FatFs文件系统的这些代码移植到STM32S上,然后STM32利用这一些代码或者函数,以文件的格式对FLASH进行读写数据。

实则对diskio.c提供一些函数接口。

首先将 ff11a\src文件夹拷贝至user底下,重命名为fatFs,以方便我们后续操作

       

移植文件系统主要就是实现底层disk函数的具体功能

一、底层disk接口程序API配置

1、首先将diskio.c和ff.c包含到工程中,如图所示:

 2、添加完成之后,点击编译,报错找不到头文件,我们需要将diskio.c官方测试样例的三个头文件注释掉

 3、将diskio.c中的result = ATA_disk_status();、result = MMC_disk_status();和result = USB_disk_status();注释掉

4、注释完之后,再次编译,找不到get_fattime,我们需要手动将get_fattime()函数添加到文件中

//返回时间
DWORD get_fattime (void)
{
    //这个我不用 所以没有实现
    return 0;

}

5、可以发现diskio.h中官方已经定义了三个物理存储介质编号ATA、MMC和USB,diskio中的所有存储介质操作函数通过传入参数判断区分具体操作哪个存储介质,我用的SD卡和FLASH就将之前定义的宏注释掉,重新定义自己的宏,并将所有底层操作函数中所有的switch case中的原存储介质替换掉

6、首先我们来看disk_initialize函数,只有一个参数用于传入存储设备编号,编号用于区分操作的存储器,返回值返回当前的存储器状态。该函数用于初始化存储设备,并使设备进入读写可用的状态,初始化完之后用于返回一个状态值来告诉上层的调用者。

该函数用于被FatFs module(中间层)调用,不能直接使用,需要使用中间层的f_mount挂载函数来调用(我们初始化文件系统都通过使用f_mount来实现)

(1)首先将SPI_FLASH_Init(),函数添加到  case SPI_FLASH :中。

(2)接着要返回一个状态,但我们仅仅通过SPI_FLASH_Init()不知道是否初始化FLASH成功。因此我们通过SPI_FLASH_ReadID()函数通过判断读取设备号是否成功来判断,将SPI_FLASH_ReadID()放在“ DSTATUS disk_status (BYTE pdrv){}”状态读取函数中

/*-----------------------------------------------------------------------*/
/* 获取设备状态                                                          */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
	BYTE pdrv		/* 物理编号 */
)
{

	DSTATUS status = STA_NOINIT;
	
	switch (pdrv) {
		case ATA:	/* SD CARD */
			break;
    
		case SPI_FLASH:      
      /* SPI Flash状态检测:读取SPI Flash 设备ID */
      if(sFLASH_ID == SPI_FLASH_ReadID())
      {
        /* 设备ID读取结果正确 */
        status &= ~STA_NOINIT;
      }
      else
      {
        /* 设备ID读取结果错误 */
        status = STA_NOINIT;;
      }
			break;

		default:
			status = STA_NOINIT;
	}
	return status;
}

 (4)如果我们不确定FLASH是否处于低功耗模式,我们需要在init后面添加SPI_Flash_WAKEUP()函数来确保FLASH处于正常功耗模式(因为FLASH在低功耗状态下,无法正常工作),所以disk_initializ函数的写法如下:

*-----------------------------------------------------------------------*/
/* 设备初始化                                                            */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
	BYTE pdrv				/* 物理编号 */
)
{
  uint16_t i;
	DSTATUS status = STA_NOINIT;	
	switch (pdrv) {
		case ATA:	         /* SD CARD */
			break;
    
		case SPI_FLASH:    /* SPI Flash */ 
      /* 初始化SPI Flash */
			SPI_FLASH_Init();
      /* 延时一小段时间 */
      i=500;
	    while(--i);	
      /* 唤醒SPI Flash */
	    SPI_Flash_WAKEUP();
      /* 获取SPI Flash芯片状态 */
      status=disk_status(SPI_FLASH);
			break;
      
		default:
			status = STA_NOINIT;
	}
	return status;
}

7、继续我们来配置disk_read()函数

disk_read()函数如下:

用于读取扇区(一个或者多个),第一个参数为设备号;第二个参数为读取扇区的起始地址,读取完数据后通过指针返回给上层,具体传入数组或指针由上层定义;第三个参数为开始的扇区号;第四个个参数为读取的扇区个数。

通过调用void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead);函数来实现扇区的读取。通过disk_read()中的sector扇区号来计算出ReadAddr起始地址,通过count扇区个数来算出NumByteToRead要读取多少个字节。一个扇区4096Byte(4KB),一个块有16个扇区,但是此处扇区偏移2MB,外部Flash文件系统空间放在SPI Flash后面6MB空间

通过调用SPI_FLASH_BufferRead()函数,并算出对应参数。默认读取成功,返回值为RES_OK
 

/*-----------------------------------------------------------------------*/
/* 读扇区:读取扇区内容到指定存储区                                              */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
	BYTE pdrv,		/* 设备物理编号(0..) */
	BYTE *buff,		/* 数据缓存区 */
	DWORD sector,	/* 扇区首地址 */
	UINT count		/* 扇区个数(1..128) */
)
{
	DRESULT status = RES_PARERR;
	switch (pdrv) {
		case ATA:	/* SD CARD */
			break;
    
		case SPI_FLASH:
      /* 扇区偏移2MB,外部Flash文件系统空间放在SPI Flash后面6MB空间 */
      sector+=512;      
      SPI_FLASH_BufferRead(buff, sector <<12, count<<12);
      status = RES_OK;
		break;
    
		default:
			status = RES_PARERR;
	}
	return status;
}

8、接着配置disk_write()函数,注意使用写功能,必须将_FS_READONLY置0,否则只支持只读

/*-----------------------------------------------------------------------*/
/* 写扇区:见数据写入指定扇区空间上                                      */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT disk_write (
	BYTE pdrv,			  /* 设备物理编号(0..) */
	const BYTE *buff,	/* 欲写入数据的缓存区 */
	DWORD sector,		  /* 扇区首地址 */
	UINT count			  /* 扇区个数(1..128) */
)
{
  uint32_t write_addr; 
	DRESULT status = RES_PARERR;
	if (!count) {
		return RES_PARERR;		/* Check parameter */
	}

	switch (pdrv) {
		case ATA:	/* SD CARD */      
		break;

		case SPI_FLASH:
      /* 扇区偏移2MB,外部Flash文件系统空间放在SPI Flash后面6MB空间 */
			sector+=512;
      write_addr = sector<<12;    
      SPI_FLASH_SectorErase(write_addr);
      SPI_FLASH_BufferWrite((u8 *)buff,write_addr,count<<12);
      status = RES_OK;
		break;
    
		default:
			status = RES_PARERR;
	}
	return status;
}
#endif

9、再来配置disk_ioctl函数,

在初始化设备前,必须将存储设备进行格式化,建立好文件信息结构,从而才能实现对设备存储内容以文件格式进行读写。

第一个参数为设备号;第二个参数为cmd命令号,文件系统通过命令号来告诉底层,比如获取当前设备的容量,某个文件的大小等等(底层通过switch...case...来确定不同的返回值);第三个参数buff既可以作为输入也可以作为输出

/*-----------------------------------------------------------------------*/
/* 其他控制                                                              */
/*-----------------------------------------------------------------------*/

#if _USE_IOCTL
DRESULT disk_ioctl (
	BYTE pdrv,		/* 物理编号 */
	BYTE cmd,		  /* 控制指令 */
	void *buff		/* 写入或者读取数据地址指针 */
)
{
	DRESULT status = RES_PARERR;
	switch (pdrv) {
		case ATA:	/* SD CARD */
			break;
    
		case SPI_FLASH:
			switch (cmd) {
        /* 扇区数量:1536*4096/1024/1024=6(MB) */
        case GET_SECTOR_COUNT:
          *(DWORD * )buff = 1536;		
        break;
        /* 扇区大小  */
        case GET_SECTOR_SIZE :
          *(WORD * )buff = 4096;
        break;
        /* 同时擦除扇区个数 */
        case GET_BLOCK_SIZE :
          *(DWORD * )buff = 1;
        break;        
      }
      status = RES_OK;
		break;
    
		default:
			status = RES_PARERR;
	}
	return status;
}
#endif

二 、FatFs 功能配置


ffconf.h 文件是FatFs 功能配置文件,我们可以对文件内容进行修改,使得FatFs 更符合
我们的要求。ffconf.h 对每个配置选项都做了详细的使用情况说明。下面只列出修改的配置,
其他配置采用默认即可。

1 #define _USE_MKFS 1
2 #define _CODE_PAGE 936
3 #define _USE_LFN 2
4 #define _VOLUMES 2
5 #define _MIN_SS 512
6 #define _MAX_SS 4096

1) _USE_MKFS:格式化功能选择,为使用FatFs 格式化功能,需要把它设置为1。
2) _CODE_PAGE:语言功能选择,并要求把相关语言文件添加到工程宏。为支持简
体中文文件名需要使用“936”,正如在图 26-7 的操作,我们已经把cc936.c 文件
添加到工程中。
3) _USE_LFN:长文件名支持,默认不支持长文件名,这里配置为2,支持长文件名,
并指定使用栈空间为缓冲区。
4) _VOLUMES:指定物理设备数量,这里设置为2,包括预留SD 卡和SPI Flash 芯
片。
5) _MIN_SS 、_MAX_SS:指定扇区大小的最小值和最大值。SD 卡扇区大小一般都
为512 字节,SPI Flash 芯片扇区大小一般设置为4096 字节,所以需要把_MAX_SS
改为4096。

三、FatFs 功能测试

移植操作到此,就已经把FatFs 全部添加到我们的工程了,这时我们编译功能,顺利编
译通过,没有错误。接下来,我们就可以使用编写图 26-5 中用户应用程序了。
主要的测试包括格式化测试、文件写入测试和文件读取测试三个部分,主要程序都在
main.c 文件中实现。

 ******************************************************************************
  */

#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "ff.h"
#include "string.h"
/**
  ******************************************************************************
  *                              定义变量
  ******************************************************************************
  */
FATFS fs;													/* FatFs文件系统对象 */
FIL fnew;													/* 文件对象 */
FRESULT res_flash;                /* 文件操作结果 */
UINT fnum;            					  /* 文件成功读写数量 */
char fpath[100];                  /* 保存当前扫描路径 */
char readbuffer[512];             
 
/**
  ******************************************************************************
  *                                任务函数
  ******************************************************************************
  */
/* FatFs多项功能测试 */
static FRESULT miscellaneous(void)
{
  DIR dir;
  FATFS *pfs;
  DWORD fre_clust, fre_sect, tot_sect;
  
  printf("\n*************** 设备信息获取 ***************\r\n");
  /* 获取设备信息和空簇大小 */
  res_flash = f_getfree("1:", &fre_clust, &pfs);

  /* 计算得到总的扇区个数和空扇区个数 */
  tot_sect = (pfs->n_fatent - 2) * pfs->csize;
  fre_sect = fre_clust * pfs->csize;

  /* 打印信息(4096 字节/扇区 1个扇区为4KB) */
  printf("》设备总空间:%10lu KB。\n》可用空间:  %10lu KB。\n", tot_sect *4, fre_sect *4);
  
  printf("\n******** 文件定位和格式化写入功能测试 ********\r\n");
  res_flash = f_open(&fnew, "1:FatFs读写测试文件.txt",
                            FA_OPEN_ALWAYS|FA_WRITE|FA_READ );
	if ( res_flash == FR_OK )
	{
    /*  文件定位 */
    res_flash = f_lseek(&fnew,f_size(&fnew));
    if (res_flash == FR_OK)
    {
      /* 格式化写入,参数格式类似printf函数 */
      f_printf(&fnew,"\n在原来文件新添加一行内容\n");
      f_printf(&fnew,"》设备总空间:%10lu KB。\n》可用空间:  %10lu KB。\n", tot_sect *4, fre_sect *4);
      /*  文件定位到文件起始位置 */
      res_flash = f_lseek(&fnew,0);
      /* 读取文件所有内容到缓存区 */
      res_flash = f_read(&fnew,readbuffer,f_size(&fnew),&fnum);
      if(res_flash == FR_OK)
      {
        printf("》文件内容:\n%s\n",readbuffer);
      }
    }
    f_close(&fnew);    
    
    printf("\n********** 目录创建和重命名功能测试 **********\r\n");
    /* 尝试打开目录 */
    res_flash=f_opendir(&dir,"1:TestDir");
    if(res_flash!=FR_OK)
    {
      /* 打开目录失败,就创建目录 */
      res_flash=f_mkdir("1:TestDir");
    }
    else
    {
      /* 如果目录已经存在,关闭它 */
      res_flash=f_closedir(&dir);
      /* 删除文件 */
      f_unlink("1:TestDir/testdir.txt");
    }
    if(res_flash==FR_OK)
    {
      /* 重命名并移动文件 */
      res_flash=f_rename("1:FatFs读写测试文件.txt","1:TestDir/testdir.txt");      
    } 
	}
  else
  {
    printf("!! 打开文件失败:%d\n",res_flash);
    printf("!! 或许需要再次运行“FatFs移植与读写测试”工程\n");
  }
  return res_flash;
}

  FILINFO fno;
/**
  * 文件信息获取
  */
static FRESULT file_check(void)
{

  
  /* 获取文件信息 */
  res_flash=f_stat("1:TestDir/testdir.txt",&fno);
  if(res_flash==FR_OK)
  {
    printf("“testdir.txt”文件信息:\n");
    printf("》文件大小: %ld(字节)\n", fno.fsize);
    printf("》时间戳: %u/%02u/%02u, %02u:%02u\n",
           (fno.fdate >> 9) + 1980, fno.fdate >> 5 & 15, fno.fdate & 31,fno.ftime >> 11, fno.ftime >> 5 & 63);
    printf("》属性: %c%c%c%c%c\n\n",
           (fno.fattrib & AM_DIR) ? 'D' : '-',      // 是一个目录
           (fno.fattrib & AM_RDO) ? 'R' : '-',      // 只读文件
           (fno.fattrib & AM_HID) ? 'H' : '-',      // 隐藏文件
           (fno.fattrib & AM_SYS) ? 'S' : '-',      // 系统文件
           (fno.fattrib & AM_ARC) ? 'A' : '-');     // 档案文件
  }
  return res_flash;
}

/**
  * @brief  scan_files 递归扫描FatFs内的文件
  * @param  path:初始扫描路径
  * @retval result:文件系统的返回值
  */
static FRESULT scan_files (char* path) 
{ 
  FRESULT res; 		//部分在递归过程被修改的变量,不用全局变量	
  FILINFO fno; 
  DIR dir; 
  int i;            
  char *fn;        // 文件名	
	
#if _USE_LFN 
  /* 长文件名支持 */
  /* 简体中文需要2个字节保存一个“字”*/
  static char lfn[_MAX_LFN*2 + 1]; 	
  fno.lfname = lfn; 
  fno.lfsize = sizeof(lfn); 
#endif 
  //打开目录
  res = f_opendir(&dir, path); 
  if (res == FR_OK) 
	{ 
    i = strlen(path); 
    for (;;) 
		{ 
      //读取目录下的内容,再读会自动读下一个文件
      res = f_readdir(&dir, &fno); 								
      //为空时表示所有项目读取完毕,跳出
      if (res != FR_OK || fno.fname[0] == 0) break; 	
#if _USE_LFN 
      fn = *fno.lfname ? fno.lfname : fno.fname; 
#else 
      fn = fno.fname; 
#endif 
      //点表示当前目录,跳过			
      if (*fn == '.') continue; 	
      //目录,递归读取      
      if (fno.fattrib & AM_DIR)         
			{ 			
        //合成完整目录名        
        sprintf(&path[i], "/%s", fn); 		
        //递归遍历         
        res = scan_files(path);	
        path[i] = 0;         
        //打开失败,跳出循环        
        if (res != FR_OK) 
					break; 
      } 
			else 
			{ 
				printf("%s/%s\r\n", path, fn);								//输出文件名	
        /* 可以在这里提取特定格式的文件路径 */        
      }//else
    } //for
  } 
  return res; 
}
/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{    	
	/* 初始化调试串口,一般为串口1 */
	USART_Config();	
  printf("******** 这是一个SPI FLASH 文件系统实验 *******\r\n");
  
	//在外部SPI Flash挂载文件系统,文件系统挂载时会对SPI设备初始化
	res_flash = f_mount(&fs,"1:",1);
  if(res_flash!=FR_OK)
  {
    printf("!!外部Flash挂载文件系统失败。(%d)\r\n",res_flash);
    printf("!!可能原因:SPI Flash初始化不成功。\r\n");
		while(1);
  }
  else
  {
    printf("》文件系统挂载成功,可以进行测试\r\n");    
  }
  
  /* FatFs多项功能测试 */
  res_flash = miscellaneous();

  
  printf("\n*************** 文件信息获取测试 **************\r\n");
  res_flash = file_check();

  
  printf("***************** 文件扫描测试 ****************\r\n");
  strcpy(fpath,"1:");
  scan_files(fpath);
  
  
	/* 不再使用文件系统,取消挂载文件系统 */
	f_mount(NULL,"1:",1);
  
  /* 操作完成,停机 */
	while(1)
	{
	}
}

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

企业内训系统源码开发实战:搭建实践与经验分享

本篇文章中&#xff0c;小编将带领读者深入探讨企业内训系统的源码开发实战&#xff0c;分享在搭建过程中遇到的挑战与解决方案。 一、项目规划与需求分析 通过对企业内训需求的深入了解&#xff0c;我们可以更好地定义系统架构和数据库设计。 二、技术栈选择 在内训系统开发…

2024年MySQL学习指南(三),探索MySQL数据库,掌握未来数据管理趋势

文章目录 前言7. DML- 增删改数据7.1 添加数据7.2 修改数据7.3 删除数据 8. DQL- 数据的查询操作8.1 基础查询1. 基础查询语法2. 基础查询练习 8.2 条件查询1. 条件查询语法2. 条件查询练习 8.3 排序查询1. 排序查询语法2. 排序查询练习 8.4 聚合函数1. 聚合函数语法2.聚合函数…

部署node.js+express+mongodb(更新中)

1-Linux服务器部署MongoDB 1.升级 yum -y update 2.下载MongoDB安装包 3.上传安装包 上传目录 &#xff1a; /usr/local/ 2-配置MongoDB环境变量并启动 1.配置环境变量全局启动 vi ~/.bash_profile 使用i命令进入编辑模式 添加: export PATH/usr/local/mongodb/bin:$P…

centos 8.0 安装sysbench 1.0.17

序号步骤说明执行命令执行结果备注1 下载并解压sysbench-1.0.17.zip sysbench-1.0.17.zip2安装依赖文件 yum install automake libtool -y yum install /usr/include/libpq-fe.h 3安装sysbench cd sysbench-1.0.17 ./autogen.sh ./configure \ --prefix/sysbench \ --with-pgsq…

Javaweb之Mybatis的基础操作之删除的详细解析

1.3 删除 1.3.1 功能实现 页面原型&#xff1a; 当我们点击后面的"删除"按钮时&#xff0c;前端页面会给服务端传递一个参数&#xff0c;也就是该行数据的ID。 我们接收到ID后&#xff0c;根据ID删除数据即可。 功能&#xff1a;根据主键删除数据 SQL语句 -- 删除…

C语言中关于strcpy函数的理解

strcpy的功能是将源指向的字符串复制到另外一个字符串中 目标指向的数组的大小应该要足够长&#xff0c;避免让源字符串中的数据溢出 关于这个函数的具体用法&#xff0c;我们可以看看下面这个程序 注意&#xff1a;strcpy函数的头文件是<string.h>&#xff0c;我们在用…

【科研绘图】Origin科研绘图超快速上手指南

Origin教程 Part 1:Origin界面介绍项目管理器graph文件工具栏文字工具箭头工具&#xff0c;直线工具 菜单栏文件新建导出 图图表绘制 Part 2:绘图实例讲解1.创建工程2.导入数据到book3.创建空Graph&#xff0c;设置画布尺寸4. 添加坐标系&#xff0c;设置坐标系的位置与尺寸5.添…

教师技能干货:如何快速发布期末考试成绩

期末考试结束&#xff0c;随之而来的是成绩发布。对于教师而言&#xff0c;这是一项既重要又繁琐的工作。成绩的发布不仅是对学生一学期努力的肯定&#xff0c;也是对学生未来学习的指引。那么&#xff0c;如何快速、准确地发布期末考试成绩呢&#xff1f;下面将为您分享一些实…

Java-replaceAll()同时替换多个字符

今天复现了raplaceAll&#xff08;&#xff09;的用法&#xff0c;但是通常都是对一种字符进行替换&#xff0c;我就在想有没有操作可以一次性替换多个不同的字符&#xff0c;百度一搜&#xff0c;果然有。具体情况如下 首先是替换字的 String str1 "小明&#xff0c;小…

Win32 TEXT()宏学习

之前学习了_T()宏&#xff1b; _T()是MFC的&#xff1b; TEXT()是win32的&#xff1b; _T("")定义于tchar.h&#xff1b; TEXT宏是windows程序设计中经常遇到的宏&#xff0c;定义在 <winnt.h>中&#xff1b; 如果使用UNICODE字符集&#xff0c;则TEXT&…

02-微服务-Eureka注册中心

Eureka注册中心 假如我们的服务提供者user-service部署了多个实例&#xff0c;如图&#xff1a; 大家思考几个问题&#xff1a; order-service在发起远程调用的时候&#xff0c;该如何得知user-service实例的ip地址和端口&#xff1f;有多个user-service实例地址&#xff0c;…

什么是差值表达式

在Vue.js中&#xff0c;差值表达式是一种基本的数据绑定形式&#xff0c;用于将数据绑定到文档对象模型&#xff08;DOM&#xff09;上。差值表达式通常使用双大括号 {{ }} 来表示&#xff0c;这种语法非常直观。当Vue实例的数据发生变化时&#xff0c;差值表达式的内容也会相应…

【源码分析】 Calcite 处理流程详解:calcite架构、处理流程以及就一个运行示例进行源码分析

文章目录 一. Calcite整体架构二. Calcite处理流程三. 处理流程样例说明1. 样例demo1.1. 样例数据1.2. 使用calcite 2. 流程源码分析Step1: SQL 解析阶段&#xff08;SQL–>SqlNode&#xff09;Step2: SqlNode 验证&#xff08;SqlNode–>SqlNode&#xff09;1. 注册元数…

入行IC,该如何规划学习和成长路线?

不同学历背景的同学会有不同的道路选择。 微电子/集成电路专业的科班生&#xff0c;已经拥有了理论知识基础&#xff0c;不需要再额外学习这一部分。所以精力主要聚焦在流片项目和集创赛一类的赛事上&#xff0c;重点在于如何拿到更好的Offer。 而电子大类以及其他相关专业的…

IOC解决程序耦合

1.什么是IOC IOC (Inverse of Control)即控制反转&#xff1a;由ioc容器来创建依赖对象&#xff0c;程序只需要从IOC容器获取创建好的对象。 我们在获取对象时&#xff0c;都是采用new的方式。是主动的。 我们获取对象时&#xff0c;同时跟工厂要&#xff0c;有工厂为我们查找…

对话惠买集团董事长兼CEO杜瑞勇:直播电商粗放时代结束,如何用AI+XR打造精细化的智慧直播生态?

“ 未来将是专业选手精细化运营的智慧直播时代。“ 整理 | 梦婕 编辑 | 渔舟 出品&#xff5c;极新&#xff06;北京电子商务协会 直播电商在经过爆发式增长后&#xff0c;从业者不断涌入&#xff0c;竞争日趋激烈&#xff0c;行业发展必然将会进入到一个缓慢增长阶段。直播…

实现vue加载指令 v-loading

文章目录 为什么使用指令实现 loading具体实现封装准备实现 loading 效果loading 显示与隐藏使用修饰符扩展 完整代码与结语 本文不会详细的说明 vue 中指令这些知识点&#xff0c;如果存在疑问&#xff0c;请自行查阅文档或者其他资料 为什么使用指令实现 loading 在日常的开…

基于SSM的班级事务管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

未来已来,Ai原生应用与人高度结合!学习就在现在?

原生应用&#xff1a;OpenAI™ChatGPT、Baidu.Inc™文心一言 也可以体验CSDN的INSCODE AI&#xff0c;集成多个国内GPT内容。 文章目录 前言----编程语言的未来&#xff1f;一、编程语言的教育1.1 学校所见所闻1.2 开启我们的Ai行程~io&#xff01;1.3 Ai结果评论 二、Ai编程教…

生成式AI:软件工程的未来伙伴

随着技术不断进步&#xff0c;软件工程正在经历一场革命性的变革。从最初的穿孔卡片和汇编语言编程&#xff0c;到现代集成开发环境和高级编程语言&#xff0c;软件工程已经走过了一条漫长的路。现在&#xff0c;生成式人工智能(AI)正打开新的篇章&#xff0c;不仅对传统的编码…
最新文章