北京邮电大学
嵌入式系统实验
实验报告
学院:电子
工程
路基工程安全技术交底工程项目施工成本控制工程量增项单年度零星工程技术标正投影法基本原理
学院
专业:电子信息科学与技术
班级:2010211203班
学号:
姓名:
2013年11月13日
一、实验目的
1.基本实验
搭建PXA270嵌入式LINUX开发软硬件环境;安装LINUX操作系统;安装与配置建立宿主机端交叉编译调试开发环境;配置宿主机 PC 机端的minicom(或超级终端)、TFTP服务、NFS服务,使宿主PC机与PXA270开发板可以通过串口通讯,并开通TFTP和NFS服务。
2.人机接口
键盘驱动;LCD控制;触摸屏数据采集与控制实验;
3.应用实验
完成VGA显示;Web服务器实验;网络文件传输实验;多线程应用实验。 4.扩展应用实验
完成USB摄像头驱动与视频采集;GPS实验;GSM/GPRS通讯;视频播放移植;USB蓝牙设备无线通讯;NFS文件服务器;蓝牙视频文件服务器。
5.QT实验
完成基本嵌入式图形开发环境搭建;“Hello world~”QT初探;创建一个窗口并添加按钮;对象通信:Signal和Slot;菜单和快捷键;工具条和状态栏;鼠标和键盘事件;对话框;QT的绘图;俄罗斯方块;基于QT的GSM手机在嵌入式LINUX下的设计与实现。
二、实验内容
1.人机接口实验
实验十九 键盘驱动实验
, 实验目的:矩阵键盘驱动的编写
, 实验内容:矩阵键盘驱动的编写
, 作业要求:完成键盘加减乘除运算
, 实验作业源码及注释:
#INCLUDE
#INCLUDE
#INCLUDE
#INCLUDE
#INCLUDE
#INCLUDE
#DEFINE DEVICE_NAME “/DEV/KEYBOARD”
INT MAIN(VOID){
INT FD;
INT RET;
UNSIGNED CHAR BUF[1];
INT I,F,J;
DOUBLE X;
INT A[2]={0};
CHAR PRE_SCANCODE=0XFF;
FD=OPEN(DEVICE_NAME,O_RDWR);
IF(FD==-1)PRINTF(“OPEN DEVICE %S ERROR\N”,DEVICE_NAME);
ELSE{
BUF[0]=0XFF;
I=0;F=0;
WHILE(1){
READ(FD,BUF,1);
IF(BUF[0]!=PRE_SCANCODE) //判断是否放开按键 IF(BUF[0]!=0XFF){ //判断是否键入
PRE_SCANCODE=BUF[0];
USLEEP(50000);
SWITCH(BUF[0]){
CASE 0X12:{ //按下ENTER
SWITCH(F){ //判断运算符
CASE
1:{J=I;I=(I+1)%2;X=A[I]+A[J];PRINTF(“%D+%D=%D”,A[I],A[J],X);BREAK;}
//加法
CASE 2:{J=I;I=(I+1)%2;X=A[I]-A[J];PRINTF(“%D-%D=%D”,A[I],A[J],X);BREAK;}//减法
CASE
3:{J=I;I=(I+1)%2;X=A[I]*A[J];PRINTF(“%D*%D=%D”,A[I],A[J],X);BREAK;}
//乘法
CASE
4:{J=I;I=(I+1)%2;X=A[I]/A[J];PRINTF(“%D/%D=%D”,A[I],A[J],X);BREAK;}
//除法
DEFAUIT:
}
F=0;BREAK;
}
CASE 0X13:{F=1;I=(I+1)%2;BREAK;} //键入运算符
CASE 0X14:{F=2;I=(I+1)%2;BREAK;}
CASE 0X15:{F=3;I=(I+1)%2;BREAK;}
CASE 0X16:{F=4;I=(I+1)%2;BREAK;}
DEFAULT:A[I]=BUF[0]; //存入数据
}
}
}
RET=CLOSE(FD);
}
RETURN 0;
}
, 实验结果:
实验效果图
实验二十 LCD控制实验
, 实验目的:了解LCD的基本原理
, 实验内容:使用总线方式驱动LCD模块,体会与QT下LCD显示的差别
, 作业要求:在目标板的LCD上显示彩色竖条纹或彩色圆环。
, 实验作业源码及注释:
#include
#include
#include
#include // open() close()
#include // read() write()
#define DEVICE_NAME "/dev/fb"
#define VERSION "PXA2700EP-LCD-V1.00-060530"
void showversion(void)
{
printf("*********************************************\n");
printf("\t %s \t\n", VERSION);
printf("*********************************************\n\n");
}
int main(void)
{
int fd;
int ret;
int i,j,r,R;
unsigned short buf[640*480];
showversion();
printf("\nstart test_lcd test\n\n");
fd = open(DEVICE_NAME, O_RDWR);
printf("fd = %d\n",fd);
if (fd == -1)
{
printf("open device %s error\n",DEVICE_NAME);
}
else
{
for(i=0;i<640*480;i++)
{
buf[i]=0x0001;
}
ret=write(fd,buf,sizeof(buf));
usleep(500000);
close(fd);
fd = open(DEVICE_NAME, O_RDWR);
//竖条纹算法:通过横坐标分布进行填色
for(r=0;r<640*480;r++){
i=r%640;
if(i>=0&&i<60)buf[r]=0x0001;
if(i>=60&&i<120)buf[r]=0xf800;
if(i>=120&&i<180)buf[r]=0x07ef;
if(i>=180&&i<240)buf[r]=0x001f;
if(i>=240&&i<300)buf[r]=0xffe0;
if(i>=300&&i<360)buf[r]=0x07ff;
if(i>=360&&i<420)buf[r]=0xf81f;
if(i>=420&&i<=480)buf[r]=0xffff;
}
/*
//圆环算法:通过离圆心半径分布进行填色
for(r=0;r<640*480;r++){
i=r%640;
j=r/640;
R=(i-320)*(i-320)+(j-480)*(j-480);
if(R>=0&&R<2500)buf[r]=0x0001;
if(R>=2500&&R<10000)buf[r]=0xf800;
if(R>=10000&&R<22500)buf[r]=0x07ef;
if(R>=22500&&R<40000)buf[r]=0x001f;
if(R>=40000&&R<62500)buf[r]=0xffe0;
if(R>=62500&&R<90000)buf[r]=0x07ff;
if(R>=90000&&R<122500)buf[r]=0xf81f;
if(R>=122500&&R<=160000)buf[r]=0xffff;
}
*/
ret=write(fd,buf,sizeof(buf));
getchar();
}
return 0;
}
, 实验结果:
实验效果图
实验二十一 触摸屏数据采集与控制
, 实验目的:通过实验掌握触摸屏的设计与控制方法
, 实验内容:编程实现触摸屏到LCD坐标的校准以及坐标采集和计算
随着使用电脑作为信息来源的与日俱增,触摸屏以其易于使用、坚固耐用、反应速度快、节省空间等优点,使得系统设计师们越来越多的感到使用触摸屏的确具有相当大的优越性。通过此试验,我们学习了触摸屏原理,并通过编写测试程序验证了触摸屏的工作过程。学习它,掌握它是非常必要的。
2.应用程序实验
实验二十二 VGA显示实验
, 实验目的:了解VGA接口的
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
和特点
, 实验内容:编程实现图像通过VGA接口在显示器上输出
通过本实验的操作,VGA设备成功启动,在液晶屏和显示器上可以看到完全同步的画面。由于两者格式和刷新频率的差别,实验中做了折中处理,可能显示效果没有达到最优。 实验二十三 Web服务器实验
, 实验目的:学习在PXA270开发板上的SOCKET网络编程
, 实验内容:SOCKET进行通讯编程
学习使用socket 进行通讯编程的过程,了解一个实际的网络通讯应用程序整体设计,
阅读HTTP
协议
离婚协议模板下载合伙人协议 下载渠道分销协议免费下载敬业协议下载授课协议下载
的相关内容,学习几个重要的网络函数的使用方法。读懂HTTPD.C源代码。
在此基础上增加一些其他功能。在宿主PC机上使用浏览器测试嵌入式WEB服务器的功能。 通过此实验,我们实现了嵌入式Web服务器的基本功能。
实验二十五 多线程应用实验
, 实验目的:学习PTHREAD 库函数的使用
, 实验内容:熟悉PTREAD库函数的使用,掌握共享锁和信号量的使用方法。 , 作业要求:利用多线程技术实现键盘控制在LCD液晶屏上显示的可移动的图形。 , 实验作业源码及注释:
#include
#include
#include
#include "pthread.h"
#include // open() close()
#include // read() write()
#include
#define DEVICE_NAME "/dev/fb"
#define BUFFER_SIZE 16
struct prodcons {
int buffer[BUFFER_SIZE]; /* the actual data */
pthread_mutex_t lock; /* mutex ensuring exclusive access to
buffer */
int readpos, writepos; /* positions for reading and writing */
pthread_cond_t notempty; /* signaled when buffer is not empty */
pthread_cond_t notfull; /* signaled when buffer is not full */
};
void init(struct prodcons * b)
{
pthread_mutex_init(&b->lock, NULL);
pthread_cond_init(&b->notempty, NULL);
pthread_cond_init(&b->notfull, NULL);
b->readpos = 0;
b->writepos = 0;
}
void put(struct prodcons * b, int data)
{
pthread_mutex_lock(&b->lock);
while ((b->writepos + 1) % BUFFER_SIZE == b->readpos) {
printf("wait for not full\n");
pthread_cond_wait(&b->notfull, &b->lock);
}
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos >= BUFFER_SIZE) b->writepos = 0;
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock); }
int get(struct prodcons * b)
{
int data;
pthread_mutex_lock(&b->lock);
while (b->writepos == b->readpos) {
printf("wait for not empty\n");
pthread_cond_wait(&b->notempty, &b->lock);
}
data = b->buffer[b->readpos];
b->readpos++;
if (b->readpos >= BUFFER_SIZE) b->readpos = 0;
pthread_cond_signal(&b->notfull);
pthread_mutex_unlock(&b->lock);
return data;
}
struct prodcons buffer;
//键盘输入线程
void * producer(void * data)
{
int fd;
int ret;
unsigned char buf[2] ;
// int i;
// double x;
char pre_scancode = 0x44;
fd = open("/dev/keypad", O_RDWR); // printf("fd = %d\n",fd);
if (fd == -1) {
printf("open device %s error\n",DEVICE_NAME);
}
else {
buf[0]=0x22;
while (1) {
read (fd,buf,1);
if(buf[0]!= pre_scancode)
{
if(buf[0]!=0x44)
{
printf("key=%x\n",buf[0]);
put(&buffer, buf[0]);
}
}
pre_scancode = buf[0]; // sleep(1);
usleep(50000);
}
// close
ret = close(fd);
// printf ("ret=%d\n",ret);
// printf ("close keypad_driver test\n");
}
}
//LCD显示线程
void * consumer(void * data) {
int d;
int ret;
int fd;
int i;
int j;
unsigned short buf[640*480];
fd = open("/dev/fb", O_RDWR);
if (fd == -1)
{
printf("open device %s error\n",DEVICE_NAME);
}
else
{
while(1)
{
d = get(&buffer);
printf("get num is %d\n", d);
for(i=0;i>>CCounter.h<<<
/* *******************************************************
* 文件名:CCounter.cpp
* 类名:CCounter
* 功能:计算器
* 作者:WNX
* 时间:2011年10月17日
* 版本:0.01
******************************************************* */
#ifndef _CCELLPHONE_H_
#define _CCELLPHONE_H_
#include // 包含Qt头文件 #include #include
#include #include
#include #include "CDigitalButton.h" // 包含自定义头文件 #define iWidthDigital50 // 数字按钮宽度 #define iHeightDigital 50 // 数字按钮高度
#define iWidthOther 100 // 其它按钮宽度
#define iHeightOther 40 // 其它按钮高度
#define cAppWidth (iWidthDigital*4) // 总宽度 #define cAppHeight (iWidthDigital*4+iHeightOther*2) // 总高度 #define iWidthOn 100 //On按钮宽度
#define iWidthCancel 100 // Cancel按钮宽度
#define DisLenth 5
#define cDigital 1 // 没用到 #define cErro 2
#define cCall 3
class CCounter : public QDialog {
Q_OBJECT // Never forget it when using signal&slot
public:
CCounter ( QWidget * parent = 0, const char * name = 0, bool modal = true );
// 重载构造函数,默认模态
~CCounter();
protected:
QLCDNumber *m_pLCD;
CDigitalButton *m_pDigitalBtn[11];
QPushButton *m_pOn;
QPushButton *m_pCancel;
QPushButton *AddButton;
QPushButton *SubButton;
QPushButton *MulButton;
QPushButton *DivButton;
QPushButton *EqlButton;
QString m_strLCD;
int m_stateLCD;
protected:
void InitConnect(void); // 初始化Signal/Slot
的连接
void InitButton(void); // 初始化各个按钮
public slots: // 定义插槽
void ClearLCDNumber();
void AddLCDNumber( const QString& str );
void DeleteLCDNumber();
void Culculate();
void IncCounter();
void SubCounter();
void MulCounter();
void DivCounter();
signals: // 定义信号
void LCDChanged( const QString& str );
private:
int counter;
int fh; // +1,-2,*3,/4,=5
int flag; //0:clear; 1:un-do
int ans;
};
#endif
>>>CCounter.cpp<<<
#include "CCounter.h"
CCounter::CCounter ( QWidget * parent, const char * name, bool modal )
:QDialog( parent, name, modal )
{
m_stateLCD = cDigital;
InitButton();
InitConnect();
setMinimumSize( cAppWidth, cAppHeight );
setMaximumSize( cAppWidth, cAppHeight );
}
CCounter::~CCounter()
{
}
void CCounter::InitConnect(void) // 建立信号和插槽的连接。二者的参数列表要相同
{
QObject::connect( m_pOn, SIGNAL( clicked() ),this, SLOT( ClearLCDNumber() ) );
QObject::connect( m_pCancel, SIGNAL( clicked() ),this,
SLOT( DeleteLCDNumber() ) );
QObject::connect( AddButton, SIGNAL( clicked() ),this, SLOT( IncCounter() ) );
QObject::connect( SubButton, SIGNAL( clicked() ),this, SLOT( SubCounter() ) );
QObject::connect( MulButton, SIGNAL( clicked() ),this, SLOT( MulCounter() ) );
QObject::connect( DivButton, SIGNAL( clicked() ),this, SLOT( DivCounter() ) );
QObject::connect( EqlButton, SIGNAL( clicked() ),this, SLOT( Culculate() ) );
int i;
for ( i=0; i<=9; i++ )
{
QObject::connect( m_pDigitalBtn[i], SIGNAL( numChanged( const QString& ) ),
this, SLOT( AddLCDNumber( const QString& ) ) );
}
QObject::connect( this, SIGNAL( LCDChanged( const QString& ) ),
m_pLCD, SLOT( display( const QString& ) ) );
}
void CCounter::InitButton(void)
{
int i=0, j=0;
char chNum[4];
m_pLCD = new QLCDNumber( DisLenth , this, "LCD" );// LCD
m_pLCD->setSegmentStyle( QLCDNumber::Flat );
m_pLCD->setGeometry( 0, 0, cAppWidth, iHeightOther );
m_pOn = new QPushButton( "On", this ); // On Button
m_pOn->setGeometry( 0*iWidthOn, 1*iHeightOther, iWidthOn, iHeightOther );
m_pCancel = new QPushButton( "C", this ); // Cancel Button
m_pCancel->setGeometry( 1*iWidthOn, 1*iHeightOther, iWidthCancel, iHeightOther );
AddButton = new QPushButton( "+", this );
AddButton->setGeometry( 3*iWidthDigital, 2*iHeightOther, iWidthDigital, iHeightDigital );
SubButton = new QPushButton( "-", this );
SubButton->setGeometry( 3*iWidthDigital, 2*iHeightOther+1*iHeightDigital, iWidthDigital, iHeightDigital );
MulButton = new QPushButton( "*", this );
MulButton->setGeometry( 3*iWidthDigital, 2*iHeightOther+2*iHeightDigital, iWidthDigital, iHeightDigital );
DivButton = new QPushButton( "/", this );
DivButton->setGeometry( 3*iWidthDigital, 2*iHeightOther+3*iHeightDigital, iWidthDigital, iHeightDigital );
EqlButton = new QPushButton( "=", this );
EqlButton->setGeometry( 2*iWidthDigital, 2*iHeightOther+3*iHeightDigital, iWidthDigital, iHeightDigital );
for( i=0; i<=9; i++ ) // Digital Buttons
{
sprintf( chNum, "%d", i );
m_pDigitalBtn[i] = new CDigitalButton( chNum, this );
QString s( chNum );
m_pDigitalBtn[i]->m_strNum = s;
}
for( i=0; i<3; i++ ) // 3 rows for digital buttons from 1 to 9
{
for( j=0; j<3; j++ )
{
m_pDigitalBtn[i*3+j+1]->setGeometry( j*iWidthDigital,
2*iHeightOther+i*iHeightDigital,
iWidthDigital, iHeightDigital );
}
}
m_pDigitalBtn[0]->setGeometry( 0*iWidthDigital,
2*iHeightOther+3*iHeightDigital,
iWidthDigital, iHeightDigital );
ans=0;
fh=0;
flag=1;
}
void CCounter::IncCounter()
{
int num;
bool ok;
if ( flag != 0)
{
num = m_strLCD.toInt( &ok , 10 );
if ( fh ==1 ) ans += num;
if ( fh ==2 ) ans = ans-num;
if ( fh ==3 ) ans = ans*num;
if ( fh ==4 ) ans = ans/num;
if ( fh ==0 ) ans = num;
flag=0;
fh=1;
m_strLCD = m_strLCD.setNum( ans );
emit LCDChanged( m_strLCD );
}
}
void CCounter::SubCounter()
{
int num;
bool ok;
if ( flag != 0)
{
num = m_strLCD.toInt( &ok, 10 );
if ( fh ==1 ) ans += num;
if ( fh ==2 ) ans = ans-num;
if ( fh ==3 ) ans = ans*num;
if ( fh ==4 ) ans = ans/num;
if ( fh ==0 ) ans = num;
flag=0;
fh=2;
m_strLCD = m_strLCD.setNum( ans );
emit LCDChanged( m_strLCD );
}
}
void CCounter::MulCounter() {
int num;
bool ok;
if ( flag != 0)
{
num = m_strLCD.toInt( &ok, 10 );
if ( fh ==1 ) ans += num;
if ( fh ==2 ) ans = ans-num;
if ( fh ==3 ) ans = ans*num;
if ( fh ==4 ) ans = ans/num;
if ( fh ==0 ) ans = num;
flag=0;
fh=3;
m_strLCD = m_strLCD.setNum( ans );
emit LCDChanged( m_strLCD );
}
}
void CCounter::DivCounter() {
int num;
bool ok;
if ( flag !=0 )
{
num = m_strLCD.toInt( &ok , 10 );
if ( fh ==1 ) ans += num;
if ( fh ==2 ) ans = ans-num;
if ( fh ==3 ) ans = ans*num;
if ( fh ==4 ) ans = ans/num;
if ( fh ==0 ) ans = num;
flag=0;
fh=4;
m_strLCD = m_strLCD.setNum( ans );
emit LCDChanged( m_strLCD );
}
}
void CCounter::Culculate() {
int num;
bool ok;
num = m_strLCD.toInt( &ok , 10 );
if ( flag != 0)
{
if ( fh ==1 ) ans += num;
if ( fh ==2 ) ans = ans-num;
if ( fh ==3 ) ans = ans*num;
if ( fh ==4 ) ans = ans/num;
if ( fh ==0 ) ans = num;
fh=0;
m_strLCD = m_strLCD.setNum( ans );
emit LCDChanged( m_strLCD );
}
}
void CCounter::ClearLCDNumber() {
int len = m_strLCD.length();
if( len < DisLenth )
{
flag=1;
fh=0;
ans=0;
m_strLCD.truncate( 0 );
emit LCDChanged( m_strLCD ); // 发射信号
}
}
void CCounter::AddLCDNumber( const QString& str )
{
if (flag == 0) m_strLCD.truncate(0);
int len = m_strLCD.length();
if( len < DisLenth )
{
flag=1;
m_strLCD.insert( len, str );
emit LCDChanged( m_strLCD ); // 发射信号
}
}
void CCounter::DeleteLCDNumber() {
int len = m_strLCD.length();
if( len > 0 )
{
flag=1;
m_strLCD.truncate( len-1 );
emit LCDChanged( m_strLCD ); // 发射信号
}
}
*********************************说明**********************************
InitConnect(void)初始化链接
InitButton(void)绘制按钮
IncCounter()定义“+”按钮函数。得出上次计算结果并将下次计算符号计为“加” SubCounter()定义“-”按钮函数。得出上次计算结果并将下次计算符号计为“减” MulCounter()定义“*”按钮函数。得出上次计算结果并将下次计算符号计为“乘” DivCounter()定义“\”按钮函数。得出上次计算结果并将下次计算符号计为“除” Culculate()定义“=”按钮函数。得出计算结果
ClearLCDNumber()定义“On”按钮函数。重置清空计算器
AddLCDNumber( const QString& str )定义数字按钮。添加数字
DeleteLCDNumber()定义“C”按钮。清除一位数字
>>>CDigitalButton.h<<<
/* *******************************************************
* 文件名:CCounter.h
* 类名:CCounter
* 功能:计算器
* 作者:WNX
* 时间:2011年10月17日
* 版本:0.01
******************************************************* */
#ifndef _CDIGITALBUTTON_H__
#define _CDIGITALBUTTON_H__
#include
#include
class CDigitalButton : public QPushButton {
Q_OBJECT // 使用Signal/Slot
public:
CDigitalButton( const QString& text, QWidget* parent, const char*
name=0 );
QString m_strNum; // 数字按钮显示的数字
public slots: // 插槽
void myClicked();
signals: // 信号
void numChanged( const QString& str ); };
#endif
>>>CDigitalButton.cpp<<<
#include "CDigitalButton.h"
#include
CDigitalButton::CDigitalButton( const QString& text, QWidget* parent, const char*
name )
:QPushButton( text, parent, name ) {
connect( this, SIGNAL( clicked() ), this, SLOT(myClicked()) ); // 连接父类QPushButton::clicked()到子类的myClicked(),
}
// 为的是发射带参数的numChanged( m_strNum )信号,
// 因为重写clicked()似乎不起作用
void CDigitalButton::myClicked()
{
//QMessageBox::information( this, "msg", "before emit" );
emit numChanged( m_strNum );
//QMessageBox::information( this, "msg", "emit returned" );
}
, 实验结果:
实验效果图
三、实验
总结
初级经济法重点总结下载党员个人总结TXt高中句型全总结.doc高中句型全总结.doc理论力学知识点总结pdf
本学期的所有实验均在宿主PC机与PXA270-EP目标板上进行。在实验中,我们先建立硬件实验平台,又建立主机软件开发环境,接着为实验进行各项配置,最后完成了各个实验中的多种功能。值得注意的是,前期的硬件、软件准备必须完整无误地实现,后续的实验才能顺利进行。所以,打基础的工作一定要仔细谨慎。后续实验中虽然给出了驱动程序的框架,仍需要我们自己补充完整,并开动脑筋举一反三,在原代码的基础上进行一定修改以实现新的功能。
通过这学期的实验,我逐步完成了建立实验软件开发平台,搭建实验编译软件环境,在PC上编辑、编译一个应用程序,并且在嵌入式系统上运行和调试它的过程。在实验中,不难发现,编译驱动程序大体框架都是一样的,比如里面的读函数、写函数、ioctl函数、打开、
关闭以及函数模块的初始化并且在超级终端上显示出等。但所不同的是,要根据不同的实验要求修改名称,并且对其中必要的部分进行修改。
除此之外,我认为很多基础知识对实验的进行也起着非常大的作用,例如数码管的显示原理。在掌握了基础知识之后,上机的过程会显得相对简单,尤其是代码框架已经给出,我
们所以需要做的就是根据需要稍作改动来得到我们想要的结果。
之后,我们又进行了更加深入的应用试验,如人机接口方面的键盘驱动实验、LCD控制实验和触摸屏数据采集与控制实验,应用方面的多线程应用实验等。由于涉及到嵌入式实验板的开发、模型化Qt编程,我们在之前实验基础上自己动手编写了程序,对算法和开发环境有了更深入的掌握,在自我与互相学习中解决了许多问题,受益匪浅。
整个实验让我了解了一套完整的嵌入式系统驱动程序开发的全过程,学到的内容非常丰富,相信在学习了这些内容后,在今后的学习工作中接触到类似内容,我不会感到无从下手,而是能够有条不紊,得心应手。