第四章各类主控制器及应用场合.docx

上传人:b****6 文档编号:3394302 上传时间:2022-11-22 格式:DOCX 页数:22 大小:2.59MB
下载 相关 举报
第四章各类主控制器及应用场合.docx_第1页
第1页 / 共22页
第四章各类主控制器及应用场合.docx_第2页
第2页 / 共22页
第四章各类主控制器及应用场合.docx_第3页
第3页 / 共22页
第四章各类主控制器及应用场合.docx_第4页
第4页 / 共22页
第四章各类主控制器及应用场合.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

第四章各类主控制器及应用场合.docx

《第四章各类主控制器及应用场合.docx》由会员分享,可在线阅读,更多相关《第四章各类主控制器及应用场合.docx(22页珍藏版)》请在冰豆网上搜索。

第四章各类主控制器及应用场合.docx

第四章各类主控制器及应用场合

第四章各类主控制器及应用场合

第一节单片机

微处理器的发展有两条路径:

通用微处理器和嵌入式微处理器。

目前仍活跃在应用领域的微处理器主要有51系列单片机和ARM。

通用微处理器的发展历程如下图所示。

嵌入式微处理器的发展如下图所示。

4.1.1单片机结构

51单片机的内部结构如下图所示。

由上图可见:

(1)8位数据总线,16位地址总线;

(2)采用哈佛结构,程序存储器与数据存储器地址空间各自独立,便于程序设计;

(3)P0口复用为数据总线,通过8位内部总线与数据存储器RAM相连接;

(4)P0口复用为地址总线时,与P2口一起通过16位地址总线与程序存储器ROM相连接;

(5)P0、P1、P2、P3具有输入锁存器及输出驱动器。

4.1.2IO口结构及工作原理

◆P0口8位中的1位结构如下图所示。

(1)输入缓冲器:

由三态门构成,当三态门的控制端(读锁存器或读引脚)有效时,D触发器的输出端Q的数据或引脚上的数据被读到内部总线上;当三态门的控制端无效时,缓冲器的输出呈现高阻状态。

(2)输出锁存器:

由D触发器构成。

当写锁存器时钟有效时,内部总线上的数据被写到输出锁存器的输出端;否则,锁存器输出端的状态保持上一个写锁存器时钟有效时的状态不变。

(3)多路开关:

在51单片机中,当内部的存储器够用(也就是不需要外扩存储器时,这里讲的存储器包括数据存储器和程序存储器)时,P0口可以作为通用的输入输出端口使用,对于8031(内部没有ROM)的单片机或者编写的程序超过了单片机内部的存储器容量,需要外扩存储器时,P0口就作为地址/数据总线使用。

这个多路选择开关就是用于选择是作为普通IO口使用还是作为数据/地址总线使用。

当多路开关与下面接通时,P0口作为普通IO口使用,当多路开关与上面接通时,P0口作为地址/数据总线使用。

(4)输出驱动器:

P0口的输出驱动是由连个MOS管组成的推挽式结构。

因为晶体管的导通电阻很小,所以输出电阻接近于零,输出驱动能力很强。

下面详细分析P0口的工作原理。

(1)用作普通IO口且作为输出口:

当P0口用作普通IO口使用时,控制信号为低电平,多路开关连通D触发器的/Q端和下MOS管的栅极,上MOS管的栅极电压为低电平。

上MOS管截止(整个结构相当于OD门输出)。

写锁存器信号有效,数据由内部总线输出到D触发器的/Q端。

当内部总线上数据为低电平时,/Q为高电平,下MOS管导通,输出引脚经下MOS管下拉到地;当内部总线上数据为高电平时,/Q为低电平,下MOS管截止,输出引脚呈现高阻态。

因此,若想输出高电平,需要对引脚上拉到VCC。

(2)用作普通IO口且作为输入口:

作为输入口有两种读方式,一是读引脚,二是读锁存器。

a.读引脚:

当P0口用作普通IO口使用时,控制信号为低电平,多路开关连通D触发器的/Q端和下MOS管的栅极,上MOS管的栅极电压为低电平。

上MOS管截止。

若此时下MOS管导通,则引脚将被强制拉到低电平,无法读入引脚上的高电平状态。

因此,读引脚操作时,需要先向输出锁存器写‘1’,使得下MOS管也截止,此时引脚上数据才能通过读引脚输入缓冲器被读入到内部总线上。

b.读锁存器:

通过打开读锁存器三态缓冲器读取锁存器输出端Q的状态。

在输入状态下,从锁存器和从引脚上读来的信号一般是一致的,但也有例外。

例如,当从内部总线输出低电平后,锁存器Q=0,/Q=1,下MOS管导通,引脚呈现低电平状态。

此时无论端口线上外接的信号是低电平还是高电平,从引脚读入单片机的信号都是低电平,因而不能正确地读入引脚上的信号。

又如,当从内部总线输出高电平后,锁存器Q=1,/Q=0,下MOS管截止,如果此时外接引脚信号为低电平,那么从引脚上读入的信号就与从锁存器读入的信号不同。

为此,8051单片机在对端口P0-P3的输入操作上,有如下约定:

凡属于读-修改-写方式的指令,从锁存器读入信号,其他指令则从端口引脚线上读入信号。

读-修改-写指令的特点是,从端口读入信号,在单片机内加以运算后,再输出到该端口上。

这样安排的原因在于读-修改-写指令需要得到端口原输出的状态,修改后再输出,读锁存器而不是读引脚,可以避免因外部电路的原因而使原端口的状态被读错。

8051CPU会根据指令码判断是读引脚还是读锁存器。

为了确保正确使用P0口作为普通IO输入口,编程时不必区分是读引脚还是读锁存器,只要是进行读操作,都要在读指令前进行写‘1’操作。

由于在读入前需要附加一个写‘1’的操作,这类端口成为准双向口。

(3)用作地址/数据输出口:

此时控制信号为‘1’,与门解锁。

当地址/数据信号为‘0’时,与门输出低电平,上MOS管截止,反相器输出高电平,下MOS管导通,引脚通过下MOS管拉到地,输出低电平;当地址/数据信号为‘1’时,与门输出高电平,上MOS管导通,反相器输出低电平,下MOS管截止,引脚通过上MOS管拉到VCC,输出高电平。

可见,在输出地址/数据信息时,上/下MOS管是交替导通的,负载能力很强。

可以直接与外设存储器相连,无须增加总线驱动器。

(4)用作数据输入口:

例如,在访问外部程序存储器时,P0口输出低8位地址信息后,将变为数据总线,以便读入指令码。

在取指令期间,控制信号为‘0’,上MOS管截止,多路开关连通锁存器反向输出端和下MOS管栅极。

CPU自动将0FFH写入P0口锁存器,使下MOS管截止,通过读引脚三态门电路将指令码读入内部总线。

通过以上的分析可以看出,当P0口作为地址/数据总线使用时,在读入指令码或输入数据前,CPU自动向P0口锁存器写入0FFH,破坏了P0口原来的状态。

因此,P0口此时不能再作为通用IO口。

即程序中不能再含有以P0口作为操作数的指令。

◆P1口8位中的1位结构如下图所示。

由上图可见,P1口和P0口的主要区别在于,P1口用上拉电阻R代替了P0口的上MOS管,并且不具有复用功能,输出的信息仅来自于内部总线,由内部总线输出的数据经锁存器反相和场效应管反向后,锁存在端口线上。

所以P1口是具有输出锁存的静态口。

同P0口工作原理类似,P1口也是准双向口。

工作原理不再赘述。

◆P2口8位中的1位结构如下图所示。

P2口在片内既有上拉电阻,又有多路开关,所以P2口在功能上兼有P0口和P1口的特点。

作为普通输入/输出口时,与P0和P1口工作原理相同。

作为输出地址口时,由于P2口不需要时分输出数据,因此,输出的地址信息保存时间长,无须外加锁存器。

换句话说,在进行外部存储器扩展时,P0口需要外加锁存器后连接到外部存储器的地址和数据总线上,通过单片机输出的控制信号(ALE/PSEN)来控制锁存器输出是地址还是数据。

而P2口直接连接在外部地址总线的高8位上即可,不需要外加锁存器。

◆P3口8位中的1位结构如下图所示。

P3端口和P1端口的结构相似,区别仅在于P3端口的各端口线有两种功能选择。

当处于第一功能时,第二输出功能线为1,此时,内部总线信号经锁存器和场效应管输入/输出,其作用与P1端口作用相同,也是静态准双向I/O端口。

当处于第二功能时,锁存器输出1,通过第二输出功能线输出特定的内含信号,在输入方面,即可以通过缓冲器读入引脚信号,还可以通过替代输入功能读入片内的特定第二功能信号。

由于输出信号锁存并且有双重功能,故P3端口为静态双功能端口。

在应用中,如不设定P3端口各位的第二功能(WR,RD信叼的产生不用设置),则P3端口线自动处于第一功能状态,也就是静态I/O端口的工作状态。

在更多的场合是根据应用的需要,把几条端口线设置为第二功能,而另外几条端口线处于第一功能运行状态。

在这种情况下,不宜对P3端口作字节操作,需采用位操作的形式。

◆P0端口能驱动8个LSTTL负载。

如需增加负载能力,可在P0总线上增加总线驱动器。

P1,P2,P3端口各能驱动4个LSTTL负载。

4.1.3单片机工作原理

单片机是程序控制式计算机,它的运行过程是在程序控制下逐条执行程序指令的过程,即从程序存储器中取出指令送到指令寄存器IR,然后指令译码器ID进行译码,译码产生一系列符合定时要求的微操作信号,用以控制单片机各部分动作。

单片机上电后从默认地址(0地址)开始执行程序。

单片机的0地址(main函数地址)位于片内程序存储器。

当执行的程序地址超过片内程序存储器的地址空间时,自动跳转到外部程序存储器执行。

由于单片机的应用场合一般比较简单,程序代码量不多,因此其外扩的程序存储器一般为EPROM型或NorFlash。

这两种存储器的容量不大,但均支持字节读写操作,因此,可以直接执行程序,而且单片机的应用场合一般对速度要求不高,因而不需要将程序拷贝到RAM中运行。

单片机的RAM只是用来作为数据存储器,而不是程序运行的地方。

4.1.4单片机应用场合

单片机是结构最简单的主控制器,也是其他复杂主控制器的基础。

优点是结构简单,价格低廉。

缺点是速度较慢(51单片机外部时钟最高为12MHz),对存储器的管理能力较差,对嵌入式系统的支持能力较差,对复杂器件的操作不方便。

因此,单片机适合应用在简单的工业控制领域,既能满足控制的功能,又降低了控制系统的成本。

第二节ARM

ARM是嵌入式CPU的主流技术,已经成为32位嵌入式处理器事实上的标准。

4.2.1ARM结构

ARM内核的内部结构如下图所示。

ARM7处理器采用冯诺依曼结构,指令和数据共用一条32位数据总线。

从ARM9处理器开始采用哈佛结构。

由上图可见,ARM与单片机一样,内部具有指令译码器和逻辑控制单元、地址寄存器、地址增量器、状态寄存器、读写数据寄存器。

比单片机多乘法器和移位寄存器。

且通过CP控制和CP握手信号对存储器进行管理。

流水线结构保证了数据处理的速度。

ARM提供的存储器管理功能和流水线结构为嵌入操作系统提供了最底层的硬件支持。

ARM的流水线级别如下图所示。

4.2.2ARM工作原理

ARM的程序一般分为两部分:

启动代码和功能代码。

启动代码的主要工作是初始化芯片的各种工作模式下的堆栈和中断向量表。

执行完启动代码后,CPU程序指针默认跳转到_main()函数执行,此处主要初始化一些数据区域。

然后再跳转到我们平时编写的main()函数,也就是所谓的功能代码。

ARM上电后也是从默认地址开始执行程序,根据启动方式的不同,该默认地址指向不同的位置。

(1)内部Flash启动:

芯片上电后PC立即开始执行内部Flash存储器里面的代码,即当内部flash启动方式时,芯片上电后的默认地址指向内部flash,但不一定是flash的零地址,具体指向flash中的哪个地址可以在芯片固化时设定。

由于内部flash存储器的容量非常小(芯片成本与体积成指数关系),所以不可能把我们编写的所有代码全部放进去,仅仅将启动代码保存在这个内部flash中,而将功能代码保存到外部的大容量廉价的存储器中。

因此启动代码又多了一项工作:

从外部非易失性程序存储器搬运功能代码到某个可以执行代码的存储器(如SDRAM)中,然后跳转到SDRAM地址去执行功能代码。

(2)外部存储器启动:

一般由NAND、NOR、SD启动三种,这几种启动方式流程大致相似,这里仅以NAND启动来说明。

在这种启动方式下,断电时将启动代码和功能代码全部保存至外部存储器中,芯片上电后内部的DMA器件自动搬运NAND的前8K代码到SDRAM,具体搬运到哪个地址也是在芯片设计时确定的,而且搬运的代码大小也是在芯片设计时确定的。

也就是说芯片上电后不再立即执行代码了,而是先启动总线到指定地址搬运代码,然后再从SDRAM开始执行代码。

所以习惯上这前几K的代码我们依然放的是启动代码,功能代码还是放在外部存储器的另一个地方。

启动代码中依然有搬运功能代码的部分,下面的执行就和第一种启动类似了。

(3)JTAG调试模式:

使用JTAG时,可以通过JTAG将代码放到任意一个可字节寻址的地址,然后会直接从此处开始执行代码。

上述讲述均是未嵌入操作系统的情况下。

对于嵌入式操作系统来说,功能代码包括Bootloader和操作系统两部分源码。

启动代码初始化堆栈,并搬运Bootloader到SDRAM。

然后开始执行Bootloader,用户可通过bootloader中的简单shell配置启动参数,然后开始搬运操作系统源码到SDRAM中,这一过程又叫做引导。

最后开始执行操作系统代码,也就是常说的将控制权交于操作系统,系统启动后,也即进入Linux世界。

通常情况下,程序是保存在Flash里面的,CPU从Flash中取指运行;但是,有时会要求将程序调到RAM中来执行。

一方面是为追求更高的速度;另一方面是为了让Flash有最好的运行性能,需要修改Flash的等待状态周期,使能FlashPipeline,而对Flash的操作必须在RAM里面执行,这些操作函数就必然要从Flash中调到RAM中执行。

对于这些程序,在启动后用户程序中需要先完成存储器拷贝工作。

拷贝到RAM中之后,才能调用这些函数,顺序不能乱。

4.2.3ARM应用场合

从某个角度上讲,可以将ARM理解成一个高级的单片机。

由于具有流水线及存储器管理结构,使得ARM可以嵌入操作系统;由于操作系统的嵌入,方便了对硬件模块的管理,因此,经常将常用的硬件模块固化,仅提供给用户操作硬件模块的接口寄存器。

节省了用户直接对硬件底层接口进行编程的操作。

另外,ARM嵌入式系统的移植很方便,为程序员节省了很多开发底层代码的时间。

因此,在控制器领域,ARM已占据了大部分天下。

大部分产品的主控制器均是基于ARM平台的。

如通信领域、存储领域、掌上电脑领域等等。

第三节CPLD/FPGA

4.3.1CPLD/FPGA内部结构

◆CPLD内部结构:

CPLD的内部结构如下图所示。

如上图所示,CPLD的结构是基于乘积项的,可分为3部分:

功能模块(functionblock)、快速互连矩阵(fastconnectswitchmatrix)和I/O控制模块。

(1)功能模块的结构如下图所示。

每个功能模块包括可编程与阵列、乘积项分配器和18个宏单元。

宏单元是CPLD的基本结构,由它来实现基本的逻辑功能。

下图所示为宏单元的基本结构。

左侧是乘积项阵列,实际就是一个与或阵列,每一个交叉点都是可编程的,如果导通就实现与逻辑,与后面的乘积项分配器一起实现组合逻辑。

右侧是一个可编程的触发器,可配置为D触发器或T触发器,它的时钟、清零输入都可以编程选择,可以使用专用的全局清零和全局时钟,也可以使用内部逻辑(乘积项阵列)产生的时钟和清零。

如果不需要触发器,也可以将此触发器旁路,信号直接输出给互连矩阵或输出到IO引脚。

(2)快速互连矩阵负责信号传递,连接所有的功能模块。

(3)IO控制模块负责输入输出的电器特性控制。

◆FPGA内部结构:

FPGA的内部结构如下图所示。

如上图所示,FPGA内部结构是基于查找表的,主要包括以下几个部分:

输入/输出模块Input/OutputBlocks(IOB)、可配置逻辑单元ConfigurableLogicBlocks(CLB)、BramBlockSelectRAMl18x18乘法器(18-Bitx18-BitMultipliers)、全局时钟网络(GlobalClockMux)、数字时钟管理模块(DCM)和布线资源(RoutingResources)。

◆IOB:

在FPGA中,所有的IOB分成8组(Bank),每一边有两组。

一些I/O标准需要外部的参考电压VCCO或者VREF,这些外部电压必须同FPGA引脚相连。

每个组(Bank)中都有多个VCCO引脚,在相同的Bank中所有VCCO引脚必须与相同电压连接。

电压大小由使用的I/O标准决定。

在一个组内部,如果所有I/O标准都使用相同的VCCO,则它们可以兼容。

每一组IOB中,能够使用的时钟网络只有两个,也就是说在每一组中,至多可以同时使用两组不同时钟的输入输出。

IOB内部的逻辑资源如下图所示。

由上图可见,IOB模块中包括6个存储单元(Reg),每个单元即可以配置成为边沿触发的D寄存器(flip-flop,FF),也可以配置能电平触发的锁存器(latch)。

IOB中,每条路径上都有两个寄存器用来进行DDR(doubledatarate)数据传送,两个寄存器的时钟需要保持反相,可以通过DCM来达到这一点。

◆CLB:

CLB是FPGA中的基本逻辑单元,其结构比较复杂。

在XilinxVirtexⅡ系列FPGA中,一个CLB单元由,四个结构类似的Slice模块组成。

在FPGA内部,所有CLB单元排列成阵列,并于交换矩阵(SwitchMatrix)相连,如下图所示。

上图中,“X1Y1”、“X1Y0”、“X0Y1”、“X0Y0”是Slice在FPGA中的位置编号,在FPGA中每一个Slice都会根据自己的横纵坐标有一个独一无二的编号。

每一个Slice模块中包含2个4输入LUT(LookUpTable,查找表)和2个1bit的存储单元。

其中,LUT能够根据设计需要配置成为:

组合逻辑、单口RAM、双口RAM、ROM、移位寄存器和多路选通器;存储单元可以配置成为边沿触发的寄存器或者电平触发的锁存器。

(1)LUT本质上讲就是一个16bit的SRAM(静态随机存储器),4个输入实际上就是SRAM的地址。

对于一个4输入得组合逻辑来说,他的结果最多只可能有16种,那么,我们完全可以把所有的16种结果事前全部计算出来,存放在一块16bit的区域中,再将组合逻辑的输入作为SRAM的读取地址,这样我们就可以通过LUT的方式实现了任意4输入的组合逻辑功能。

而且,使用这样的实现方法,电路延迟同组合逻辑无关,只取决于SRAM的读写速度。

当用户通过原理图或HDL语言描述了一个逻辑电路以后,PLD/FPGA开发软件会自动计算逻辑电路的所有可能的结果,并把结果事先写入RAM,这样,每输入一个信号进行逻辑运算就等于输入一个地址进行查表,找出地址对应的内容,然后输出。

a.DistributedSelectRAMMemory

既然LUT本质上就是一小块RAM,那么在实际的设计过程中,我们也可以把LUT配置成为RAM来使用(此处所说的配置是系统自动配置,不需要用户人工干预)。

LUT作为RAM来使用的时候也有两种配置方式:

单口RAM和双口RAM。

一个LUT配置成为一块16bitx1的RAM,而双口RAM要多占用一倍的资源,既需要两个LUT才能配置成一块16bitx1的双口RAM。

图8所示配置成RAM所占用资源的情况,其中“S”代表单口RAM;“D”代表双口RAM。

无论是LUT配置成的单口RAM还是双口RAM都可以通过并联或者串联来增加RAM的数据位宽度和地址位深度(容量)。

通RAM类似,LUT还能够配置能ROM。

b.移位寄存器

LUT还有一种非常重要的配置方式是移位寄存器。

LUT的输入A[3:

0]用来选择移位寄存器输出长度,对于单个LUT构成的移位寄存器来说,最大长度为16bit。

移位寄存器既可以配置成固定长度的、静态移位寄存器,也可以配置成动态的移位寄存器。

在每个时钟(CLK)的上升沿,移位寄存器从D(BY)读取一位数据。

信号Output作为移位寄存器的输出,输出的位置由A[3:

0]的值决定。

移位寄存器有两种工作模式:

静态模式和动态模式。

静态模式中,地址A[3:

0]都是定值(staticvalue),移位寄存器的长度的范围为1bit到16bit。

可以由以下公式确定:

Length=(8*A3)+(4*A2)+(2*A1)+A0+1

如果输入全部为零,则移位寄存器的长度为1;如果输入全部为1,则移位寄存器长度为16。

在动态模式中,移位寄存器的长度可以根据A[3:

0]变化,计算公式同静态模式中相同。

需要注意的是,尽管我们可以动态的配置移位寄存器的长度,但是对于一个LUT来说,它本质上讲还是一个16bit的移位寄存器,一位寄存器的长度仅仅是指出了数据出口的位置。

例如,当我们将移位寄存器的长度从12改为8的时候,输出的是第8个数据,但移位寄存器并没有将后面的数据丢掉,如果我们这个时候再把长度设为10还是能够得到正确的数据。

下图为移位寄存器的结构,这里需要指出的是在上面的讨论中都是没有寄存器的情况下,如果移位寄存器包含了寄存器,既输出为RegisteredOutput,则在静态模式下移位寄存器的长度要加1,动态模式下的情况比较复杂,请读者自己分析。

移位寄存器,还可以级联以进行扩展。

在FPGA内部,有一条专用联线,用于移位寄存器的级联扩展,即上图中的“SHIFT”,它将前级移位寄存器的输出同后级移位寄存器的输入相连。

在一个CLB单元中至多可以构成一个256bit的移位寄存器。

c.寄存器/锁存器(Register/Latch)

Slice中的存储单元即可以配置成边沿触发的寄存器,也可以配置成电平触发锁存器。

寄存器的输入即可以使LUT的输出,也可以是来自交换矩阵(SwitchMatrix)的数据。

可以通过设置属性的方式设置寄存器的初值和清零方式,INIT1表示初值为1;INIT0表示初值为0。

设定SRHIGH时,在“SR”有效时寄存器值为“1”;设定SRLOW时,在“SR”有效时寄存器值为“0”。

在默认情况下,设定SRHIGH即表示了INIT1;设定SRLOW即表示了INIT0;当然,这两组属性也可以分别独立设置。

每个Slice都可以配置成同步清零或者异步清零。

在下图中,CLK为时钟信号;SR为清零信号;CE为时钟有效信号(ClockEnable);DY、BY、DX、BX都是寄存器的输入。

可以看出,在同一个Slice中的CLK、SR、CE信号都是共用的。

d.多路选通器(Multiplexers)

任何一个LUT都可以构成一个2:

1的选通器;在一个Slice中,可以构成一个4:

1的选通器;在两个Slice中,可以构成一个8:

1的选通器;在一个CLB中,可以构成一个16:

1的选通器;在两个CLB中,可以构成一个32:

1的选通器;

e.快速进位逻辑(FastLookaheadCarryLogic)

FPGA内部有专用的进位逻辑,可以对加减法运算速率进行优化,每个CLB单元中有两条独立的进位链。

每个Slice中的进位链宽度为2bit。

专用进位链和专用的选通器MUXCY还可以用于串联LUT,以实现更复杂的逻辑。

算数逻辑(ArithmeticLogic)

Slice内部有异或门(XOR)可以实现两位全加器。

还有一个专用的与门,可以提高选通器的实现效率。

加法是最常用的逻辑结构,FPGA内部之所以有算数逻辑结构主要是为了对加法的速率和实现进行优化。

三态缓存器(3-StateBuffers)

每一个Slice中都有2个三态缓存器。

如下图所示,可以利用三态缓存器构建片内的总线,实现同一条连线上的双向通信。

◆BRAM(18KbitBlockSelectRAMResources)

XilinxVirtexⅡ中集成了大量18KbitBlockSelectRAMResources(以下简称BRAM)。

每一块BRAM都是物理上的双口RAM,它有两个独立的时钟和两组独立的控制端口。

每一组端口都包括以下输入:

时钟(CLK)、时钟有效(CE,ClockEnable)、写有效(WE,WriteEnable)、复位(SSR,Set/Reset)、地址(ADDR,Address),以及数据通路DI(DataIn)和DO(DataOut)。

BRAM的工作时同寄存器类似,控

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1