14.Nor-Flash操作实例
目录
1.基础知识
2.使用u-boot体验Nor Flash的操作
3.编写NOR-Flash测试程序
源代码
数据手册
1.基础知识
1).Nor Flash 和Nand Flash 的区别?
NOR FLASH | NAND FLASH | |
---|---|---|
结构 | NORflash采用内存的随机读取技术。各单元之间是并联的,对存储单元进行统一编址,所以可以随机访问任意一个字,应用程序可直接在flash内运行,而无需先拷贝到RAM。 | NANDflash数据线和地址线共用I/O线,需额外联接一些控制的输入输出 |
读写速度 | NOR flash有更快的读取速度 | NAND flash有更快的写、擦除速度 |
可靠性 | NOR的擦写次数是10万次 |
NAND的擦写次数是100万次 (NAND器件的坏块是随机分布的) |
成本和容量 | 在面积和工艺相同的情况下,NAND的容量比NOR大的多,成本更低 | |
优缺点 | 无位翻转,无坏块,稳定(存储关键性的程序) | 位反转,有坏块 |
易用性 | NOR flash有专用的地址引脚来寻址,较容易和其他芯片联接,还支持本地执行 | NAND flash的IO端口采用复用的数据线和地址线,必须先通过寄存器串行地进行数据存取。各厂商对信号的定义不同,增加了应用的难度 |
编程 |
NOR flash采用统一编址(有独立地址线),可随机读取每个“字”,但NOR flash不能像RAM以字节改写数据,只能按“页”写,故NOR flash不能代替RAM。擦除既可整页擦除,也可整块擦除 注意: flash进行写操作时,只能将相应的位由1变0,而擦除才能把块内所有位由0变1。所有写入数据时,如果该页已经存在数据,必须先擦除再写。 |
NAND flash共用地址线和数据线,页是读写数据的最小单元,块是擦除数据的最小单元 |
NOR FLASH 的特点是:
可以像内存一样的读取,但是不能直接写。
例子: 在Nor Flash中有以下指令:
mov R0,#0 --R0赋值为0
LDR R1 ,[R0] --读取地址R0的值到寄存器R1
STR R1 ,[R0] --把R1的值写入R0寄存器
当执行STR R1 ,[R0] 不会成功,被视为无效操作。
这样子如果程序烧写在NOR FLASH 中会出现什么问题呢?
程序中含有需要更改的全局变量/静态变量(变量存储在栈中),但是如果现在bin文件烧写到NOR FLASH 上,那么意味着不能修改变量的值了,程序就会达不到我们预期的效果。所以如果想要的到想要的结果,就需要把这些全局变量/静态变量,重定位放到SDRAM(可读可写)中。
2).以S3C2440为例,设为NOR Flash 或 Nand Flash 启动时,启动地址的差别
- .基本框架
S3C2440是一个SOC,在一块芯片上面集成了有CPU、GPIO控制器、Nand控制器、Nor控制器、以及4K的SRAM。
- 启动过程(大多数ARM芯片从0地址启动)
1.NoR启动,NoR Flash 基地址为0(片内RAM地址为:0x40000000),CPU读出NOR读出上的第一个指令(前四个字节)执行,CPU继续读出其他指令执行(CPU可以在Nor Flash取指令直接执行)。
2.Nand启动,片内4K SRAM 基地之为0(Nor Falsh 不可访问),硬件2240把NAND前4K内容复制到片内内存SRAM中,然后CPU从0地址取出第一条指令(前四个字节)执行。
3).不同位宽内存设备之间的连接
内存控制器地址线和片外内存设备的接法:
可以发现他们的接法好像都是不同的,他们的规律是什么?
这时需要去查看一下芯片手册。
8-bit ROM
16-bit ROM
32-bit ROM
规律:那么就是说外接芯片的位宽有变化,那地址线的接法也有变化。
大致如下简图所示:
那为什么是这样呢?需要了解数据内部的保存结构,简图如下:
假如现在执行指令:
mov R0 ,#3 --把3的数值赋值给R0
LDRB R1, [R0] --读取地址为3的位置读取1个字节的数据
那么CPU就会把地址3发出去,也就是:0x00000011 ,那么此时地址线 A0 =1, A1 =1 ,其他(A2-A27)为0.
- 如果外界是8-bit ROM,因为A0接A0,A1连接A1,此时他收到的就是0x3
- 如果外界是16-bit ROM,因为A1接A0,A2连接A1,此时他收到的就是0x1
- 如果外界是32-bit ROM,因为A2接A0,A3连接A1,此时他收到的就是0x0
我们的任务是读取第3byte的数据:
当为8-bit ROM,那我收到的正好也是0x3这个数值,没有问题。
当为16-bit ROM,我收到的是0x1,这个数值,也就是十进制的1,读取地址编号为1的地址的值,很巧,发现我们需要第3字节的数据刚好在地址1的位置,但是这个位置有两个字节啊,怎么办?CPU不用管,它只需要发出地址就行,所以这也是内存控制器做的事,内存控制器根据收到的CPU发送的 A0 = 1 ,那么读取的就是地址编号为1,右边的那个字节(第3字节)的数据。
当为32-bit ROM,我收到的是0x0,这个数值,也就是十进制的0,读取地址编号为0的地址的值,同样,发现我们需要第3字节的数据刚好在地址0的位置,但是这个位置有四个字节啊,怎么办?CPU不用管,它只需要发出地址就行,所以这也是内存控制器做的事,内存控制器根据收到的 [A1:A0] = 11 ,那么读取的就是地址编号为0,最右边的那个字节(第3字节)的数据。
这个过程可以使用一张图来表示,就可以简单明了。
再举个例子:
假如现在执行指令:
mov R0 ,#4 --把4的数值赋值给R0
LDR R1, [R0] --读取地址为43的位置读取4个字节的数据
那他的过程可以简化为下表:
所以CPU就是一个大BOSS,它只负责发出指令(地址)给内存控制器,而关于你数据是如何拆分和组装的,CPU并不关心,我只需要发出指令,然后就收数据就好了,那剩下的事情就是手下(内存控制器)做的,它负责数据的组装和拆分,最终把正确的结果返回给CPU。
2.使用u-boot体验Nor Flash的操作
例子2:读数据
烧写u-boot,到Nor Flash 上,开发版设为Nor Flash启动、
使用OpenJTAG:输入命令读取:md.b 0 读取Nor Flash 0地址的数据:
结果如下:
查看一下uboot.bin文件的数据和读取出来是一样:
说明Nor Flash可以直接读取数据。
例子2:读取ID
查看Nor Flash的数据手册,在此开发版使用的芯片型号是:MX29LV160DBTI
步骤:
①往地址 0x555写入数据0xAA
②往地址 0x2AA写入数据0x55
③往地址 0x555写入数据0x90
④读取地址0x00得到厂家ID:0xC2
⑤读取地址0x01得到设备ID:MX29LV160DT: 22C4; MX29LV160DB: 2249
注意:设备位宽连接的问题,因为NOR Flash连接的是16位的,所以连接的简图如下
因此如果CPU需要往NOR Flash的0x555的写入数据0xAA,那么需要在2440发送地址的时候需要把0x555左移一位,再发送给Nor Flash才是正确的地址。
那么此时UBOOT怎么操作呢?
如果CPU需要左移一位,才是正确的地址,也就是是说,发送的地址需要乘上2,如下:
步骤:
①往地址 0xAAA写入数据0xAA (mw.w aaa aa)
②往地址 0x554写入数据0x55 (mw.w 554 55)
③往地址 0xAAA写入数据0x90 (mw.w aaa 90)
④读取地址0x00得到厂家ID:0xC2 (md.w 0 1)
⑤读取地址0x02得到设备ID:MX29LV160DT: 22C4; MX29LV160DB: 2249 ( md.w 2 1)
结果如下:
如何退出读ID状态?
往任意地址写入:0xF0
结果如下:
例子3:读取CFI信息
查看芯片手册的描述:
进入CFI(common flash interface)模式:
往地址0x55 写入 0x98 进入CFI模式
查询芯片容量:
从0x10 读取一个字节数据得到0x51(Q)
从0x11 读取一个字节数据得到0x51(R)
从0x12 读取一个字节数据得到0x51(Y)
从0x27 读取一个字节数据得到内存大小。
由于设备位宽不同,所以在OpenJTAG的操作是:
往地址0xAA 写入 0x98 进入CFI模式 (mw.w aa 98)
从0x20 读取一个字节数据得到0x51(Q) (md.w 20 1)
从0x22读取一个字节数据得到0x51(R) (md.w 22 1)
从0x24 读取一个字节数据得到0x51(Y) (md.w 24 1)
从0x4E 读取一个字节数据得到内存大小。(md.w 4e 1)
结果如下:
退出CFI模式,往任意地址写0xf0
例子4:写数据
试一下在地址1M以外的地方写入数据0x1234,然后读出来
那如何写数据呢?需要一定的格式,如下手册所描述:
步骤:
①往地址 0x555写入数据0xAA
②往地址 0x2AA写入数据0x55
③往地址 0x555写入数据0xA0
④往指定Addr写Data
那么此时UBOOT怎么操作呢?
如果CPU需要左移一位,才是正确的地址,也就是是说,发送的地址需要乘上2,如下:
步骤:
①往地址 0xAAA写入数据0xAA (mw.w aaa aa)
②往地址 0x554写入数据0x55 (mw.w 554 55)
③往地址 0xAAA写入数据0xA0 (mw.w aaa A0)
④往地址 0x100000 写入数据 0x1234 (mw.w 100000 1234)
⑤读取地址0x100000的数据是否写入成功 (md.w 100000 1)
结果如下:
例子5:当原来的数据不是全f的时候
解锁后能写入成功的前提,必须是这个位置的数据时全f,也就是:ffff
再次往0x100000这个地址 ,写入一个新数据,是否能成功?
那如何写呢?如果原来的数据不是全f,那么需要先对这个位置进行擦除操作
芯片数据手册的描述如下:
擦除扇区0x100000数据的步骤步骤:
①往地址 0x555写入数据0xAA
②往地址 0x2AA写入数据0x55
③往地址 0x555写入数据0x80
④往地址 0x555写入数据0xAA
⑤往地址 0x2AA写入数据0x55
⑥往扇区0x100000写0x30
那么此时UBOOT怎么操作呢?
如果CPU需要左移一位,才是正确的地址,也就是是说,发送的地址需要乘上2,如下:
步骤:
①往地址 0xAAA写入数据0xAA (mw.w aaa aa)
②往地址 0x554写入数据0x55 (mw.w 554 55)
③往地址 0xAAA写入数据0x80 (mw.w aaa 80)
④往地址 0xAAA写入数据0xAA (mw.w aaa aa)
⑤往地址 0x554写入数据0x55 (mw.w 554 55)
④往地址 0x100000 写入数据 0x30 (mw.w 100000 30)
如下:
擦除成功后就可以正常的写数据了,和上面写的步骤是一样的。
3.编写NOR-Flash测试程序
在这个测试例程中有这几个功能如下:
/*菜单选项
*1.识别nor_falsh,设备和容量
*2.读取某个地址的数据
*3.擦除nor_flash扇区数据
*4.往某个地址写数据
*/
1).识别nor_falsh打印出各个扇区的起始地址,读取设备ID和厂家ID以及设备容量
由数据手册可知,需要查询设备容量,厂家ID和设备ID之前,需要进入CFI模式
那么进入CFI模式的方式如下所描述:往0x55的地址写入0x98
退出CFI模式,如下所描述:往任意地址写0xF0
进入CFI模式之后,可以查询的信息如下描述:
读取设备容量:读取地址0x27可以得到设备容量
在CFI模式下,可以查询 erase region的有关信息:
其中region的描述需要参考:CFI publication 100 规范,如下:
代码如下:
/*进入NOR_FLASH的CFI模式,读取设备信息*/
void Scan_nor_flash(void)
{char qry[4]; //存储读取CFI模式下的QRYint Manifacture_ID,Devide_ID;int n,size;int regions; //NOR_Flash的region个数int i,j,count=0;/*变量含义:* 1.region的起始地址 2.block的个数* 3.每个block的大小 4.block的起始扇区基地址*/int region_Bank_Area,blocks,block_size,block_base_addr;/*读取QRY字符到数组qry*/nor_cmd(0x55,0x98);/*进入CFI模式,往0x55写0x98*/qry[0] = nor_read(0x10);qry[1] = nor_read(0x11);qry[2] = nor_read(0x12);qry[3] = '\0';printf("******************msg = %s\n\r" ,qry); //打印出QRYnor_cmd(0,0xf0); //复位,退出CFI模式/*打印nor_flash的厂家ID,设备ID*/nor_cmd(0x555,0xaa);nor_cmd(0x2AA,0x55); //解锁nor_cmd(0x555,0x90); //读取厂家ID命令Manifacture_ID = nor_read(0x00); //读取厂家IDDevide_ID = nor_read(0x01); //读取设备IDprintf("******************The Manifacture_ID is: 0x%x\r\n",Manifacture_ID);printf("******************The Devide_ID is: 0x%x\r\n",Devide_ID);nor_cmd(0,0xf0); //复位/*打印设备容量*/nor_cmd(0x55,0x98);/*进入CFI模式,往0x55写0x98*/n = nor_read(0x27);size = 1<<n; //表示 2^nprintf("******************Device size:0x%x = %d bytes = %d M \r\n",size,size,size/(1024*1024));/*打印各个扇区的起始地址*/regions = nor_read(0x2c); //从0x2c的地址读出region个数region_Bank_Area =0x2d;block_base_addr=0; printf("Block/Sector start Address:\r\n");for(i=0;i<regions;i++){/*读出这个region总共有多少个block*/blocks=nor_read(region_Bank_Area)+(nor_read(region_Bank_Area+1)<<8)+1;/*读取每个block的大小*/block_size=(nor_read(region_Bank_Area+2)+(nor_read(region_Bank_Area+3)<<8))*256;printf("================Region %d==============\n\r",i+1);printf("number_of_blocks=%d, block_size=0x%x=%dk\n\r",blocks,block_size,block_size/1024);/*打印每个block的起始地址*/for(j=0;j<blocks;j++){puthex(block_base_addr);printf("\t");block_base_addr +=block_size;count++;if(count % 5 == 0){printf("\r\n");}}printf("\n\r");/*region地址自加4读取下一个region的信息*/region_Bank_Area +=4; }nor_cmd(0,0xf0); //复位,退出CFI模式printf("\n\r");
}
注意事项:进入CFI模式之后,退出函数时需要退出CFI模式,才能正常访问NOR_FALSH。
程序运行结果如下:
注意事项:
编译程序加上选项:-march=armv4 ,
否则像
volatile unsigned short *p =xxx;
*p=data的操作会被分成两个strb步骤(我们需要的是strh),最后导致读取CFI设备ID和厂家ID的时候出错。
2).读取nor_flash某个地址的数据
首先从键盘输入要读取的起始地址,接着输入读取的字节,为了方便起见,读取的字节数是16的整数倍。
代码如下:
unsigned short Read_nor_flash(void)
{//读取的基地址unsigned int addr;//定义一个无符号字符型变量pvolatile unsigned char *p;int i,j;unsigned char c;unsigned short amount,hex_addr=0;/*保存数据*/unsigned char str[16];/*获取读取地址*/printf("Enter Read Address: ");/*根据用户输入的地址,结果给回addr*可输入16进制和10进制*/addr = get_uint();/*把addr强制转换成unsigned char 类型,表明*p只读取一个字节的数据*/p = (volatile unsigned char *)addr;printf("Enter Read amount(16 times): ");amount = get_uint();printf("Read Data:\n\r");printf(" 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n\r");/*读取长度:64字节*/for(i=0;i<amount;i++){ printf("0x%08x ",hex_addr);/*每行打印16字节数据*/for(j=0;j<16;j++){/*先打印16进制*/c = *p++; //读取第一个字节的数据,然后p指向下一个字节str[j] = c; //先保存数值printf("%02x ",c); //打印出当前字节的16进制}printf(" ; ");for(j=0;j<16;j++){/*打印对应的字符*/if(str[j]<0x20 || str[j]>0x7e) /*不可视字符,打印出一个点*/{putchar('.');}elseputchar(str[j]); //可视字符,直接打印}hex_addr+=16;printf("\n\r");}
}
加入我们现在需要读取的是从基地址(0地址)开始的160字节的数据,那么从键盘输入的地址就是0,读取数量就是10,结果如下:
我们读取的nor_flash上前160字节的数据,对比一下nor_flash.bin文件的数据是否一致:
可以看出来结果完全一致,说明读取nor_flash的数据时成功的。
注意:
ascii的可打印字符:ASCII字符集由95个可打印字符(0x20-0x7E)
3).擦除nor_flash扇区数据
查看数据手册中如何擦除数据:
代码如下:
void Erase_nor_flash(void)
{//擦除的地址unsigned int addr;/*从键盘获取删除地址*/printf("Enter Erase Address: ");addr = get_uint();printf("erasing ... ");nor_cmd(0x555,0xaa); /*解锁*/nor_cmd(0x2aa,0x55);/*注意此处擦除的是一整个扇区,擦除的最小单位就是*一个扇区的大小,此处总共有35个扇区*/nor_cmd(0x555,0x80); /*擦除扇区*/nor_cmd(0x555,0xaa); /*解锁*/nor_cmd(0x2aa,0x55);/*因为nor_Flash是16bit的,所以发送地址,需要右移一位*/nor_cmd(addr>>1,0x30);wait_ready(addr); /*等待擦除完成*/printf("Erase finished!\n\r");
}
4)往某个地址写数据
查看数据手册如何写数据:
需要注意一个点,写入的数据是16位的,也就是两个字节,需要一次性写入一个字节,所以在写入之前需要对数据进行整合。
如何判断烧写完成,以便于进行下一次的烧写工作:
代码如下:
void Write_nor_flash(void)
{//写数据的地址unsigned int addr;unsigned char write_data[100];int i=0,j=1;unsigned int data;/*从键盘获取写数据起始地址*/printf("Enter Write Address: ");addr = get_uint();printf("Enter Write data: ");gets(write_data);printf("writing... ");/*把write_data的数组构造16bit的数据*//*如果数组有数据*/while(write_data[i] && write_data[j]) {//构造一个16bit的数据data = write_data[i]+ (write_data[j]<<8);/*写入数据*/nor_cmd(0x555,0xaa); /*解锁*/nor_cmd(0x2aa,0x55);/*注意只有当数据为f时才能直接些,否则必须先擦除*/nor_cmd(0x555,0xa0); /*写命令*//*往地址写数据*/nor_cmd(addr>>1,data);/*等待烧写完成:读数据Q6无变化则烧写完成*/wait_ready(addr);i +=2;j +=2;addr +=2;}/*IF write_data[i]!=0 write_data[j]=0* 说明还有数据,此时:* data = write_data[i]+ (write_data[j]<<8);*//*IF write_data[i]==0 write_data[j]!=0* 说明已经结束了,0是结束符‘\0’* data = write_data[i]+ (0<<8); 此时data =0*//*IF write_data[i]==0 write_data[j]==0* 说明已经结束了,0是结束符‘\0’* data = write_data[i]+ (0<<8); 此时data =0*//*已上三种情况都需要再写一个数据*为了方便和保险起见,无论是三种的哪一种*都让 data = write_data[i]; 把结束符写进去*///构造一个16bit的数据data = write_data[i];/*写入数据*/nor_cmd(0x555,0xaa); /*解锁*/nor_cmd(0x2aa,0x55);/*注意只有当数据为f时才能直接些,否则必须先擦除*/nor_cmd(0x555,0xa0); /*写命令*//*往地址写数据*/nor_cmd(addr>>1,data);/*等待烧写完成:读数据Q6无变化则烧写完成*/wait_ready(addr);printf("Write finished!\n\r");
}
此处注意还需要加一个判断数据是否写完成的函数,当一次行写入16bit时,等待写入完成再写下一个16bit,依次类推:
函数如下:
void wait_ready(unsigned int addr)
{unsigned int pre_val;unsigned int current_val;pre_val = nor_read(addr>>1); //先读取一次current_val= nor_read(addr>>1); //再次读取/*两次读取的结果不一致,说明数据还在变化,继续等待*/while((pre_val&(1<<6)) != (current_val&(1<<6))){pre_val=current_val; //当前的值等于上一次的值/*再次读取:Q6 位*/current_val = nor_read(addr>>1);}}
上面的代码已经完成了所有功能了,接下来就是写数据进行测试了。
通过上面的例子已经知道,这个NOR_flash的大小是2M,共有4个region,而且每一个region的block数量以及block的大小是不同的。如下所示:其中地址是每个block的起始地址
注意:在写数据时,只有当数据为全f时,才能写入,因为规定,数据的bit只能从1变成0,而不能从0变成1,所以当数据不为全f时,需要对擦除对应的block,而且每次擦除的最小单位是block,比如,擦除region1的block,那么一次性擦除16k的数据,擦除region2的block,一次性擦除8k的数据。
现在读取地址:0x001D0000 开始,160 byte的数据,如下:
直接写入,写入数据:hello world !
往地址:0x001Daaaa 的位置写入,hello yuan (也就是在这个block的末尾的位置)
现在擦除地址:0x001D0000的数据,查看数据是否还在:
这也证明了,擦除操作是针对一个扇区。
源代码
地址:https://download.csdn.net/download/qq_36243942/10940801
数据手册
地址:https://download.csdn.net/download/qq_36243942/10941195
14.Nor-Flash操作实例相关推荐
- 我的docker随笔14:MySQL操作实例
本文使用docker运行MySQL,并进行简单的操作. 本文使用的MySQL为官方镜像,版本为5.7.下载镜像命令: docker pull mysql:5.7 使用下面的命令运行容器,并设置root ...
- 初中计算机flash操作,初中信息技术FLASH基础知识
<初中信息技术FLASH基础知识>由会员分享,可在线阅读,更多相关<初中信息技术FLASH基础知识(26页珍藏版)>请在人人文库网上搜索. 1.FLASH 第一课,一.Flas ...
- c 获取当前时间插入oracle数据库,Oracle如何获取系统当前时间等操作实例,c++获取系统时间...
Oracle如何获取系统当前时间等操作实例,c++获取系统时间 获取系统当前时间 date类型的 select sysdate from dual; char类型的 select to_char(sy ...
- legend3---lavarel多对多模型操作实例
legend3---lavarel多对多模型操作实例 一.总结 一句话总结: 在多对多模型中,增加关系表的数据 需要 弄一个和关系表一对多的模型关系 1.在lavarel关系模型中,课程和标签表是多对 ...
- 后盾网lavarel视频项目---lavarel多表关联一对多操作实例
后盾网lavarel视频项目---lavarel多表关联一对多操作实例 一.总结 一句话总结: 1.一对多中多那个部分的数据前端通过json弄到服务器 2.所有通过一操作多的时候,都要用上模型中定义的 ...
- python dataframe 列_python pandas库中DataFrame对行和列的操作实例讲解
用pandas中的DataFrame时选取行或列: import numpy as np import pandas as pd from pandas import Sereis, DataFram ...
- ubuntu用户管理与权限操作实例
ubuntu用户管理与权限操作实例 昨天在转载此文时提到都要把文件及目录权限的操作也会独立成文来给大家介绍,今天特地学习了用户管理和权限操作的例程,现总结如下.这些命令基本都是我在自己电脑上运行过后能 ...
- Linux nor flash分区,Linux驱动开发笔记:NOR FLASH编写实例
1. 背景介绍 板子上的zynq通过emc外接一块nor flash,地址分配如下: Nor flash的起始地址为0x80000000.当zynq上运行Linux后可以通过对该地址起始的区域进行擦除 ...
- Fluent多相流之VOF模型操作实例
Fluent多相流之VOF模型操作实例 前言:"相"指不同物态或同一物态的不同物理性质或力学状态.相具有可定义的边界,对周围流场有特定的动力响应,相一般分为固体.液体和气体,但也指 ...
- mysql修改工资字段_基于Linux的MySQL操作实例(修改表结构,MySQL索引,MySQL数据引擎)...
基于Linux的MySQL操作实例(修改表结构,MySQL索引,MySQL数据引擎) 前言 本篇是基于Linux下针对MySQL表结构的修改,MySQL索引的操作以及MySQL数据引擎的配置和说明. ...
最新文章
- android从放弃到精通 第八天 freedom
- WiFi安全之WPA介绍
- wxWidgets:异形窗示例
- 动态加入JS及加入CSS
- 静态static关键字修饰成员方法
- tasker使用手册_如何开始使用Tasker调整Android手机
- 二分+01分数规划+最大化平均值 Dropping tests POJ - 2976
- php数据库创建文件失败怎么回事,安装zblogPHP提示“创建c_option.php失败”解决方法...
- xenserver 安装新硬盘_给Xenserver添加新硬盘
- php分页上一页下一页判断,一个分页函数:显示“上一页下一页”等
- 程序员必备的10大健康装备!
- python函数和模块有什么关键特性_【Python函数与模块】(2)函数的特点
- linux在服务器上下载文件,上传下载文件到Linux服务器
- .net快速开发框架源码分享
- python有哪两种表现形式小练笔_写一篇不一样的爱400字:爱有两种表现形式小练笔400字...
- 一个在线五笔的例子的代码,很不错,转载过来共享
- 我和你,不是影子一样的朋友,只在光明的日子里相随
- 转本计算机知识普及软件,江苏专转本新政策的解读
- Cesium解决传感器抖动问题
- 时间管理经典书籍-《番茄工作法图解》
热门文章
- python中sys.stdout和sys.stderr
- 联想IBM ThinkPad 笔记本BIOS设置手册
- 线和面的方程区别_平面方程和直线方程的区别?
- exlc表格怎么换行_在Excel中如何换行?Excel表格换行快捷键是什么?
- 信息系统高级项目管理师:十大知识领域+五大过程组
- 【C语言】之实现大小写字母转换
- 添加178源未能链接服务器,添加178源_在cydia中添加178源_178插件源-Guide信息网
- hdu-4747(线段树)
- 递归算法应用实例------八皇后算法
- Bad Request This combination of host and port requires TLS