北邮电子院嵌入式实验报告大四上_北邮嵌入式实验报告
北邮电子院嵌入式实验报告大四上由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“北邮嵌入式实验报告”。
嵌入式实验报告
学院: 电子工程学院
一、实验目的1、了解嵌入式系统及其相关基础知识。
2、了解宿主PC机与PXA270目标版,能正确连接宿主PC机与PXA270目标版。
3、学会在宿主机上安装Linux操作系统——RedHat9.0。、4、学会建立宿主PC机端的开发环境。
5、学会配置宿主PC机端的超级终端。
6、配置宿主PC机端的TFTP服务,并开通此服务。
7、配置宿主PC机端的NFS服务,并开通此服务。
8、学会简单Linux驱动程序的设计。
二、实验内容
(一)基本实验
实验一到六为基础实验,主要是为了在熟悉实验操作平台的同时为后续实验搭建好软、硬件环境,配置好相关的协议、服务。
其中实验一是各个硬件的互联,搭建好了实验的硬件环境。实验二是在宿主PC端安装虚拟机,提供了实验需要的Linux操作系统。实验三是宿主PC端开发环境的安装与配置。
实验四是配置宿主PC机端的超级终端,使PC机与PXA270目标板之间可以通过串口通讯。在每次重启宿主PC机时,都需要重新将超级终端挂载到虚拟机上,挂载之前须通过ifconfig命令查看该机的IP地址,若其已经复位,须用命令:ifconfig eth0 192.168.0.100 up重置宿主PC机的IP地址。挂载虚拟机的代码为:
root ifconfig eth0 192.168.0.50 up mount –o nolock 192.168.0.100:/ /mnt 实验五是配置宿主PC机的TFTP服务。TFTP是简单文件传输协议。每次重启宿主PC机时,都要重启该服务,重启命令为:
service xinetd restart。
实验六是配置宿主PC机端NFS服务。NFS是指网络文件系统,它实现了文件在不同的系统间使用。当使用者想用远端档案时,只需调用“mount”就可以远端系统挂接在自己的档案系统之下。每次重启宿主PC机时,也都要重启该服务,重启命令为: service nfs restart service nfs restart
(二)基本接口实验
实验
十二、简单设备驱动程序
本次实验的目的是让我们动手实践一个简单的字符型设备驱动程序,学习Linux驱动程序构架,学习在应用程序中调用驱动。驱动程序代码及注释为: // 头文件
#include #include #include #include #include #include #include #define SIMPLE_HELLO_MAJOR 96 // 定义主设备号HELLO DEVICE MAJOR #define OURS_HELLO_DEBUG // 定义标识符
#define VERSION “PXA2700EP-SIMPLE_HELLO-V1.00-060530” // 定义版本号 void showversion(void)//显示版本的函数 { printk(“***************************************”);printk(“t %s tn”,VERSION);printk(“***************************************”);}
/*-------read:用于在指定文件描述符中读取数据 file:是文件指针 buf:读取数据缓存区 count:请求传输的字节数 f_ops:文件当前偏移量
当读取标识符OURS_HELLO_DEBUG时,打印信息,然后返回count----------*/ ize_t SIMPLE_HELLO_read(struct file * file ,char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_HELLO_DEBUG
printk(“SIMPLE_HELLO_read[--kernel--]n”);#endif return count;}
/*-----write:用于向打开的文件写数据 file:是文件指针 buf:写入数据缓存区 count:求传输的字节数 f_ops:文件当前偏移量
当读取标识符OURS_HELLO_DEBUG时,打印信息,然后返回count----------*/ ize_t SIMPLE_HELLO_write(struct file * file ,const char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_HELLO_DEBUG
printk(“SIMPLE_HELLO_write[--kernel--]n”);#endif
return count;}
/*-----ioctl:对设备的I/O通道进行管理的函数 inode:设备节点
flip:打开的一个文件
cmd:驱动程序的特殊命令编号 data:接收剩余参数
----------*/ ize_t SIMPLE_HELLO_ioctl(struct inode * inode ,struct file * file, unsigned int cmd, long data){ #ifdef OURS_HELLO_DEBUG
printk(“SIMPLE_HELLO_ioctl[--kernel--]n”);#endif return 0;}
/*----------open:打开函数
inode:打开文件所对应的i节点,获取从设备号 flip:打开的一个文件
open()方法最重要的是调用了宏MOD_INC_USE_COUNT,这个宏主要用来使驱动程序使用计数器,避免不正确卸载程序
----------*/ ize_t SIMPLE_HELLO_open(struct inode * inode ,struct file * file){ #ifdef OURS_HELLO_DEBUG
printk(“SIMPLE_HELLO_open[--kernel--]n”);#endif MOD_INC_USE_COUNT;return 0;}
/*----------released:关闭函数
Inode:打开文件所对应的i节点,主要获取从设备号 flip:打开的一个文件
release()方法最重要的是调用了宏MOD_DEC_INC_USE_COUNT,这个宏主要用来减少驱动程序使用计数器
----------*/ ize_t SIMPLE_HELLO_release(struct inode * inode ,struct file * file){ #ifdef OURS_HELLO_DEBUG
printk(“SIMPLE_HELLO_release[--kernel--]n”);#endif MOD_DEC_INC_USE_COUNT;return 0;}
struct file_operations HELLO_ops ={ // SIMPLE_HELLO设备向系统注册
open: SIMPLE_HELLO_open, read: SIMPLE_HELLO_read, write: SIMPLE_HELLO_write, ioctl: SIMPLE_HELLO_ioctl, release: SIMPLE_HELLO_release, };
/*----------INIT:驱动程序初始化
devfs_register_chrdev(SIMPLE_HELLO_MAJOR,“hello_serial_ctl”,& HELLO_ops)最为主要
devfs_register_chrdev注册设备驱动程序,包括主设备号、驱动程序名、结构体指针----------*/ static int __init HW_ HELLO_init(void){ int ret =-ENODEV;
ret = devfs_register_chrdev(SIMPLE_HELLO_MAJOR, “hello_serial_ctl”,& HELLO_ops);
showversion();
if(ret
{
printk(“pxa270 init_module failed with %d n[--kernel--]”,ret);
}
else
{
printk(“pxa270 hello_driver register succe!![--kernel--]n”);
} return ret;}
static int __init pxa270_ HELLO_init(void)//模块初始化函数,调用HW_ HELLO_init 函数
{ int ret =-ENODEV;
#ifdef OURS_HELLO_DEBUG
printk(“pxa270_ HELLO_init[--kernel--]n”);
#endif ret = HW_ HELLO_init();if(ret)return ret;return 0;}
/*----------模块卸载函数
devfs_unregister_chrdev(SIMPLE_HELLO_MAJOR,“hello _ctl”)最为主要 devfs_unregister_chrdev卸载设备驱动程序,包括主设备号、驱动程序名
----------*/ static void __exit cleanup_ HELLO_ctl(void){ #ifdef OURS_HELLO_DEBUG
printk(“cleanup_HELLO_ctl[--kernel--]n”);#endif devfs_unregister_chrdev(SIMPLE_HELLO_MAJOR, “hello_ctl”);}
MODULE_DESCRIPTION(“simple hello driver module”);//描述信息 MODULE_AUTHOR(“liduo”);
//驱动程序作者姓名 MODULE_LICENSE(“GPL”);module_init(pxa270_HELLO_init);
//指定驱动程序初始化函数 module_exit(cleanup _HELLO_ctl);
//指定驱动程序卸载函数
Makefile文件代码:
#TOPDIR:=$(shell cd..;pwd)TOPDIR:=.KERNELDIR=/pxa270_linux/linux INCLUDEDIR=$(KERNELDIR)/include CROSS_COMPILE=arm-linux-
AS =$(CROSS_COMPILE)as LD =$(CROSS_COMPILE)ld CC =$(CROSS_COMPILE)gcc CPP =$(CC)-E AR =$(CROSS_COMPILE)ar NM =$(CROSS_COMPILE)nm STRIP =$(CROSS_COMPILE)strip OBJCOPY=$(CROSS_COMPILE)objcopy OBJDUMP=$(CROSS_COMPILE)objdump
CFLAGS+=-I..CFLAGS+=-Wall –O –D_KERNEL_-DMODULE –I$(INCLUDEDIR)
TARGET = pxa270_hello_drv.o modules: $(TARGET)
all: $(TARGET)
pxa270_hello_drv.o:pxa270_hello_drv.c $(CC)-c $(CFLAGS)$^-o $@
clean: rm-f *.o *~ core.depend Makefile文件的内容用于执行编译工作,一个Makefile文件包括:① 由make工具创建的目标体(target),通常是目标文件或可执行文件;② 要创建目标体所依赖的文件(dependency_file);③ 创建每个目标需要运行的命令(command)。
以上两个文件编辑完成后后,用make modules编译驱动程序,编写测试文件simple_test_driver.c,然后GCC编辑器编译测试程序生成测试文件。成功生成测试文件后用超级终端开始挂载,加载驱动程序,使用命令./test测试,观察测试结果,实验完成。
实验十三 CPU GPIO驱动程序设计
本实验是让我们在linux系统中插入自己的驱动程序,调用它。实现用CPU GPIO控制外部LED,利用PXA270核心板上的LED验证我们的工作。驱动程序代码:
驱动程序代码与实验十二无大区别,下面列出需要补充的代码。
一、补充代码
补充代码1:
#ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_write [--kernel--]n”);#endif return count;
补充代码2:
#ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_open [--kernel--]n”);#endif
补充代码3:
open: SIMPLE_GPIO_LED_open, read: SIMPLE_GPIO_LED_read, write: SIMPLE_GPIO_LED_write, ioctl: SIMPLE_GPIO_LED_ioctl, release: SIMPLE_GPIO_LED_release, 不同之处:GPIO_LED,主文件名、二、Makefile文件:
将实验十二相关代码作如下修改即可: TARGET = pxa270_gpio_led_drv.o modules: $(TARGET)
all: $(TARGET)
pxa270_gpio_led_drv.o:pxa270_gpio_led_drv.c $(CC)-c $(CFLAGS)$^-o $@
三、作业代码
要求:使得目标板的核心板上的LED闪烁产生亮7秒,灭5秒的效果。作业主要代码:
while(1)
{ ioctl(fd,LED_OFF);
sleep(5);//原来为sleep(1);
ioctl(fd,LED_ON);sleep(7);//原来为sleep(1); }
不同之处:改变代码中加粗位置括号数字,可以改变灯亮和熄灭的时间比
四、测试显示
测试时,超级终端上的显示如下:
实验十四 中断实验
本实验是让我们学习中断的相关概念,以及Linux系统是如何处理中断的,并且学会编写获取和处理外中断的驱动程序。
一、补充代码
补充代码1:
printk(“*****************************************n”);printk(“t %s tn”,VERSION);printk(“************************************************nn”);补充代码2:
#ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_read [--kernel--]n”);#endif return count;
补充代码3:
#ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_write [--kernel--]n”);#endif return count;
补充代码4:
open: SIMPLE_INT_open, read: SIMPLE_INT_read, write: SIMPLE_INT_write, ioctl: SIMPLE_INT_ioctl, release: SIMPLE_INT_release, 二、Makefile文件如实验十三做相应修改。
三、测试时,超级终端上显示如下:
实验十五 数码管显示驱动实验
本实验中,我们要编驱动程序以实现在Linux系统下控制LED数码管的显示。
一、补充代码
补充代码1:
printk(“*****************************************n”);printk(“t %s tn”,VERSION);printk(“************************************************nn”);
补充代码2: #ifdef OURS_HELLO_DEBUG printk(“SERIAL_LED_read [--kernel--]n”);#endif return count;
补充代码3: #ifdef OURS_HELLO_DEBUG printk(“SERIAL_LED_write [--kernel--]n”);#endif return count;
补充代码4: #ifdef OURS_HELLO_DEBUG printk(“SERIAL_LED_ioctl [--kernel--]n”);#endif return 0;
补充代码5: #ifdef OURS_HELLO_DEBUG printk(“SERIAL_LED_open [--kernel--]n”);#endif MOD_INC_USE_COUNT;return 0;
补充代码6: #ifdef OURS_HELLO_DEBUG printk(“SERIAL_LED_release [--kernel--]n”);#endif MOD_DEC_USE_COUNT;return 0;
补充代码7: open: SERIAL_LED_open, read: SERIAL_LED_read, write: SERIAL_LED_write, ioctl: SERIAL_LED_ioctl, release: SERIAL_LED_release
补充代码8: int ret =-ENODEV;ret = devfs_register_chrdev(SERIAL_LED_MAJOR, “serial_led_ctl”, &SERIAL_LED_ops);Showversion();If(ret
补充代码9: int ret =-ENODEV;#ifdef OURS_HELLO_DEBUG printk(“pxa270_SERIAL_LED_init [--kernel--]n”);#endif ret = HW_SERIAL_LED_init();if(ret)return ret;return 0;
补充代码10: #ifdef OURS_HELLO_DEBUG printk(“cleanup_SERIAL_LED [--kernel--]n”);#endif devfs_unregister_chrdev(SERIAL_LED_MAJOR, “serial_led”);
补充代码11: MODULE_DESCRIPTION(“serial_led driver module”);MODULE_AUTHOR(“liduo”);MODULE_LICENSE(“GPL”);module_init(pxa270_SERIAL_LED_init);module_exit(cleanup_SERIAL_LED);
二、Makefile文件与实验十四相同,只需作相应修改即可
三、作业代码
1、实现目标板上的LED数码管循环显示数字9-0。
for(count=0;count
{ data[0] = buf[9-count];//原来为data[0] = buf[count] ret=write(fd,data,1);sleep(1);} 修改之处:将显示的数有buf[count]改为buf[9-count],实现反向循环显示。
2、实现目标板上的LED数码管循环显示数字2、4、6、8、0或者8、6、4、2、0。代码: for(count=0;count
{data[0] = buf[count];ret=write(fd,data,1);sleep(1);}
修改之处:修改count的变化方式,让其每次增加2,而不是1,使0、2、4、6、8循环显示,如要循环显示8、6、4、2、0的话,只要在上述代码中将buf[count]改为buf[8-count]即可。
四、测试显示:
测试时,显示如下:
作业1: 作业2:
实验十六 LED点阵驱动程序设计
本实验要求我们学会编写驱动程序,实现在Linux系统下控制LED点阵显示,并在此基础上稍加改进,实现对LED的控制。驱动程序代码:
一、补充代码
补充代码1:
printk(“*****************************************n”);printk(“t %s tn”,VERSION);printk(“************************************************nn”);
补充代码2:
#ifdef OURS_LED_DEBUG printk(“SIMPLW_LED_read [--kernel--]n”);#endif return count;
补充代码3:
#ifdef OURS_LED_DEBUG printk(“SIMPLE_LED_ioctl [--kernel--]n”);#endif return 0;
补充代码4:
open: SIMPLE_LED_open, read: SIMPLE_LED_read, write: SIMPLE_LED_write, ioctl: SIMPLE_LED_ioctl, release: SIMPLE_LED_release
补充代码5:
int ret =-ENODEV;#ifdef OURS_LED_DEBUG printk(“pxa270_LED_CTL_init [--kernel--]n”);#endif ret = HW_LED_CTL_init();if(ret)return ret;return 0;
补充代码6:
#ifdef OURS_LED_DEBUG printk(“cleanup_LED_ctl [--kernel--]n”);#endif devfs_unregister_chrdev(SIMPLE_LED_MAJOR, “led_ctl”);
二、Makefile程序仍然可以用前一个实验的,只要把相关函数名改了就可以,此处不再赘述。
三、作业代码
1、按横方向隔行扫描led点阵数码管。代码:
for(i=1;i
buf[0]=c;
buf[1]=~r;// row
for(j=1;j
write(fd,buf,2);
printf(“buf[0],buf[1]: [%x,%x]n”,buf[0],buf[1]);
usleep(200000);// sleep 0.2 second
c = c
buf[0]=c;// column
}
c = 1;
r = r
} //原来为r=r
修改之处:外层for循环中间i
2、按竖方向顺序扫描led点阵数码管。代码:
for(i=1;i
buf[0]=c;
buf[1]=~r;// row
for(j=1;j
write(fd,buf,2);
printf(“buf[0],buf[1]: [%x,%x]n”,buf[0],buf[1]);
usleep(200000);// sleep 0.2 second
r = r
测试时,超级终端显示如下:
作业1: 作业2:
实验十七 AD驱动程序
本实验要求我们学会编写驱动程序对模拟量输入进行采集,并转换为数字量显示在超级终端上,从而实现AD转换。
驱动程序代码
一、补充代码
补充代码1:
printk(“*****************************************n”);printk(“t %s tn”,VERSION);
printk(“************************************************nn”);
补充代码2:
#ifdef OURS_HELLO_DEBUG printk(“SIMPLE_HELLO_read [--kernel--]n”);#endif return count;
补充代码3:
#ifdef OURS_HELLO_DEBUG printk(“SIMPLE_HELLO_write [--kernel--]n”);#endif return count;
补充代码4:
#ifdef OURS_HELLO_DEBUG printk(“SIMPLE_HELLO_open [--kernel--]n”);#endif MOD_INC_USE_COUNT;return 0;
补充代码5:
#ifdef OURS_HELLO_DEBUG printk(“SIMPLE_HELLO_release [--kernel--]n”);#endif MOD_DEC_USE_COUNT;return 0;
补充代码6:
open: SIMPLE_HELLO_open, read: SIMPLE_HELLO_read, write: SIMPLE_HELLO_write, ioctl: SIMPLE_HELLO_ioctl, release: SIMPLE_HELLO_release
补充代码7:
ad_ucb = ucb1x00_get();
int ret =-ENODEV;ret = devfs_register_chrdev(ADCTL_MAJOR, “ad_ctl”, &adctl_ops);Showversion();If(ret
补充代码8:
int ret =-ENODEV;#ifdef OURS_HELLO_DEBUG printk(“pxa270_AD_CTL_init [--kernel--]n”);#endif ret = HW_AD_CTL_init();if(ret)return ret;return 0;
补充代码9:
#ifdef OURS_HELLO_DEBUG printk(“cleanup_AD_ctl [--kernel--]n”);#endif devfs_unregister_chrdev(ADCTL_MAJOR, “ad_ctl”);
二、Makefile文件可以用前一个程序的文件,只要将相应部分的代码修改即可
三、作业代码
要求:将UCB_ADC_INP_AD0换为其他通道并观察。代码:
for(i=0;i
{ Val0 = ioctl(fd,UCB_ADC_INP_AD1,0);usleep(100);val1 = ioctl(fd,UCB_ADC_INP_AD0,0);printf(“val0 = %dtval1 = %dn”,val0,val1;usleep(500000);
}
修改之处:只需交换AD1和AD0即可实现输出通道的改变。四、测试时显示
测试时、超级终端显示如下:
实验十八 DA驱动程序
本实验要求我们编写驱动程序,实现将数字信号转换成模拟信号并在示波器上显示出模拟信号波形,即实现DA转换。驱动程序代码:
一、补充代码
补充代码1:
#include“../AD/pxa_ad_drv.h” /引用AD驱动程序的头文件/
补充代码2:
printk(“*****************************************n”);printk(“t %s tn”,VERSION);
printk(“************************************************nn”);
补充代码3:
#ifdef OURS_DA_DEBUG printk(“SIMPLE_DA_read [--kernel--]n”);#endif return count;
补充代码4:
#ifdef OURS_DA_DEBUG printk(“SIMPLE_DA_write [--kernel--]n”);#endif return count;
补充代码5:
#ifdef OURS_DA_DEBUG printk(“SIMPLE_DA_ioctl [--kernel--]n”);#endif return 0;
补充代码6:
#ifdef OURS_DA_DEBUG printk(“SIMPLE_DA_open [--kernel--]n”);#endif MOD_INC_USE_COUNT;return 0;
补充代码7:
open: SIMPLE_DA_open, read: SIMPLE_DA_read, write: SIMPLE_DA_write, ioctl: SIMPLE_DA_ioctl, release: SIMPLE_DA_release
补充代码8:
int ret =-ENODEV;ret = devfs_register_chrdev(SIMPLE_DA_MAJOR, “DA_ctl”, &DA_ctl_ops);Showversion();If(ret
补充代码9:
int ret =-ENODEV;#ifdef OURS_DA_DEBUG printk(“pxa270_DA_CTL_init [--kernel--]n”);#endif ret = HW_DA_CTL_init();if(ret)return ret;return 0;
补充代码10:
#ifdef OURS_DA_DEBUG printk(“cleanup_DA_ctl [--kernel--]n”);#endif devfs_unregister_chrdev(SIMPLE_DA_MAJOR, “DA_ctl”);补充代码11:
MODULE_DESCRIPTION(“serial_led driver module”);MODULE_AUTHOR(“liduo”);MODULE_LICENSE(“GPL”);module_init(pxa270_DA_CTL_init);module_exit(cleanup_DA_ctl);
二、Makefile文件可以继续用前面程序Mekefile的代码,只需要将相应部分的代码修改即可。
三、作业代码
要求:输出三角波。代码:(需要修改部分)
//---------------------print--------------------void da_create_sin(int fd){ unsigned char buf[(int)POINT];unsigned char*c;unsigned long I;int j;double x;for(j=0;j
x=(j/POINT)*(5*M_PI);//此处原来为x=sin((j/POINT
//*(2*M_PI))#ifdef OURS_DEBUG printf(“%ft”,x);#endif buf[j] =(unsigned char)255*(x/2+1)/2;#ifdef OURS_DEBUG printf(“%xn”, buf[j]);#endif } printf(“create sin waven”);printf(“Use”Ctrl + c“quit the functionn”);while(1){ c = buf;for(j=0;j
四、测试显示:(以下为三角波)
(以下为sin)
三、实验总结:
在本次嵌入式实验中,我们首先在老师的指导下了解了嵌入式系统,初步接触了Linux环境。我们的实验板是OURS-PXA270-EP,它是一款基于INTEL XSCALE PXA270处理器,针对高校嵌入式系统教学和实验科研的平台。这款设备主要包括核心板与底板两个部分,核心板主要集成了高速的PXA270 CPU,配套的存储器,网卡等设备;底板主要是各种类型的接口与扩展口。
了解了实验的平台后,在接下来的基本实验中我们学会了嵌入式开发系统硬件环境的搭建、Linux操作系统RedHat9的安装、软件环境的搭建,以及配置超级终端,配置通讯服务。这些实验内容只要按照实验指导书上的步骤一步一步做即可,不会出现难以解决的问题,一般都会做的很顺利。有三个需要注意的地方时,在配置端口时,一定要确定实验箱接的是端口一,还是端口二。否则会出现无法建立呼叫的问题(其表现为超级终端接口内没有输出内容)。其次要确定虚拟机上网桥的设定是否正确。不然也会出现无法呼叫现象。最后,要确定网线是否连接上。在实验时,由于有些电脑的网线接口有断裂的现象,如果插口没接好的话,将会出现nfs连接错误。
在基本实验之后,进行的就是接口实验。总的来说,实验的难度不大。当然这是建立在对实验代码有一定理解的基础之上的。在实验十二中,我们对实验的接口代码规则已经有了一定的了解。而之后的几个实验都是基于实验十二进行相应的改动即可。所以完成下来难度不是很大。而对应的作业中,我们仅需要对测试代码进行相应的改写。在对c语言有一定的了解的前提下,可以很容易相应代码所实现的功能,仅需要对相应代码做些修改即可。
不过,值得注意的还有两点,第一:代码的编写一定要符合规则,同时,代码的输入要避免输入错误。否则,在需要一次一次编译一次次查看错误一次次改正错误,这会是个费时费力的工作。第二:每次实验时,需要从新设定虚拟机的ip,即每次实验开始时都需要重复做实验五实验六。不然在挂载时会出现无法挂载的现象。
通过这次实验,我对嵌入式编程有了更深层次的理解,加深了我对理论知识的认识,有助于今后的学习和工作。感谢黄惠英老师的细心指导。