课程名称:模拟电路与数字系统(三)实验
实验项目名称:并行IO接口设计
· 要求所有外设都通过GPIO连接到MicroBlaze微处理器构成的计算机系统的同一总线上。分别通过程序控制方式和并行IO接口中断方式实现不同的功能:
程序控制方式实现:
嵌入式计算机系统将独立按键以及独立开关作为输入设备,LED
灯作为输出设备,实现以下功能:
(1) 按下BTNC 按键时,计算机读入一组16
位独立开关状态作为第一个输入的二进制数据,并即时显示输入的二进制数到16 位LED
灯上。(没有按下BTNC按键时,开关拨动不读入数据)
(2) 按下BTNR 按键时,计算机读入另一组16
位独立开关状态作为第二个输入的二进制数据,并即时显示输入的二进制数到16 位LED
灯上。(没有按下BTNR按键时,开关拨动不读入数据)
(3) 按下BTNU 按键时,将保存的2
组二进制数据做无符号加法运算,并将运算结果输出到LED 灯对应位。
(4) 按下BTND 按键时,将保存的2
组二进制数据做无符号乘法运算,并将运算结果输出到LED 灯对应位。
(程序控制方式提示:循环读取按键键值,根据按键的值读取开关状态,并做相应处理。)
并行IO接口中断方式实现:
嵌入式计算机系统将独立按键以及独立开关作为输入设备,七段数码管作为输出设备。实现以下功能:
(1) 按下BTNC 按键时,计算机读入一组16
位独立开关状态作为一个二进制数据,并将该二进制数的低8 位对应的二进制数值0
或1 显示到8 个七段数码管上。
(2) 按下BTNU 按键时,计算机读入一组16
位独立开关状态作为一个二进制数据,并将该16 进制数据各位数字对应的字符0~F
显示到低4 位七段数码管上(高4 位七段数码管不显示)。
(3) 按下BTND 按键时,计算机读入一组16
位独立开关状态作为一个二进制数据,并将该数据表示的无符号十进制数各位数字对应的字符0~9
显示到低5 位七段数码管上(高3 位七段数码管不显示)。
设计各种控制方式下的控制程序(要求设计程序框架结构、各个函数之间的关联关系、各个函数的执行流程图并说明原因、写出程序源代码)。
掌握GPIOIP核的工作原理;
掌握IO接口程序控制方法;
掌握中断控制方式的10接口设计原理;
掌握中断程序设计方法。
Windows 10操作系统 ;
嵌入式软件开发平台:Vivado 2018.1
硬件平台开发板:Xilinx Nexys4。
任务1中共有两种输入设备,一种输出设备:分别是独立按键以及独立开关作为输入设备,LED
灯作为输出设备。
采用程序控制方式实现时,只需要一个主程序来实现,在主程序中设置GPIO各个通道的工作模式,并开始循环读取按键状态,如果按键状态改变,则根据按键的不同值,进入不同的if语句,来实现相应的功能:
当按键值为0x10,即BTNC被按下时,读取此时对应开关状态,存为csw1,并将其显示在LED灯上;
当按键值为0x10,即BTNR被按下时,读取此时对应开关状态,存为csw2,并将其显示在LED灯上;
当按键值为0x10,即BTNU被按下时,结果取r1 = csw1 +
csw2,并将结果r1显示在LED灯上;
当按键值为0x10,即BTND被按下时,结果取r2 = csw1
*csw2,并将结果r2显示在LED灯上.
流程图如图2所示:
图2 程序控制方式主程序流程图
分析题目可知,主要需要实现2个任务:
① 七段数码管动态显示:
七段数码管动态显示电路也需要硬件定时中断,动态显示利用视觉暂留效应,定时间隔不能被人察觉,使用Timer_0,中断程序为:Timer_0中断时,中断事务处理为点亮当前位置的七段数码管,即输出当前位置的七段数码管段码和位码,并且将七段数码管点亮位置修改为下一位。其中,Timer_0的定时间隔需满足视觉暂留效应要求即可。
② 开关与按键状态输入:
开关状态输入以及按键状态输入都在按键的GPIO中断事务处理实现。按键的GPIO中断事务处理除了读入开关状态的功能外,还需根据开关状态更新七段数码管显示缓冲区。
所以,控制程序可以分为四个函数,他们的层级结构如图3所示:
其中,各个函数的功能与流程如下所示:
①中断初始化程序:
功能与流程图如图4所示:
②总中断服务程序:
功能与流程图如图5所示:
③Timer_0的中断事务处理函数:
④按键的中断事务处理函数:
功能与流程图如图7所示:
图7 按键的中断事务处理函数流程图
在Vivado 2018.1中,使用Xilinx
Nexys4开发板,搭建基于MicroBlaze软核的嵌入式系统硬件平台如下图8所示:
中断方式使用一个中断控制器:其中GPIO_0中断输出连接到Intr0,GPIO_2中断输出连接到Intr1,Timer_0中断输出连接到Intr2;中断控制器的中断向量输出连接到MicroBlaze微处理器的中断输入总线上。
其中对常用并行IO外设GPIO接口进行了配置(如图9):
16位开关和16位LED灯共用一个GPIO
IP核(设为GPIO_1),其中,开关使用GPIO通道,LED灯使用GPI2通道;四位七段数码管的位码与段码共用另一个GPIO
IP核(设为GPIO_0),其中,位码使用GPIO通道,段码使用GPIO2通道;两位按键使用另一个GPIO
IP核(设为GPIO_2)的GPIO通道;延时T0与T1使用Timer IP核(设为Timer_0)。
对并行IO中断系统进行了配置(如图10):
中断方式使用一个中断控制器:其中GPIO_1中断输出连接到Intr0;GPIO_2中断输出连接到Intr1;UART_0中断输出连接到Intr2;Timer_0中断输出连接到Intr3;
SPI_0中断输出连接到Intr4;
SPI_1中断输出连接到Intr5;;UART_1中断输出连接到Intr6;UART_2中断输出连接到Intr7.
中断控制器的中断向量输出连接到MicroBlaze微处理器的中断输入总线上。
如图所示:
对串行IO接口外设UART、SPI进行了配置(如图11):
生成HDL封装,查看硬件平台存储空间布局如下(如图12):
根据上面的分析,在主程序中设置按键对应GPIO通道工作在输入模式,开关对应的GPIO通道工作在输入模式,LED灯对应的GPIO通道工作在输出模式,设置并开始循环读取按键状态,如果按键状态改变,则根据按键的不同值,进入不同的if语句,来实现相应的功能:
· 当按键值为0x10,即BTNC被按下时,读取此时对应开关状态,存为csw1,并将其显示在LED灯上;
· 当按键值为0x10,即BTNR被按下时,读取此时对应开关状态,存为csw2,并将其显示在LED灯上;
· 当按键值为0x10,即BTNU被按下时,结果取r1 = csw1 +
csw2,并将结果r1显示在LED灯上;
· 当按键值为0x10,即BTND被按下时,结果取r2 = csw1
*csw2,并将结果r2显示在LED灯上.
\#include "stdio.h"
\#include "xil_io.h"
\#include "xgpio.h"
int main()
{
short button;
unsigned short csw1,csw2,r1,r2;
Xil_Out8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_TRI_OFFSET,0x1f);
Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI2_OFFSET,0xffff);
Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI_OFFSET,0x0);
while(1)
while((Xil_In8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_DATA_OFFSET)&0x1f)!=0)
{
button =
Xil_In8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_DATA_OFFSET)\&0x1f;
while((Xil_In8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_DATA_OFFSET)\&0x1f)!=0);
xil_printf("The pushed button's code is %d\\n" , button);
if(button==0x10 ){
csw1 =
Xil_In16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA2_OFFSET)\&0xffff;
Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA_OFFSET,csw1);
}
if(button ==0x8){
csw2 =
Xil_In16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA2_OFFSET)\&0xffff;
Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA_OFFSET,csw2);
}
if(button ==0x1){
r1 = csw1 + csw2;
Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA_OFFSET,r1);
}
if(button ==0x4){
r2 = csw1 \* csw2;
Xil_Out16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA_OFFSET,r2);
}
}
}
GPIO初始化:
对于程序控制方式,依据GPIO表格,写GPIO的TRI寄存器设置输入输出模式;
实现代码如下:
Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_TRI_OFFSET,0x0);//设段码输出方式
Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_TRI2_OFFSET,0x0);//设位码为输出方式
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_TRI_OFFSET,0x1f);//设地BUTTON方输入方式
Xil_Out32(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI2_OFFSET,0xffff);//设地Switch方输入方式
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_IER_OFFSET,XGPIO_IR_CH1_MASK);//允许中断
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_GIE_OFFSET,XGPIO_GIE_GINTR_ENABLE_MASK);//GPIO中断输出
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
Timer_0初始化:
Timer_0初始化的操作流程为:首先停止计时(通过写TCSR寄存器使使能定时器这一位为0实现),然后再是写预置值(通过写TLR寄存器实现),紧接着装载预置值(通过写TCSR寄存器使装载这一位为1实现)然后再是写TCSR寄存器,控制定时器使能。清除源中断状态、使能中断、使能自动装载、减计数。
实现代码如下:
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)&~XTC_CSR_ENABLE_TMR_MASK);//写TCSR,停止计数
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TLR_OFFSET,RESET_VALUE);//TLR,预置计数值
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)|XTC_CSR_LOAD_MASK);//
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
(Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)&~XTC_CSR_LOAD_MASK)\
|XTC_CSR_ENABLE_TMR_MASK|XTC_CSR_AUTO_RELOAD_MASK|XTC_CSR_ENABLE_INT_MASK|XTC_CSR_DOWN_COUNT_MASK);
INTC初始化与微处理器开中断:
INTC内部寄存器如下:
对中断控制器开中断:首先清除原中断状态,然后使能intr1和intr3对应的中断输入并使能中断输出(分别通过写IAR、IER以及MER寄存器实现);
MicroBlaze微处理器开中断:要实现微处理器开中断,我们可通过调用microblaze_enable_interrupt实现:
实现代码如下:
//INTC初始化
Xil_Out32(XPAR_INTC_0_BASEADDR+XIN_IER_OFFSET,XPAR_AXI_GPIO_2_IP2INTC_IRPT_MASK\|XPAR_AXI_TIMER_0_INTERRUPT_MASK);//
Xil_Out32(XPAR_INTC_0_BASEADDR+XIN_MER_OFFSET,0x3);
//微处理器开中断
microblaze_enable_interrupts();
总中断服务程序:
总中断服务程序,首先读取中断控制器的中断状态寄存器;然后判断D3是否为1,如果是1则表示按键状态发生了变化,因此调用按键对应的GPIO中断事务处理函数,返回之后,判断D3是否为1如果是1则表示Timer_0定时器计时时间到,因此调用Timer_0对应的中断事务处理函数。
实现代码如下:
void My_ISR()
{
int status;
status=Xil_In32(XPAR_INTC_0_BASEADDR+XIN_ISR_OFFSET);//续敢ISR
if((status&0x8)==0x8)
Seg_TimerCounterHandler();//l溉用用户中断服务狂序
else if((status&0x2)==0x2)
BtnHandler();//l遴用按痉中断
Xil_Out32(XPAR_INTC_0_BASEADDR+XIN_IAR_OFFSET,status);//写IAR
}
Timer_0的中断事务处理函数:
T0通过gpio_0的GPIO2通道控制一位LED灯点亮,并准备下一位的输出后直接退出。
实现代码如下:
void Seg_TimerCounterHandler()
{
Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_DATA_OFFSET,segcode[j]);
Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_DATA2_OFFSET,pos);
pos=pos\>\>1;
j++;
if(j==8)
{
j=0;
pos=0xff7f;
}
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET));//满总中断
}
按键的中断事务处理函数:
首先读取按键的状态,根据按键的值来实现相应功能:
实现代码如下:
void BtnHandler()
{
int button;
unsigned short sw;
int i;
int temp;
int q,w,e,r,t;
sw = Xil_In16(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_DATA2_OFFSET)\&0xffff;
button = Xil_In8(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_DATA_OFFSET)\&0x1f;
if(button == 0x10) //(1)
{
short pos1 = 0x0080;
for(i=0;i\<8;i++)
{
if((sw&pos1) != 0)
temp = 1;
else
temp = 0;
segcode[i] = segtable[temp];
pos1=pos1\>\>1;
}
}
else if(button == 0x1) //(2)
{
for(i=0;i\<8;i++)
{
if(i\>3){
temp = ( sw \>\>(4\*(7-i)))\&0xf;
segcode[i]=segtable[temp];
}
else
segcode[i] = 0xff;
}
}else if(button == 0x4) //(3)
{
q = sw/10000;
w = (sw-10000\*q)/1000;
e = (sw-10000\*q-1000\*w)/100;
r = (sw-10000\*q-1000\*w-100\*e)/10;
t = (sw-10000\*q-1000\*w-100\*e-10\*r)/1;
xil_printf("q=%d,w=%d,e=%d,r=%d,t=%d,",q,w,e,r,t);
for(i=0;i\<8;i++)
{
if(i\>2){
switch(i)
{
case 3:temp =q;break;
case 4:temp =w;break;
case 5:temp =e;break;
case 6:temp =r;break;
case 7:temp =t;break;
default: break;
}
segcode[i] = segtable[temp];
}
else
segcode[i] = 0xff;
}
}
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_ISR_OFFSET,
Xil_In32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_ISR_OFFSET));
}
完整代码:
最终的实现代码如下(上面的中断事务处理函数已折叠):
\#include "xil_io.h"
\#include "stdio.h"
\#include "xgpio_l.h"
\#include "xintc_l.h"
\#include "xtmrctr_l.h"
\#define RESET_VALUE 100000
void Seg_TimerCounterHandler();
void BtnHandler();
void My_ISR()__attribute__((interrupt_handler));//总中断服务雅序
char segtable[16] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e };
char segcode[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};//缓冲区
short pos=0xff7f;
int j = 0;
int main()
{
Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_TRI_OFFSET,0x0);//设段码输出方式
Xil_Out32(XPAR_AXI_GPIO_0_BASEADDR+XGPIO_TRI2_OFFSET,0x0);//设位码为输出方式
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_TRI_OFFSET,0x1f);//设地BUTTON方输入方式
Xil_Out32(XPAR_AXI_GPIO_1_BASEADDR+XGPIO_TRI2_OFFSET,0xffff);//设地Switch方输入方式
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_IER_OFFSET,XGPIO_IR_CH1_MASK);//允许中断
Xil_Out32(XPAR_AXI_GPIO_2_BASEADDR+XGPIO_GIE_OFFSET,XGPIO_GIE_GINTR_ENABLE_MASK);//GPIO中断输出
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)\&\~XTC_CSR_ENABLE_TMR_MASK);//琛TCSR,停止计数
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TLR_OFFSET,RESET_VALUE);//TLR,预置计数值
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)\|XTC_CSR_LOAD_MASK);//
Xil_Out32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET,
(Xil_In32(XPAR_AXI_TIMER_0_BASEADDR+XTC_TCSR_OFFSET)&\~XTC_CSR_LOAD_MASK)\\
\|XTC_CSR_ENABLE_TMR_MASK\|XTC_CSR_AUTO_RELOAD_MASK\|XTC_CSR_ENABLE_INT_MASK\|XTC_CSR_DOWN_COUNT_MASK);
//INTC初始化
Xil_Out32(XPAR_INTC_0_BASEADDR+XIN_IER_OFFSET,XPAR_AXI_GPIO_2_IP2INTC_IRPT_MASK\|XPAR_AXI_TIMER_0_INTERRUPT_MASK);//
Xil_Out32(XPAR_INTC_0_BASEADDR+XIN_MER_OFFSET,0x3);
//微处理器开中断
microblaze_enable_interrupts();
return 0;
}
void My_ISR()……
void Seg_TimerCounterHandler()……
void BtnHandler()……
按下BTNC 按键时,计算机读入一组16
位独立开关状态作为第一个输入的二进制数据,并即时显示输入的二进制数到16
位LED 灯上。(如图13)
输入为: 0000000000101101(十进制:45)
按下BTNR 按键时,计算机读入另一组16
位独立开关状态作为第二个输入的二进制数据,并即时显示输入的二进制数到16 位LED
灯上。(如图14)
按下BTNU 按键时,将保存的2
组二进制数据做无符号加法运算,并将运算结果输出到LED 灯对应位。(如图15)
按下BTND 按键时,将保存的2
组二进制数据做无符号乘法运算,并将运算结果输出到LED 灯对应位。(如图16)
输出为:0010010011101010(十进制:9450)
按下BTNC 按键时,计算机读入一组16
位独立开关状态作为一个二进制数据,并将该二进制数的低8
位对应的二进制数值0 或1 显示到8 个七段数码管上。(如图17)
按下BTNU 按键时,计算机读入一组16 位独立开关状态作为一个二进制数据,并将该16
进制数据各位数字对应的字符0~F 显示到低4 位七段数码管上(高4
位七段数码管不显示)。(如图18)
按下BTND 按键时,计算机读入一组16
位独立开关状态作为一个二进制数据,并将该数据表示的无符号十进制数各位数字对应的字符0~9
显示到低5 位七段数码管上(高3 位七段数码管不显示)。(如图19)
输入为:0001010101010101(十进制:5461)
程序控制方式 | 中断方式 |
---|---|
IO接口设计简单. 程序代码简洁明了. CPU和外设之间交换信息采用查询方式.,使得快速CPU与慢速外设之间矛盾 在反复查询上浪费了CPU的大部分时间. 程序配置比较灵活 | CPU实行分时操作,从而大大提高了计算机的效率. 能够立即响应与处理. 由软件维护中断向量表 通过一个总中断服务程序查询ISR寄存器识别中断源,来调用各个中断服务函数 通过软件写IAR和清除ISR |
这次实验是微机原理实验中最重要的一次实验。通过这次的实验,我学到了很多,也收获了很多。不仅对《微机原理与接口技术》课程的相关知识有了更为深入的了解,对使用中断控制方式实现各种较复杂的任务有了亲身的体会,也对独立自主学习与独立完成任务有了进一步的实践,主要有以下一些感受和认识:
中断控制器在计算机系统实现中断管理中至关重要.
由中断控制器来实现中断请求信号保持与清除、中断源识别、中断使能控制、中断优先级设置等功能,配合微处理器实现与外设之间的中断方式通信。
工作模式有快速中断与普通中断.
普通中断还是快速中断可由软件设定,他们之间的区别为:快速中断模式时,INTC
维护硬件中断向量表,在中断响应周期向微处理器提供中断向量,根据微处理器中断响应周期提供的中断响应状态信号自动清除中断状态;普通中断模式时,由软件维护中断向量表以及读取中断状态寄存器识别中断源,并且软件需在中断服务程序中写中断响应寄存器清除INTC中断状态。
中断方式程序设计.
中断方式程序设计包含两个程序:中断系统初始化程序和中断服务程序。它们的功能不同,但都十分重要,缺一不可。中断系统初始化程序主要完成设备初始化和中断系统初始化,实现如使能中断、填写中断向量表等功能;而中断服务程序主要完成中断事务处理以及清除中断状态等。中断服务程序由硬件中断源调用,因此不带参数。但是,当设备中断服务程序由总中断服务程序调用时,则可以带参数,此时设备的中断服务程序并非真正意义上的中断服务程序,而可以看作是总中断服务程序的一个子程序。
中断执行流程.
微处理器检查是否存在中断,需要在执行完现行指令且设置开中断。若有中断,则进入中断响应周期,流程为:关中断、保护断点; => 读取中断向量、转入中断服务程序; => 中断服务; =>
中断返回、开中断。
多中断源.
当有多个中断源时,中断发生时,不同的中断服务程序各自处理完成自己的任务,不会引起混乱;但每个中断事务要求要尽可能简单,如果过于复杂的话,可能会阻塞其他中断源,造成难以预料的错误。
使用全局变量与公共缓冲区.
因为中断服务程序相互之间不存在子、主程序关系,所以无法通过参数调用实现信息互传。因此,需要使用全局变量来完成不同程序之间的信息传递,比如说使用多个数码管显示时。同时,为了简化开发,在C语言中我们可以把地址用宏定义来代替。
代码纠错.
因为我们在开始开发前,总可能会没有考虑到实际会遇到的一些问题与困难,很多时候第一次写出来的代码无法实现理想的效果,会出现各种各样的问题。在解决问题时,我们应当学会对整个问题进行细化,学会对每部分进行一个流程的设计,学会先对每个模块进行分析,这样降低了问题的难度,也使得自己写代码更加顺畅,头脑更具有条理性,这样的分析、解决问题的方法,也是本次实验以及报告贯穿始终的。
通过这次实验,我对中断技术有了更加直观的了解,中断方式是计算机系统应用最为广泛的接口通信方式,同时,当许算机系统运行复杂软件系统时,中断方式也是软件各模块之间通信方式之一;对各种不同的实现方法也有了更加深刻地了解,不仅巩固了所学,也提升了各方面的能力,对计算机实现各种各样的更复杂的任务的底层逻辑有了一个初步的了解。
总之,这是一次意义丰富、收获众多的实验经历,我从中学到了很多!