嵌入式程序实验报告

2024-09-05 版权声明 我要投稿

嵌入式程序实验报告(精选4篇)

嵌入式程序实验报告 篇1

一实验目的

1、了解和掌握交叉编译模式和方法;

2、熟悉和掌握Linux简单程序设计。

二实验环境

预装Fedora10_A8_Linux的pc机一台,CVT-A8嵌入式实验箱一台(已构建嵌入式Linux系统),以太网线一根,交叉编译工具链。

三实验步骤

1、连接主机和目标板;(三根线,注意网线和串口线是否连接正常)

2、安装交叉编译器arm-linux-gcc,并配置环境。a)在命令行中输入arm-linux-后按tab键,如果命令能够补齐,说明里面已经有交叉编译工具了,环境变量已经设置好,那接下来的步骤,可以作为参考。如果不能补齐,则把电脑“E:cvtechCVT-A8-III Linux光盘Linux系统及应用源码”目录下的“4.3.3.tar.gz”文件拷贝到Fedora10的/usr/local目录下

b)转到文件夹/usr/local

cd /usr/local

c)解压交叉编译工具链

tar-vzxf4.3.3.tar.gz cd 4.4.3/bin 执行pwd命令得到这个目录的绝对路径,用右键复制这个路径,这个路径一般为/usr/local/4.3.3/bin。

d)打开环境变量设置脚本文件

vi ~/.bash_profile e)在文件中倒数第几行中,把“/usr/local/4.3.3/bin”添加到PATH环境变量路径的后面,类似于PATH=$PATH:/usr/local/4.3.3/bin $PATH表示原来的环境变量路径,添加的/usr/local/4.3.3/bin部分表示在原来的环境变量PATH中添加此交叉编译器的路径

f)vi保存并退出

g)输入命令source ~/.bash_profile使环境变量路径生效

h)在任意目录下输入arm-linux-gcc后回车,如果是arm-linux-gcc no input file表示配置成功,或者仅输入“arm-linu”之后按TAB键看是否能补齐arm-linux-gcc命令,如果能够补齐,说明交叉编译工具链的环境变量设置成功。

3,Linux简单程序设计

a)使用vi等编辑器编写一个简单程序,比如输出“hello world”,实现a+b等C语言程序。

b)在命令行中使用gcc编译器编译并运行程序;使用file命令查看编译后的可执行文件信息。

c)使用交叉编译器arm-linux-gcc编译并运行程序,记录结果;使用file命令查看交叉编译后的可执行文件信息。

d)将交叉编译得到的可执行文件通过tftp下载到目标机,在目标机上执行,记录结果

Cd: Vi:

gcc –o.c:

四实验思考

1、为什么要使用交叉编译模式?

由于嵌入式系统资源匮乏,一般不能像PC一样安装本地编译器和调试器,不能在本地编写、编译和调试自身运行的程序,而需借助其它系统如PC来完成这些工作,这样的系统通常被称为宿主机。宿主机通常是Linux系统,并安装交叉编译器、调试器等工具;宿主机也可以是Windows系统,安装嵌入式Linux集成开发环境。在宿主机上编写和编译代码,通过串口、网口或者硬件调试器将程序下载到目标系统里面运行。所谓的交叉编译,就是在宿主机平台上使用某种特定的交叉编译器,为某种与宿主机不同平台的目标系统编译程序,得到的程序在目标系统上运行而非在宿主机本地运行。ARM上可以运行操作系统,所以用户完全可以将ARM当做计算机来使用,理论上也可以在ARM上使用本地的编译器来编译程序.但是,编译器在编译程序时,会产生大量的中间文件,这会占用很大的内存和磁盘空间,且对CPU处理速度要求较高,比如S3C2440A内存、磁盘空间只有几十到100多兆,CPU只有400-500MHz,完全达不到编译程序的要求.所以,在进行ARM-linux嵌入式开发时必须在PC机(x86结构)上编译出能够运行在ARM上的程序,然后再将程序下载到ARM中来运行.这就用到了交叉编译器.要进行交叉编译,用户需要在主机平台上安装对应的交叉编译工具链(cross compilation tool chain),然后用这个交叉编译工具链编译用户的源代码,最终生成可在目标平台上运行的代码.交叉编译工具链可以从网上下载,也可以自己制作.但编译器不是万能的,受版本限制,编译某些程序时会报错.常见的交叉编译工具链有:

(1)Cross-2.95.3 tar: 该版本较早,除了编译vivi外一般不使用.(2)arm920t-eabi.tgz: 4.1.2版本的编译器,支持eabi,可以编译TX2440A开发板上的所有程序.(3)arm-linux-gcc: 4.3.2版本的编译器,支持eabi,是最常见的交叉工具链.2、gcc和交叉编译工具生成的可执行文件有什么不同?

Gcc:GCC(GNU Compiler Collection,GNU编译器套件),是由 GNU 开发的编程语言编译器。它是以GPL许可证所发行的自由软件,也是 GNU计划的关键部分。GCC原本作为GNU操作系统的官方编译器,现已被大多数类Unix操作系统(如Linux、BSD、Mac OS X等)采纳为标准的编译器,GCC同样适用于微软的Windows。[2] GCC是自由软件过程发展中的著名例子,由自由软件基金会以GPL协议发布。

GCC 原名为 GNU C 语言编译器(GNU C Compiler),因为它原本只能处理 C语言。GCC 很快地扩展,变得可处理 C++。后来又扩展能够支持更多编程语言,如Fortran、Pascal、Objective-C、Java、Ada、Go以及各类处理器架构上的汇编语言等,所以改名GNU编译器套件(GNU Compiler Collection)。

交叉编译工具:在一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码。

可执行文件(executable file)指的是可以由操作系统进行加载执行的文件。在不同的操作系统环境下,可执行程序的呈现方式不一样。

交叉编译工具可以简单地理解为在电脑上编译,生成的可执行文件在开发板上运行。交叉编译工具是根据开发板芯片的体系结构制作的,这与开发板上的芯片指令系统有关。arm-linux-gcc只是在编译时根据arm芯片的环境来生成可执行文件,生成的可执行文件必须移植到开发板上才能运行。

3、比较可执行文件在主机和目标板上运行的不同,理解交叉编译的含义。执行文件在主机和目标板上运行的不同:

宿主机和开发板可通过网络连接, 宿主机将会包含开发板所需的编译环境, 程序可在宿主机上编译完成后, 传递到开发板上执行, 而在开发板上不会包含编译环境, 只会有执行环境,所以两者的运行不同。

在windows操作系统下,可执行程序可以是.exe文件.sys文件.com等类型文件。

Linux可执行文件格式为ELF即Executable and Linkable Format。格式: ELF header program header table.txt.rodata.data Section header table 交叉编译含义:

交叉编译这个概念的出现和流行是和嵌入式系统的广泛发展同步的。我们常用的计算机软件,都需要通过编译的方式,把使用高级计算机语言编写的代码(比如C代码)编译(compile)成计算机可以识别和执行的二进制代码。比如,我们在Windows平台上,可使用Visual C++开发环境,编写程序并编译成可执行程序。这种方式下,我们使用PC平台上的Windows工具开发针对Windows本身的可执行程序,这种编译过程称为native compilation,中文可理解为本机编译。然而,在进行嵌入式系统的开发时,运行程序的目标平台通常具有有限的存储空间和运算能力,比如常见的 ARM平台,其一般的静态存储空间大概是16到32MB,而CPU的主频大概在100MHz到500MHz之间。这种情况下,在ARM平台上进行本机编译就不太可能了,这是因为一般的编译工具链(compilation tool chain)需要很大的存储空间,并需要很强的CPU运算能力。为了解决这个问题,交叉编译工具就应运而生了。通过交叉编译工具,我们就可以在CPU能力很强、存储空间足够的主机平台上(比如PC上)编译出针对其他平台的可执行程序。4.你认为做好本实验应该注意哪些方面?

在做本实验时首先应该做好预习工作,在网上或者书本上查相关资料,了解交叉编译模式和方法,可以提前练习linux的程序设计流程,做一个小的练习,这样在试验中就会更加流畅。在做实验中,应该好好学习助教的讲解,并做好笔记,防止助教讲完就忘记,结果又会遇到一些本来可以自己解决的问题。听完助教讲解后,加上之前的预习,再按照操作一步步完成,一般都不会有问题了。

五实验心得

嵌入式系统实验报告 篇2

班 级: 学 号: 姓 名: 成 绩: 指导教师:

1.实验一

1.1 实验名称

博创UP-3000实验台基本结构及使用方法

1.2 实验目的

1.学习嵌入式系统开发流程。

2.熟悉UP-net3000实验平台的核心硬件电路和外设。

3.增加对各个外设的了解,为今后各个接口实验打下基础。

1.3 实验环境

博创UP-NETARM3000 嵌入式开发平台

1.4 实验内容及要求

(1)嵌入式系统开发流程概述

(2)熟悉UP-net3000实验平台的核心硬件电路和外设(3)ARM JTAG的安装与使用

(4)通过操作系统自带的通讯软件超级终端,检验各个外设的工作状态(5)通过本次课程对各个外设的了解,为今后各个接口实验打下基础

1.5 实验设计与实验步骤

1.硬件安装 2.软件安装

(1)超级终端:

运行Windows 系统下的超级终端(HyperTerminal)应用程序,新建一个通信终端;在接下来的对话框中选择 ARM开发平台实际连接的PC机串口;完成新建超级终端的设置以后,可以选择超级终端文件菜单中的保存,将当前设置保存为一个特定超级终端到桌面上,以备后用。

(2)JTAG 驱动程序的安装:

执行armJtag目录下armJtagSetup.exe程序,选择安装目录,安装 JTAG 软件。

1.6 实验过程与分析

(1)了解嵌入式系统开发流程(2)对硬件的安装(3)对软件的安装

1.7 实验结果总结

通过本次实验对嵌入式系统开发流程进行了了解,并且对硬件环境和软件环境进行了安装配置,通过本次实验对以后的接口实验打了基础。

1.8 心得体会

通过本次实验对嵌入式实验有了初步的了解,对基本开发流程也有了初步的了解。

2.实验二

2.1 实验名称

ADS1.2软件开发环境使用方法

2.2 实验目的

熟悉ADS1.2开发环境,学会 ARM仿真器的使用。使用 ADS 编译、下载、调试并跟踪一段已有的程序,了解嵌入式开发的基本思想和过程。

2.3 实验环境

(1)ADS1.2开发环境

(2)博创UP-NETARM3000 嵌入式开发平台(3)PC(4)串口线

2.4 实验内容及要求

本次实验使用ADS 集成开发环境,新建一个简单的工程文件,并编译这个工程文件。学习ARM仿真器的使用和开发环境的设置。下载已经编译好的文件到嵌入式控制器中运行。学会在程序中设置断点,观察系统内存和变量,为调试应用程序打下基础。

2.5 实验设计与实验步骤

(1)运行ADS1.2开发环境(2)新建工程文件(3)编译工程文件

(4)下载编译好的文件到嵌入式控制器中运行

2.6 实验过程与分析

(1)实现Hello World!

最终在输出了Hello World(2)编程实现ARM 和计算机之间的串行通讯

实现了串口通信,用ARM监视串口,接收到的字符串由ARM通过串口发送给超级终端,最终在超级终端上显示了按下的键。学习了串行通讯原理,了解串行通讯控制器,阅读ARM 芯片文档,掌握ARM 的UART相关寄存器的功能,熟悉ARM 系统硬件的UART 相关接口。

2.7 实验结果总结

对ADS 1.2开发环境使用和AXD Debugger使用方法有了初步的了解,基本成功运行了编译好的工程文件。

2.8 心得体会

学习了ADS1.2开发环境的使用方法和调试方法。使用 ADS 编译、下载、调试并跟踪一段已有的程序,了解了嵌入式开发的基本思想和过程。

3.实验三

3.1 实验名称

键盘控制方法及LED驱动设计

3.2 实验目的

熟悉ZLG7289芯片的内部结构,掌握用ZLG7289驱动键盘和LED的方法,掌握ARM汇编语言和C语言的编程方法编写出一段程序,要求能在LED上显示出小键盘上按下的4位数字。

3.3 实验环境

(1)ADS1.2开发环境

(2)博创UP-NETARM3000 嵌入式开发平台(3)PC(4)串口线

3.4 实验内容及要求

通过ZLG7289芯片驱动17键的键盘和8个共阴极LED,将按键值在LED 上显示出来。

3.5 实验设计与实验步骤

(1)新建工程,将“Exp3键盘及LED 驱动实验”中的文件添加到工程。(2)定义ZLG7289 寄存器(3)编写ZLG7289 驱动函数(4)定义键盘映射表(5)定义键值读取函数

(6)编写主函数

3.6 实验过程与分析

(1)定义ZLG7289寄存器 #define ZLG7289_CS #define ZLG7289_KEY #define ZLG7289_ENABLE()do{ZLG7289SIOBand=rSBRDR;ZLG7289SIOCtrl=rSIOCON;rSIOCON=0x31;rSBRDR=0xff;rPDATB&=(~ZLG7289_CS);}while(0)#define ZLG7289_DISABLE()do{rPDATB|=ZLG7289_CS;rSBRDR=ZLG7289SIOBand;rSIOCON=ZLG7289SIOCtrl;}while(0)(2)主函数中需要在开始初始化zlg7289。编写驱动和键值映射之后,在一个循环里面从键盘中读取按键的号码,根据键值映射读出按键的值。然后在主函数中,将读出的按键值在数码管上显示出来。

(3)Main函数的主要功能部分,GetKey()函数得到按键值是调用zlg7289获取键盘事件和核心。

3.7 实验结果总结

通过实验最终LED灯上能显示数字,即实现了通过键值控制LED灯

3.8 心得体会

通过本次实验对ZLG7289芯片的内部结构有了更进一步的了解,对ZLG7289驱动键盘和LED的方法也更进一步的进行了学习。

4.实验四

4.1 实验名称

电机转动控制及中断实验

4.2 实验目的

(1)熟悉ARM本身自带的六路即三对PWM,掌握相应寄存器的配置

(2)编程实现 ARM系统的PWM 输出和I/O 输出,前者用于控制直流电机,后者用于控制步进电机。

(3)了解直流电机和步进电机的工作原理,学会用软件的方法实现步进电机的脉冲分配,即用软件的方法代替硬件的脉冲分配器。

(4)掌握带有PWM 和I/O 的CPU 编程实现其相应功能的主要方法。

4.3 实验环境

(1)ADS1.2开发环境

(2)博创UP-NETARM3000 嵌入式开发平台(3)PC(4)串口线

4.4 实验内容及要求

学习步进电机和直流电机的工作原理,了解实现两个电机转动对于系统的软件和硬件要求。学习ARM知识,掌握PWM 的生成方法,同时也要掌握I/O 的控制方法。

(1)编程实现ARM芯片的一对PWM 输出用于控制直流电机的转动,通过A/D 旋钮控制其正反转及转速

(2)编程实现ARM的四路I/O 通道实现环形脉冲分配用于控制步进电机的转动,通过A/D 旋钮转角控制步进电机的转角。

(3)通过超级终端来控制直流电机与步进电机的切换。4.5 实验设计与实验步骤

(1)新建工程,将“电机转动控制实验”中的文件添加到工程(2)编写直流电机初始化数(MotorCtrl.c)(3)控制直流电机与步进电机

4.6 实验过程与分析

(1)通过把从串口中得到控制信息的代码修改成从zlg7289芯片中读取小键盘信息,从而利用试验台的小键盘来控制步进电机和直流电机的切换

(2)A/D转换可以把电信号转换成数字信号来控制电机的转速。for(;;)

{ loop:

//if((rUTRSTAT0 & 0x1))//有输入,则返回

if(rPDATG&ZLG7289_KEY)//17键小键盘控制电机

{

*Revdata=RdURXH0();

goto begin;

}

Delay(10);ADData=GetADresult(0);

if(abs(lastADData-ADData)<20)

goto loop;Delay(10);count=-(ADData-lastADData)*3;

//(ADData-lastADData)*270/1024为ad旋钮转过的角度,360/512为步距角,//由于接了1/8减速器,两者之商再乘以8为步进电机相应转过的角度

if(count>=0)

{//转角大于零

for(j=0;j

{

for(i=0;i<=7;i++)

{

SETEXIOBITMASK(stepdata[i], 0xf0);

Delay(200);

}

}

}

else

{//转角小于零

count=-count;

for(j=0;j

{

for(i=7;i>=0;i--)

{

SETEXIOBITMASK(stepdata[i], 0xf0);

Delay(200);

}

}

} lastADData=ADData;

} }

(3)S3C44B0X 具有6 个16bit定时器,每个定时器可以基于中断模式或 DMA模式运行。在定时中断服务程序中写需要定时处理的程序,每隔一段时间就会运行一次。

4.7 实验结果总结

利用A/D转换器实现了对直流电机和步进电机的控制,利用实验设备上自带的小键盘实现了A/D转换器对两个电机控制的切换。

4.8 心得体会

通过本次实验,熟悉了ARM自带的六路(三对)PWM,并对直流电机和步进电机的工作原理有了进一步的了解。

5.实验五

5.1 实验名称

LCD驱动及触摸屏实验

5.2 实验目的

掌握LCD显示原理及显示驱动的嵌入式系统编程实现方法;学习基于ARM的LCD 显示驱动控制方法,通过对ARM 内置的LCD 控制器进行编程实现驱动LCD显示屏;学习触摸屏基本原理,理解触摸屏的输出标定以及与LCD 显示器配合的过程,编程对触摸屏进行控制。

5.3 实验环境

(1)ADS1.2开发环境(2)博创UP-NETARM3000 嵌入式开发平台(3)PC(4)串口线

5.4 实验内容及要求

(1)学习LCD显示器的基本原理,理解其驱动控制方法(2)编程对触摸屏进行控制,实现:

1.点击触摸屏上两点后,两点之间画出一条直线。2.点击触摸屏并在其上移动,显示移动轨迹

(3)编程实现总线方式驱动模块的LCD和ARM内置的LCD控制器来驱动LCD

5.5 实验设计与实验步骤

(1)新建工程

(2)定义有关常量与宏

#define LCDWIDTH 320 #define LCDHEIGHT 240 U32* pLCDBuffer16=(U32*)0xc000000;// 一级缓存指针 U32 LCDBuffer[LCDHEIGHT][LCDWIDTH];//二级缓存(3)编写LCD 初始化函数(4)编写LCD 刷新函数(5)编写主函数

5.6 实验过程与分析

(1)通过不断刷新的方式获得LCD液晶屏幕的动画。即刷新函数将二级缓存LCDBuffer 的数据由32 位彩色图形信息转换成8 位256 色的图形信息,然后放到pLCDBuffer16指向的一级缓存。

(2)触摸屏的先得到触屏输出的电信号的值,然后转换为实际的屏幕坐标,再根据动作来决定如何处理缓存信息,刷新LCD。

LCD二级缓存矩阵: for(i=0;i<9;i++){ switch(i){ case 0: jcolor=0x00000000;// 黑色 break;case 1: jcolor=0x000000e0;// 红色 break;case 2: jcolor=0x0000d0e0;// 橙色 break;case 3: jcolor=0x0000e0e0;// 黄 break;case 4: jcolor=0x0000e000;// 绿色 break;case 5: jcolor=0x00e0e000;// 青色 break;case 6: jcolor=0x00e00000;// 蓝色 break;case 7: jcolor=0x00e000e0;// 紫色 break;case 8: jcolor=0x00e0e0e0;// 白色 break;} for(k=0;k<240;k++)for(j=i*32;j

5.7 实验结果总结

本次实验由于坐标设定的问题并没有成功实现触摸痕迹的显示,但在测试过程中,在触摸屏上点击或移动时会在超级终端上有显示。

5.8 心得体会

虽然本次实验不太成功实现,但对LCD屏幕和触摸屏的工作原理有了进一步的了解,更好的掌握了LCD显示原理及显示驱动的嵌入式系统编程实现方法。

6.实验六

6.1 实验名称

ucos-II裁剪实验

6.2 实验目的 掌握μcos-II裁剪的基本原理与嵌入式编程实现方法;学习如何根据具体情况对μcos-II操作系统进行裁剪,从而得到即满足需要,又非常紧凑的应用软件系统。

6.3 实验环境

(1)ADS1.2开发环境

(2)博创UP-NETARM3000 嵌入式开发平台(3)PC(4)串口线

6.4 实验内容及要求

(1)通过对μcos-II配置文件(OS_CFG.H)中相关的配置常量进行设置,实现对μcos-II的裁剪

(2)给出裁剪的详细过程与裁剪结果说明,并生成裁剪后的操作系统文件。

6.5 实验设计与实验步骤

(1)新建工程,将ucosII移植的文件添加到工程中。

(2)编辑os_cfg.h头文件。

(3)将裁减后的系统所需用到的功能宏定义配置常量置为1,实现系统的裁减。(4)编译生成新的ucosII系统。

6.6 实验过程与分析

(1)配置功能常量,将裁剪后的系统需要用到的功能配置常量设为1(2)裁减信号量数据(3)配置数据结构

OS_MAX_TASKS,若程序中用到了三个任务,则该值的最小值为3 OS_LOWEST_PRIO设置程序中最低任务的优先级

OS_TASK_IDLE_STK_SIZE设置UC/OS操作系统中空闲任务堆栈的容量 OS_TASK_STAT_STK_SIZE设定统计任务的任务堆栈容量

6.7 实验结果总结

通过本次实验,裁减了系统,修改了某些数据结构相关的常量,节省了内存空间

6.8 心得体会

通过本次实验主要学习到了如何根据具体情况对μcos-II操作系统进行裁剪,从而得到即满足需要,又非常紧凑的应用软件系统。

7.实验七

7.1 实验名称

ucos-II移植实验

7.2 实验目的

了解µC/OS-II 内核的主要结构,掌握ARM的C语言和汇编语言的编程方法;了解ARM7处理器结构;掌握将µC/OS-II 内核移植到ARM 7 处理器上的基本原理与嵌入式编程实现方法

7.3 实验环境

(1)ADS1.2开发环境

(2)博创UP-NETARM3000 嵌入式开发平台(3)PC(4)串口线

7.4 实验内容及要求

(1)将µC/OS-II 内核移植到ARM7 微处理器S3C44B0上。(2)编写两个简单任务,在超级终端上观察两个任务的切换。

7.5 实验设计与实验步骤

(1)新建工程

(2)该实验的文件分为两类,其一是 STARTUP目录下的系统初始化、配置等文件,其二是uCOS-II 的全部源码,arch 目录下的3 个文件是和处理器架构相关的3.定义驱动函数(tchscr.c)(3)设置os_cpu.h 中与处理器和编译器相关的代码(4)用C 语言编写6 个操作系统相关的函数(5)用汇编语言编写4 个与处理器相关的函数

(6)编写一个简单的多任务程序来测试一下移植是否成功(7)编译并下载移植后的uCOS-II

7.6 实验过程与分析

(1)首先需要对相关寄存器做详细的设定(2)用汇编语言编写与处理器相关的函数(3)用分时的方法同时运行两个任务

OS_STK TaskName_Stack[STACKSIZE]={0, };//任务堆栈 void TaskName(void *Id);//任务函数

#define TaskName_Prio N //任务优先级

在main()函数中调用OSStart()函数之前用下列语句创建任务: OSTaskCreate(TaskName,(void*)0,(OS_STK*)&TaskName_Stack[STACKSIZE-1], TaskName_Prio);OSTaskCreate()函数的原型是:

INT8U OSTaskCreate(void(*task)(void *pd), void *p_arg, OS_STK *ptos, INT8U prio);(4)编写任务函数

7.7 实验结果总结

通过实验达到了ucosII系统移植的目的,并编写了一个简单的多任务程序,分时运行。

7.8 心得体会

通过本次实验了解了µC/OS-II 内核的主要结构,掌握了ARM的C语言和汇编语言的编程方法。

8.实验八

8.1 实验名称

各接口模块相互衔接综合实验

8.2 实验目的

(1)回顾串口、键盘、LED接口、A/D、电机转动、定时器中断、LCD接口及触摸屏驱动控制等接口模块驱动设计及开发方法

(2)综合应用以上全部或者部分模块,实现一个嵌入式综合应用系统,要求至少用到8个模块中的5个

8.3 实验环境

(1)ADS1.2开发环境

(2)博创UP-NETARM3000 嵌入式开发平台(3)PC(4)串口线

8.4 实验内容及要求

(1)综合应用串口、键盘、LED接口、A/D、电机转动、定时器中断、LCD接口及触摸屏驱动控制等全部或者部分模块(2)实现一个嵌入式综合应用系统,要求至少用到8个模块中的5个,尽量使综合应用系统具备合理的功能。

8.5 实验设计与实验步骤

(1)运行ADS1.2开发环境(2)新建工程文件

(3)将综合实验中用到的文件放到这个工程文件中(4)下载编译好的文件到嵌入式控制器中运行

8.6 实验过程与分析

(1)本次实验设计主要是通过中断来实现,设定了flag=1,2,3,4,5,6六个标志位,对应不同的键值来实现功能的切换

(2)通过num/lock键来控制直流电机(3)通过“/”键来控制步进电机

(4)通过“*”键来控制屏输出“hello world”(5)通过“+”键来实现LED灯的计时

(6)通过“DEL”键来实现清屏和LED灯的清除

(7)通过“enter”键来进入到键值控制LED显示的功能

8.7 实验结果总结

实验最终能实现5个功能的切换,但不足的是未涉及到触摸屏的设计,并且最后的键值控制LED灯不能实现正常的中断跳转。

8.8 心得体会

通过本次综合性的实验来综合之前做的串口、键盘、LED接口、A/D、电机转动、定时器中断、LCD接口及触摸屏驱动控制实验,回顾了之前的知识,对整体的运用有了进一步的了解,但是实验结果仍有很多的不足,需要改进。

9.实验总结与心得体会

邝坚_北邮嵌入式实验报告 篇3

一、实验要求

题目:支持消息驱动模式的实时软件框架

目的:在充分理解嵌入式处理器特点、RTOS 及强实时嵌入式系统软件设计规范的基础上,构建自己的实时系统软件框架基本功能,并在其上自拟应用(如部分模拟TCP 的C/S两端通信流程),测试软件框架的相关功能。

环境:VxWorks 的VxSim 仿真环境或2440(ARM920T)内容: 必选功能:

1.消息驱动的Task 统一框架,包含统一消息格式定义及使用规范; 2.支持消息驱动模式的软定时器的机制; 3.Task 启动同步功能;

4.体现前次实验中实现的自定义内存管理机制,最大限度降低外部碎片对系统可靠性的威胁。

可选功能(加分):

其它有利于实时处理的有效机制,如:无信号量(互斥)支持的临界资源访问方式,zero copy 等;

二、实现的功能

1.消息驱动的Task 统一框架,包含统一消息格式定义及使用规范; STATUS Task(){ Initialization(MBox, Data Structure, Timer, etc.)Forever{ MsgReceive If(…){ …… }else if(…){ …… } ……

} } typedef struct _MESSAGE { int mType;

/* 消息类型 0:timer->client *1:client->server 2:server->client*/ int mSendId;/* 发送任务的MESSAGE ID */ int mRecvId;/* 接收任务的MESSAGE ID */ int mData;/* 消息中传递的数据 */ }MESSAGE;2.支持消息驱动模式的软定时器的机制;

/* timer(id)向客户端消息队列定时发送的定时器*/ STATUS timer(int id){ MESSAGE* txMsg;/* 用于从消息队列中接收消息 */ int tick;/*创建一个定时,用于提醒发送者任务定时发送消息*/ tick=sysClkRateGet();semTake(semSynStart,WAIT_FOREVER);FOREVER {

taskDelay((int)(tick*DELAY_SECOND));txMsg =(MESSAGE*)memMalloc(MAX_MSG_LEN);txMsg->mType = 0;txMsg->mSendId = MID_TIMER(id);txMsg->mRecvId = MID_CLIENT(id);txMsg->mData = 0;printf(“tTimer%d send message to tClient%d!n”,id,id);if(msgQSend(msgQIdClient[id],(char*)&txMsg,MAX_MSG_LEN,WAIT_FOREVER,MSG_{ return(ERROR);} PRI_NORMAL)== ERROR)

} } 3.Task 启动同步功能;

由manager()创建的任务优先级最高,先创建timer()、server()、client()的任务,让他们都在等待信号量semSynStart而被阻塞,最后创建manager()的任务,占据CPU,等待其他所有任务都被阻塞,解锁所有等待信号量的任务,让它们同时启动。/* progStart()启动实例程序*/ STATUS progStart(void){

int id;/* 用来区分不同的定时器或者客户任务 */ mallocPtr=&sysMalloc;mallocPtr->frontBlock = 0;return(OK);

initialPtr = initial();tidServer = tidManager = 0;for(id = 0;id < NUM_CLIENT;id++){ tidClient[id] = 0;} for(id = 0;id < NUM_TIMER;id++){

} /* 创建消息队列 */ msgQIdServer = msgQCreate(MAX_MSGS, MAX_MSG_LEN, MSG_Q_FIFO|MSG_Q_EVENTSEND_ERR_NOTIFY);if(msgQIdServer == NULL){

} for(id = 0;id < NUM_CLIENT;id++){

} semSynStart = semBCreate(SEM_Q_FIFO | SEM_EVENTSEND_ERR_NOTIFY,SEM_EMPTY);semMalloc = semBCreate(SEM_Q_PRIORITY,SEM_FULL);semFree = semBCreate(SEM_Q_PRIORITY,SEM_FULL);/* 创建任务 */ tidServer = taskSpawn(“tServer”, 220, 0, STACK_SIZE,(FUNCPTR)server,0,0,0,0,0,0,0,0,0,0);for(id = 0;id < NUM_CLIENT;id++){

char tempName[20];sprintf(tempName, “tClient%d”, id);tidClient[id] = taskSpawn(tempName, 210, 0, STACK_SIZE, msgQIdClient[id] = msgQCreate(MAX_MSGS, MAX_MSG_LEN, if(msgQIdClient[id] == NULL){ return(ERROR);} MSG_Q_FIFO|MSG_Q_EVENTSEND_ERR_NOTIFY);return(ERROR);tidTimer[id] = 0;(FUNCPTR)client,id,0,0,0,0,0,0,0,0,0);} for(id = 0;id < NUM_TIMER;id++){

} tidManager = taskSpawn(“tMannager”, 200, 0, STACK_SIZE,(FUNCPTR)manager,0,0,0,0,0,0,0,0,0,0);printf(“programe start!n”);return(OK);} /* manager()管理进程,实现task同步*/ STATUS manager(){ int id;while(taskIsSuspended(tidServer)|| taskIsReady(tidServer))

{ while(taskIsSuspended(tidClient[id])|| taskDelay(10);taskIsReady(tidClient[id]))

} for(id = 0;id < NUM_TIMER;id++){

} semFlush(semSynStart);return(OK);} /* server()处理来自各个客户任务的消息*/ STATUS server(void){ …… while(taskIsSuspended(tidTimer[id])|| taskIsReady(tidTimer[id]))taskDelay(10);taskDelay(10);for(id = 0;id < NUM_CLIENT;id++)char tempName[20];sprintf(tempName, “tTimer%d”, id);tidTimer[id] = taskSpawn(tempName, 230, 0, STACK_SIZE,(FUNCPTR)timer,id,0,0,0,0,0,0,0,0,0);semTake(semSynStart,WAIT_FOREVER);FOREVER { } return(OK);} /* timer(id)向客户端定时发送的定时器*/ STATUS timer(int id){ ……

semTake(semSynStart,WAIT_FOREVER);FOREVER { } /*client(id)向服务器任务发请求消息*/ STATUS client(int id){ ……

semTake(semSynStart,WAIT_FOREVER);FOREVER { } return(OK);} 4.体现前次实验中实现的自定义内存管理机制,最大限度降低外部碎片对系统可靠性的威胁。

静态内存的数据结构为单链表,采用头插法,申请内存时,修改firstavailable另其指向第二块,将firstavailable指向的头块取出,回收内存时,将回收的块的frontBlock指向第一块,修改firstavailable另其指向回收的块,将回收的块作为第一块,数据结构如下所示: …… ……

} return(OK);…… poolpoolHeadnextfirstavailable blockHeadfrontBlockblockHeadfrontBlockblockHeadfrontBlockblockHeadpoolHeadfirstavailableblockHeadfrontBlockblockHeadfrontBlockblockHeadfrontBlockblockHead 静态分配了含有32个16B块的内存池和含有16个256B块的内存池,如果申请的内存大于256B,调用系统malloc。

/*initial()初始化内存池*/ pool* initial(void){ int i;pool* mem;pool* poolPtr;poolHead* poolHeadPtr;blockHead* blockHeadPtr;

mem=(pool*)malloc(6000);/*分配6000B内存作为内存池*/

/*初始化pool*/ poolPtr =(pool*)mem;poolPtr->poolNum = 2;poolPtr->pool =(poolHead*)((char*)mem + sizeof(pool));/*pool指向申请内存区尾*/

/*初始化pool 1 该内存池分配大小为16B的内存*/ poolHeadPtr =(poolHead*)((char*)mem + sizeof(pool));/*初始化内存池的首地址*/ poolHeadPtr->available = 32;/*初始化可用块数32*/ poolHeadPtr->blockSize = 16;/*块大小16B*/ blockHeadPtr =(blockHead*)((char*)poolHeadPtr+sizeof(poolHead));初始化块的首地址*/ poolHeadPtr->firstavailable = blockHeadPtr;/*初始化第一块可用块的地址*/ poolHeadPtr->next=(poolHead*)((char*)poolHeadPtr + sizeof(poolHeadPtr)

/*+ 32*(sizeof(blockHead)+16));/*next指向第二个内存池 */

blockHeadPtr->poolId =1;blockHeadPtr->frontBlock = 0;

for(i=1;i<32;i++)/*将该内存池划分为32个容量16B的内存块*/ {

址*/ } /*初始化pool 2 该内存池分配大小为256B的内存*/ poolHeadPtr = poolHeadPtr->next;poolHeadPtr->available = 16;/*初始化可用块数16*/ poolHeadPtr->blockSize = 256;/*块大小256*/

blockHeadPtr =(blockHead*)((char*)poolHeadPtr+sizeof(poolHead));

poolHeadPtr->firstavailable = blockHeadPtr;poolHeadPtr->next = 0;

blockHeadPtr->poolId =2;blockHeadPtr->frontBlock = 0;

for(i=1;i<16;i++)/*将该内存池划分为16个容量256B的内存块*/ {

} return(pool*)mem;} blockHeadPtr=(blockHead*)((char*)blockHeadPtr + blockHeadPtr->poolId = 2;/* pool号为2,表示他是256B容量的*/ blockHeadPtr->frontBlock = poolHeadPtr->firstavailable;poolHeadPtr->firstavailable = blockHeadPtr;(sizeof(blockHead)+256));

blockHeadPtr=(blockHead*)((char*)blockHeadPtr + blockHeadPtr->poolId = 1;/* pool号为1,表示他是16B容量的*/ blockHeadPtr->frontBlock = poolHeadPtr->firstavailable;/* 当前首poolHeadPtr->firstavailable = blockHeadPtr;/* 求下一首个可用块地(sizeof(blockHead)+16));/*块的首址移动16加结构体的开销长度*/ 个可用块地址赋给frontBlock */

/*memMalloc()分配内存*/ void* memMalloc(int Size){ void* mem;poolHead* poolHeadPtr;blockHead* blockHeadPtr;

semTake(semMalloc,WAIT_FOREVER);

poolHeadPtr = initialPtr->pool;

if((Size <= 16)&&(poolHeadPtr->available!= 0))/*长度小于16时,分配长度为16的内存空间*/ {

blockHeadPtr = poolHeadPtr->firstavailable;/*首个可用块地址赋给poolHeadPtr->firstavailable = blockHeadPtr->frontBlock;/*改变下poolHeadPtr->available--;/*可用块数减一*/ semGive(semMalloc);分配块的首地址*/ 一第一可用块的地址*/

return(void*)((char*)blockHeadPtr + sizeof(blockHead));/*分配内存时加入块头开销*/ } else if((Size <= 256)&&((poolHeadPtr->next)->available!= 0))

{

} else

{ printf(“n[Warning] : Too large for blocks or the blocks are /*其他情况用系统的内存分配函数malloc分配*/ blockHeadPtr =(poolHeadPtr->next)->firstavailable;(poolHeadPtr->next)->firstavailable = blockHeadPtr->frontBlock;(poolHeadPtr->next)->available--;semGive(semMalloc);return(void*)((char*)blockHeadPtr + sizeof(blockHead));/*长度大于16小于256时,分配长度为256的内存空间*/ exhausted n”);

} } /*memFree()释放内存空间*/ void memFree(void* dataPtr){ char* mem=(char*)dataPtr;poolHead* poolHeadPtr;blockHead* blockHeadPtr;

semTake(semFree,WAIT_FOREVER);

poolHeadPtr = initialPtr->pool;/*恢复内存池首址*/ blockHeadPtr =(blockHead*)((char*)memsizeof(blockHead));Timer0Timer1Timer9ClientMsgQ0ClientMsgQ1……ClientMsgQ9Client0Client1Client9ServerMsgQserver6.zero copy 消息队列存储的是指向消息的指针,从而实现了零拷贝。#define MAX_MSG_LEN sizeof(MESSAGE*)MESSAGE* rxMsg;/* 用于从消息队列中接收消息 */ MESSAGE* txMsg;/* 用于向消息队列中发送消息 */ msgQReceive(msgQIdServer,(char*)&rxMsg,MAX_MSG_LEN,WAIT_FOREVER);

msgQSend(msgQIdClient[mSendId],(char*)&txMsg,MAX_MSG_LEN,WAIT_FOREVER,MSG_PRI_NORMAL);

三、运行结果

在shell中输入progStart,观察VxSim,输入progStop结束。

四、心得

实验中遇到了各种各样的问题,特别是代码调试,对报错的分析,定位错误,但是通过不懈努力,完成了本次实验,让我对课堂上所讲的内容有了更深刻的认识,对嵌入式实时操作系统有了更深的理解。

嵌入式程序实验报告 篇4

电梯原理(+键盘原理+显示器原理+电机原理)??

2、实验解决方案

逻辑判断:再只考虑电梯内部按键的情况下,电梯运行的逻辑为

1、接收到键盘指令

2、判断电梯当前楼层

3、判断当前楼层与目标楼层的差值,引导电机运行

4、电机运行一定时间

5、灯亮提示门已开

6、LCD显示当前所到楼层。

要解决的问题:

1、程序的初始化

2、当前楼层的判断

3、电梯运行状态

4、到达状态(LCD、LED与sound)的设置

初始化:应当先初始化电梯的工作状态,使得电机,显示器,LCD灯以及内部变量都位于电梯在一楼特定状态下。

当前楼层高度:设置变量(state)为当前楼层,初始值默认为1,当电梯运行过后state值发生改变,跟随当前楼层的值。

电梯的运行:电梯的运行状态主要根据变量K的值来判断,K=state-f;f是根据键盘的按键来决定的值,当前楼层与目标楼层的差的正负性(state-f)来判断电机的正反转,差的大小来判断电机运行的时间。

到达状态设置:LED灯的显示方式分别为从北面开始,从左往右根据楼层的高度依次亮灯,模拟电梯对应的楼层的开门。LCD则提示用户已经到达已经到达该楼层。并发出蜂鸣声提醒用户已经到达指定楼层。

3、软件具体设计

初始化

设置init(),???

设置LcdDisplay(),刷新内存等操作,设置当前楼层显示的Bin。设置sound(),根据一定的频率来发出声音。

设置dcmotorclockwise()和dcmotorcounterclockwise(),根据 m_bClockwise 的值是否为真来判断电机的正反转,用echo函数使能运行直流电机。

设置delay(),用来延缓电机停转后LCD与LED的显示和蜂鸣声。设置stopsound()和dcmotorstop(),停止硬件上的操作。运行

设置keyPressEvent(),根据按钮所触发的不同的事件,每个事件赋予了f不同的值,再根据k=state(当前状态)-f(目标楼层)的值,引导直流电机的运行方向以及运行时间,延时关闭电机,并提示声音和灯。

4、调试及结果分析

初始化:运行编写的项目,在最开始的初始化过程中LCD显示了“一楼”,LED显示开一楼门,电机不动作,键盘未接受事件触发,程序初始化完毕。

图4-1.初始化界面

电机运行:接收到键盘触发事件里面变量值的改变,程序良好运行,直流电机运行逆时针指定圈数,LCD显示已经到达5楼,LED灯亮提示5楼门已开,并伴随蜂鸣声提示用户下电梯。

图4-2.运行到5楼

电机运行:接收到键盘触发事件里面变量值的改变,程序良好运行,直流电机运行顺时针指定圈数,LCD显示已经到达3楼,LED灯亮提示3楼门已开,并伴随蜂鸣声提示用户下电梯。

图4-3.运行到3楼

键盘工作有效,直流电机正常运行并且没有明显延迟,LED,LCD,蜂鸣器依顺序执行,完全根据设定的程序运行。

5、个人承担工作

初始化State,f,k接收按键判断k=state-fk>0电机正转k<0电机反转延时|k|倍电机停止发声显示楼层 本人设计以目标楼层和当前楼层为基本判别方法的人机交互架构。主要是以keyPressEvent为主体。调用了 dcmotorcounterclockwise(),dcmotorclockwise(),delay(),sound(),dcmotorstop()等函数。以if为大框架,switch为小框架。KeyPressEvent为触发方式,f为主要变量,k为判断条件。

keyPressEvent(QKeyEvent * e){

switch(e->key())

case Qt::Key_1:

f=1;

break;case Qt::Key_2:

f=2;

break;}

......//诸如此类

k=state-f;//根据k值来判断运行的方式 if(k<0)//电机向上

{

switch(k)

{

case-1:

dcmotorcounterclockwise(2);//电机旋转

delay(1000);//延时

dcmotorstop();//电机停止

sound(100);//发声提示

break;}

......//诸如此类

}

Else{

switch(k)

{

case 1: dcmotorclockwise(2);

delay(1000);

dcmotorstop();

sound(100);

break;}

......//诸如此类

} } state=f;//当前值发生改变

delay(300);stopsound();}//声音停止

6、遇到问题的解决方案

遇到的问题:

1、电梯最初设计为二楼结构,只使用了电机的正反转,后来将电梯扩展为5楼电梯,使用了If和Switch的同时判断。

2、对LED北面灯(north)先亮(1-3楼),西面灯(west)后亮(4-5楼),再执行北面灯(1-3楼)时西面灯不会自动熄灭。问题在于启用灯亮的函数被放在了判断上升楼层高度差K里面,解决方法是将灯的点亮设置为根据state的值(当前楼层)亮,这样既方便显示当前的楼层数,又可对于灯有关闭熄灭。

3、对直流电机的控制改用时间控制,避免了因角度控制,电机旋转对绳缆长度造成的误差。设置了电机旋转的速度 dcmotorcounterclockwise(X),只要控制好时间delay(N)再调用dcmotorstop(),既可停用电机,控制时间远比控制角度来的方便。

7、个人工作自我评估

上一篇:教育局民主评议行风政风工作方案下一篇:高等教育法规案例分析

热门文章
    相关推荐