嵌入式程序设计大作业1Word格式文档下载.docx
《嵌入式程序设计大作业1Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《嵌入式程序设计大作业1Word格式文档下载.docx(12页珍藏版)》请在冰豆网上搜索。
#MakefileforLEDdrivers
#
mod-subdirs:
=diohilmtdsbusvideomacintoshusbinputtelephonyide\
message/i2omessage/fusionscsimdieee1394pnpisdnatm\
fc4net/hamradioi2cacpibluetoothusb/gadget
subdir-y:
=parportcharblocknetsoundmiscmediacdromhotplug
subdir-y+=led
subdir-m:
=$(subdir-y)
(3)修改/uClinux-dist/linux-2.4.x/Makefile文件,在“DRIVERS-y:
=”之后,添加如下
加粗代码,这样在连接uClinux内核映像文件时,能把led.o连接进去。
DRIVERS-n:
=
DRIVERS-y:
DRIVERS-$(CONFIG_ACPI_BOOT)+=drivers/acpi/acpi.o
DRIVERS-$(CONFIG_PARPORT)+=drivers/parport/driver.o
DRIVERS-y+=drivers/char/char.o\
drivers/block/block.o\
drivers/misc/misc.o\
drivers/net/net.o
DRIVERS-y+=drivers/led/led.o
(4)修改/uClinux-dist/vendors/Embest/EduKit/Makefile文件,在”DRIVERS=”后,添加如下加粗代码“led0,c,60,0”。
其中led0为设备名称,c代表字符设备,60为主
设备号,最后一个0是从设备号。
主设备号与驱动程序注册时的主设备号要求一致,
否则用户程序用设备文件名称请求打开设备时,内核无法根据主设备号找到对应的
设备驱动程序。
DEVICES=\
tty,c,5,0console,c,5,1cua0,c,5,64cua1,c,5,65\
\
led0,c,60,0\
(5)完成以上修改后,重新构造romfs和内核映像文件,并烧录到开发板的FLASH上。
(6)最后,启动uClinux。
使用cp命令,简单测试一下LED驱动程序。
把任意一个文件复制到led设备上,检查是否能点亮其中某个LED。
例如在uClinux输入终端执行如下命令:
$cp/bin/init/dev/led0
观察并记录实验现象。
2.测试驱动程序
(1)准备实验环境,使用EmbestEduKit44B0目标开发板附带的串口线分别连接到目标板上的UART0和PC机的串口,将Embest仿真器的JTAG接口与EmbestEduKit
的JTAG接口相连,仿真器的PARALLEL接口与PC机的并口相连。
(2)在PC机上运行Windows附件中自带的超级中断串口通信程序(波特率115200、1位停止位、无检验位、无硬件流控制);
或者使用其它串口通信程序。
(3)交叉编译led测试程序test-led。
(4)编译好测试程序后,启动目标板的uClinux操作系统,在PC机上观察超级终端程序主窗口,可以看到如下界面:
Sashcommandshell(version1.1.1)
/>
在PC机上运行tftp服务端程序,设置好传送文件路径,通过以太网使用tftp把
test-led下载到/var目录下。
在uClinux的输入终端里输入如下命令:
>
cdvar
/var>
tftp–g192.168.0.101–r./test-led(此处IP地址可能不同)
(5)修改test-led程序的属性,使其拥有可执行属性,然后运行test-led。
观察test-led
点亮目标开发板上的LED的情况,并描述。
var>
chmod777test-led
./test-led
2.编写驱动程序
编写测试程序,让各个LED以人眼能够识别的频率依次闪烁,每个LED持续闪烁大约3秒钟,找到编号为1-4的LED在实验板上的布局,绘制布局图,添加到实验报告中。
四、实验数据记录和处理
驱动程序代码:
/*
*linux/deriver/led/ekii-led.c
*leddriverforEmbestEduKitII
*Copyright(C)2005Embest<
*/
#include<
linux/module.h>
linux/init.h>
linux/sched.h>
linux/kernel.h>
linux/fs.h>
linux/errno.h>
//errorcodes
linux/types.h>
//size_t
linux/delay.h>
//mdelay
asm/uaccess.h>
asm/arch-S3C44B0X/s3c44b0x.h>
#undefDEBUG
#ifdefDEBUG
#defineTRACE(str,args...)printk("
led:
"
str,##args)
#else
#defineTRACE(str,args...)
#endif
//TRACE没用
#defineLED_MAJOR60//设备号
#defineLED_DEVNAME"
led"
//设备名称
#defineGPC_MASK(3<
<
8)//掩码.pc8/pc9
#defineGPF_MASK(3<
3)//掩码.pf3/pf4
#defineGET_DATA(c,f)((u8)(((~c&
0x80)>
5)|((~c&
0x100)>
7)|((~f&
0x10)>
3)|((~f&
0x08)>
3)))
//把b、f的值组合为一个8位数据
//3210
//pc8pc9pf4pf3
#defineSET_DATA(t,c,f)(c=(((~t&
0x08)<
5)|((~t&
0x04)<
7)),f=(((~t&
0x02)<
3)|((~t&
0x01)<
3)))
//给b、f赋值
//t3210
//pc8pc9pf4pf3
#defineLED_LOCK(u)down(&
u->
lock);
//信号量
#defineLED_UNLOCK(u)up(&
structunit{//定义一个结构类型,成员是整型指针,代表各个口寄存器,以及两个变量
structsemaphorelock;
//定义信号量
u32*PCONC;
/*PCONBregister*/
u32*PDATC;
/*PDATBregister*/
u32*PCONF;
/*PCONFregister*/
u32*PDATF;
/*PDATFregister*/
u32*PUPF;
/*PUPFregister*/
u32c;
/*storeLED1andLED2value*/
u32f;
/*storeLED3andLED4value*/
};
staticchar*version="
EmbestEdukit-IIleddriverversion1.0(2005-04-18)<
\n"
;
staticstructunitled_unit={//给结构体变量部分成员赋值
.PCONC=(u32*)S3C44B0X_PCONC,
.PDATC=(u32*)S3C44B0X_PDATC,
.PUPC=(u32*)S3C44B0X_PUPC,
.PCONF=(u32*)S3C44B0X_PCONF,
.PDATF=(u32*)S3C44B0X_PDATF,
.PUPF=(u32*)S3C44B0X_PUPF,
staticvoidled_set_value(structunit*unit,u8val)
{//设置pc、pf口的值,初始化时用到两次,第一次val是0x0f,第二次是0
u32temp;
SET_DATA(val,unit->
c,unit->
f);
//第一次:
用0x0f给c、f赋值为:
0、0。
点亮4个led
//第二次:
用0给c、f赋值,使pc8、pc9、pf4、pf3均为1,关闭4个led
//写函数还要多次调用本函数
temp=*unit->
PDATC;
//取pb口状态
temp&
=~GPC_MASK;
//清pb4、pb5
temp|=unit->
c;
//用新值更新temp
*unit->
PDATC=temp;
//写回pc口
PDATF;
=~GPF_MASK;
f;
PDATF=temp;
}
staticu8led_get_value(structunit*unit)
{
u8temp=GET_DATA(unit->
returntemp;
staticintled_open(structinode*inode,structfile*file)
TRACE("
open\n"
);
file->
private_data=&
led_unit;
//这个操作为read服务
MOD_INC_USE_COUNT;
return0;
staticintled_release(structinode*inode,structfile*file)
release\n"
MOD_DEC_USE_COUNT;
//模块引用计数自减
staticssize_tled_read(structfile*file,char*buf,size_tcount,loff_t*offset)
u8temp;
intret;
structunit*unit=(structunit*)file->
private_data;
//使在read函数中可以访问硬件寄存器
read\n"
if(count>
1)
count=1;
LED_LOCK(unit);
//信号量操作
temp=led_get_value(unit);
//读数据
ret=copy_to_user(buf,&
temp,count)?
-EFAULT:
count;
//把数据从内核空间拷贝到用户空间,
//copy_from_user、copy_to_user函数返回不能被复制的字节数,
//因此,如果完全复制成功,返回值为0。
LED_UNLOCK(unit);
//信号量操作
returnret;
staticssize_tled_write(structfile*file,constchar*buf,size_tcount,loff_t*offset)
//使在write函数中可以访问硬件寄存器
write\n"
ret=copy_from_user(&
temp,buf,count)?
//把数据从用户空间拷贝到内核空间
if(ret)
led_set_value(unit,temp);
staticstructfile_operationsled_ops={
owner:
THIS_MODULE,
read:
led_read,
write:
led_write,
open:
led_open,
release:
led_release,
*leddeviceinit
staticvoid__initled_init(structunit*unit)
/*initdevicelock*/
init_MUTEX(&
unit->
/*initioport*/
PCONC;
=~((3<
16)|(3<
18));
//16、17、18、19均0,表示pf3、pf4输入
temp|=((1<
16)|(1<
//16、18为1,所以pc8、pc9都是输出口
//pconc8、pconc9:
01表示输出
PCONC=temp;
PUPC;
temp|=(3<
8);
//8、9置高,pc8、pc9无上拉
PUPC=temp;
PCONF;
8)|(3<
6));
//6、7、8、9均0,表示pf3、pf4输入
8)|(1<
//6、8为1,所以pf3、pf4都是输出口
PCONF=temp;
PUPF;
3);
//4、3置高,pf3、pf4无上拉
PUPF=temp;
/*initdataandturnonled*/
led_set_value(unit,0x0f);
/*delaysometime*/
mdelay(100);
/*turnoffled*/
led_set_value(unit,0x00);
*moduleinit
int__initled_init_module(void)
intres;
init_module\n"
/*printversioninformation*/
printk(KERN_INFO"
%s"
version);
/*registerleddevice*/
res=register_chrdev(LED_MAJOR,LED_DEVNAME,&
led_ops);
if(res<
0){
printk("
ekii-led.o:
unabletogetmajor%dforleddevice.\n"
LED_MAJOR);
returnres;
}
/*thencallled_init()*/
led_init(&
led_unit);
*modulecleanup
void__exitled_cleanup(void)
cleanup\n"
/*unregisterleddevice*/
res=unregister_chrdev(LED_MAJOR,LED_DEVNAME);
0)
unabletoreleasemajor%dforleddevice.\n"
module_init(led_init_module);
module_exit(led_cleanup);
MODULE_DESCRIPTION("
EduKit-IIleddriver"
MODULE_AUTHOR("
Embesttech&
infoCo.,Ltd.<
"
MODULE_LICENSE("
GPL"
测试程序代码:
unistd.h>
stdio.h>
stdlib.h>
linux/fcntl.h>
#defineLED_NUM4
intmain(intargc,char**argv)
inti,j,wval,rval,fd;
printf("
TestLED...\n"
/*openleddevice*/
fd=open("
/dev/led0"
O_RDWR);
/*testsingleled*/
while
(1)
{
for(i=0;
i<
3;
i++)
for(j=0;
j<
LED_NUM;
j++)
{
wval=1<
j;
write(fd,&
wval,1);
read(fd,&
rval,1);
printf("
TurnonLED%d,readbackval=0x%02X\n"
j+1,rval);
/*delay500ms*/
usleep(3000*1000);
}
/*closeleddevice*/
close(fd);
六、实验结果与分析
将驱动程序添加到文件系统,重新编译文件系统和内核映像,将编译好的内核映像烧写到目标板上,重启目标板,使用tftp将驱动测试程序传入到目标板中,运行测试程序,试验箱上的4个LED灯按顺序依次点亮。
七、讨论、建议、质疑
1.考虑到自动匹配不同寄存器的长度,在给寄存器置位时,对数据进行使用取非操作可以自动补齐到寄存器的长度。