第一篇:北邮现场总线实验报告
现场总线实验报告
实验名称:
CAN总线技术与iCAN模块实验
学院:
自动化学院
专业:
自动化专业
班级:
2010211411
姓名:
韩思宇
学号:
10212006
指导老师:
杨军
一、实验名称:
实验一:CAN总线技术与iCAN模块实验
二、实验设备:
计算机,CAN总线系列实验箱,测控设备箱,万用表。
三、实验内容:
1、熟悉iCAN各模块的功能及原理,了解接线端子。
2、学习USBCAN-2A接口卡的使用及安装,安装USBCAN-2A接口卡的驱动程序。
3、根据实验指导书中的手动设置iCAN模块MACID的方法手动设置各模块的MACID。
4、使用提供的iCANTest测试软件工具来测试各模块的功能及用法,利用测试工具与模块之间通信。
5、学习了解iCAN主站函数库中的主要操作函数及其应用。
6、学习利用VC或者VB编程来对iCAN系列各模块进行操作。
四:实验过程:
1、驱动程序安装:
USBCAN-2A接口卡的驱动程序需要自己手动进行安装,驱动程序已经存放于实验准备内容中。找到驱动程序,直接点击进行安装即可。安装完成后,在“管理->设备管理器->通用串行总线控制器”中查看驱动是否安装成功。
注意:安装驱动程序过程中PC机不能连接USB电缆。
2、iCANTEST安装与运行:
连接设备后,打开iCANTEST软件,点击“系统配置”,设置设备类型为USBCAN2,点击“启动”->“上线”,试验各模块的功能。点击“全部下线”,将断开主机与所有模块的连接。
3、各种iCAN模块的测试
4、指示灯,按钮,温湿度传感器的连接
5、测试运行记录与截屏图:
iCAN模块测试运行记录与截图。
图(1)
iCANTEST界面
iCAN4055模块界面如图(2)。DI输入由测控设备箱中的开关控制,DO输出控制设备箱上的灯泡亮灭。
图(2)
iCAN4055模块界面
iCAN4210模块如图(3)。iCAN4210模块为2路模拟量输出模块。将该模块的输出通道0与iCAN4017模块的输入通道3相连,可观察到改变iCAN4210的通道0设定值时,iCAN4017的通道3显示值会随之变化。(通道0为0x8000时,通道3显示为5.000V。)
图(3)
iCAN4210模块界面
iCAN4017模块如图(4)。iCAN4017模块为8路模拟量输入模块。将该模块的通道0与通道1与测控设备箱的温湿度传感器相连,可由通道0和1的电压值推导出传感器测出的环境温度和湿度。由于实验时使用的温湿度传感器温度测量部分故障,所以通道0显示0.000V,湿度测量部分正常,通道1显示为6.182V。
图(4)
iCAN4017模块界面
6、自编程序主要功能
(1)添加一个输入编辑框和一个按钮控件,通过输入0x00-0xFF之间的十六
进制数来控制iCAN4055的DO通道的输入;再设置一个编辑框edit控件来读取iCAN4055的8位数字量输入通道的状态。(2)设置两个输入编辑框控件,来分别设置iCAN4210两个通道的输出。(3)设置4个编辑框edit控件来分别读取iCAN4017前四个通道ch0、ch1、ch2、ch3的模拟量输入值。
7、自编程序运行结果与截图(课上未做,课下做了界面和程序)
图(5)
iCAN4055模块界面
图(6)
iCAN4017模块界面
8、主要程序部分
(1)有关iCAN4055功能模块的简单功能的实现的整体代码如下:
首先在生成的类头文件Sample4055dlg.h中的类CSample4055中添加申明变量: public:
unsigned char buf[1];//发送数据的数据缓存区 unsigned char recbuf[1];//接受数据的数据缓存区 unsigned long len;int outvalue;int count;CString str;在Sample4055.cpp文件中编写控制代码: 首先添加对变量的定义: ROUTECFG cfg;
HANDLE hRoute=0;//新的ICAN网络
HANDLE hSlave4055=0;//数字量输入输出模块4055,MACID=1 CSample4055::CSample4055(CWnd* pParent /*=NULL*/){
}
(2)添加每个控件消息响应函数的代码: void CSample4055::OnStartsysButton1(){ : CDialog(CSample4055::IDD, pParent)buf[0]=0;recbuf[0]=0;count=0;len=0;str=“";
// TODO: Add your control notification handler code here cfg.iCardType=4;//使用usbcan2接线口 cfg.iCardInd=0;//卡序号
cfg.iCANInd=0;//CAN通道选择(0表示0通道;1表示1通道)cfg.wCANBaud=0x001c;//波特率的设定0x001c(500kbps)cfg.iMasterCycle=500;//主站循环周期 cfg.wMasterID=0;//主站ID
Mgr_AddRoute(cfg,&hRoute);//添加iCAN网络
if(Mgr_StartSys()!=ICANOK)//调用Mgr_StartSys()函数对CAN网络是否启动进行判断,返回为ICANOK
} void CSample4055::OnLink4055Button2(){ if(Mgr_IsStarted()!=1){ { } else { } MessageBox(”CAN网络已启动“);MessageBox(”系统启动失败“);
MessageBox(”系统未启动或启动失败,请先启动CAN网络“);
} else { // TODO: Add your control notification handler code here Route_AddSlave(hRoute,1,&hSlave4055);//添加从站4055,MACID=1
if(Slave_Connect(hSlave4055)!=ICANOK)//判断从站4055是否连接成功 { } MessageBox(”4055连接失败“);
else
{ } MessageBox(”4055连接成功“);
SetTimer(1,1000,NULL);//设定开启定时循环,1代表消息事件id,1000表示1000ms即1s } void CSample4055::OnTimer(UINT nIDEvent)//Timer事件函数 {
// TODO: Add your message handler code here and/or call default if(nIDEvent==1){ }
len=1;Slave_GetDIData(hSlave4055,recbuf,&len);//读取4055数字量输入端口数据 str.Format(”0x%02x:%d“,recbuf[0],count);
m_getDI.SetWindowText(str);count=count+1;
CDialog::OnTimer(nIDEvent);
} } void CSample4055::OnButtonSetvalue()//设定4055数字量输出端口值 { // TODO: Add your control notification handler code here if((Mgr_IsStarted()==1)&&(Slave_IsConnected(hSlave4055)==1))
{
UpdateData(true);
outvalue=strtol(m_invalue,NULL,16);//按十六进制进行读取 if(outvalue >= 0 && outvalue <= 255){
buf[0]=(unsigned short)strtol(m_invalue,NULL,16);
Slave_SendData(hSlave4055,0x20,buf,1);//发送数据 } else { } } else { MessageBox(”请输入00~FF之间的十六进制数“);
MessageBox(”系统未启动或从站未连接,请查看后再进行操作“);}
(3)2路模拟量输出模块iCAN4210的编程使用 实验代码如下:
首先添加所用变量的申明: ROUTECFG cfg;
HANDLE hRoute=0;//新的ICAN网络 HANDLE hSlave4210=0;//MACID=2
控制代码:
void CSample4210::OnBUTTONStartCANSys(){ // TODO: Add your control notification handler code here } 8
cfg.iCardType=4;//使用usbcan2接线口 cfg.iCardInd=0;//卡序号
cfg.iCANInd=0;//CAN通道选择(0表示0通道;1表示1通道)cfg.wCANBaud=0x001c;//波特率的设定0x001c(500kbps)cfg.iMasterCycle=500;//主站循环周期 cfg.wMasterID=0;//主站ID
Mgr_AddRoute(cfg,&hRoute);//添加iCAN网络
if(Mgr_StartSys()!=ICANOK)//调用Mgr_StartSys()函数对CAN网络是否启动进行判断,返回为ICANOK
} void CSample4210::OnButtonLink4210(){
// TODO: Add your control notification handler code here if(Mgr_IsStarted()!=1){ { } else { } MessageBox(”CAN网络已启动“);MessageBox(”系统启动失败“);
MessageBox(”系统未启动或启动失败,请先启动CAN网络“);
} else { // TODO: Add your control notification handler code here Route_AddSlave(hRoute,2,&hSlave4210);
if(Slave_Connect(hSlave4210)!=ICANOK){ } MessageBox(”4210连接失败“);
else
} void CSample4210::OnButtonCanok(){ if((Mgr_IsStarted()==1)&&(Slave_IsConnected(hSlave4210)==1)){ } } MessageBox(”4210连接成功“);
{ unsigned char buf[32]={0};
UpdateData(true);if(m_setch0>=0.0&&m_setch0<=10.0){
buf[1]=(unsigned short)(m_setch0/10)*65535;
buf[0]=(unsigned short)((m_setch0/10)*65535)>>8;
} else { } if(m_setch1>=0.0&&m_setch1<=10.0)MessageBox(”提示:请输入0~10V电压“);
{
buf[3]=(unsigned short)(m_setch1/10)*65535;
buf[2]=(unsigned short)((m_setch1/10)*65535)>>8;
}
else { } MessageBox(”提示:请输入0~10V电压“);
Slave_SendData(hSlave4210,0x60,buf,4);
} else {
MessageBox(”系统未启动或从站未连接,请查看后再进行操作“);}(4)8路模拟量输入模块iCAN4017 首先,在生成的.h头文件中添加使用到的变量的申明。public:
unsigned char recbuf[16];unsigned long len;int count;} 在.cpp文件中首先添加iCAN网络定义和申明以及变量的初始化操作。
ROUTECFG cfg;HANDLE hRoute=0;//新的ICAN网络
HANDLE hSlave4017=0;//AI模块4017,MACID=3
CSample4017::CSample4017(CWnd* pParent /*=NULL*/){
: CDialog(CSample4017::IDD, pParent)//{{AFX_DATA_INIT(CSample4017)m_valuech0 = 0.0;m_valuech1 = 0.0;m_valuech2 = 0.0;
} m_valuech3 = 0.0;m_counter = 0;//}}AFX_DATA_INIT recbuf[0]=0;recbuf[1]=0;recbuf[2]=0;recbuf[3]=0;recbuf[4]=0;recbuf[5]=0;recbuf[6]=0;recbuf[7]=0;len=0;count=0;void CSample4017::OnBUTTONStartCANSys(){
// TODO: Add your control notification handler code here cfg.iCardType=4;//使用usbcan2接线口 cfg.iCardInd=0;//卡序号
cfg.iCANInd=0;//CAN通道选择(0表示0通道;1表示1通道)cfg.wCANBaud=0x001c;//波特率的设定0x001c(500kbps)cfg.iMasterCycle=500;//主站循环周期 cfg.wMasterID=0;//主站ID
Mgr_AddRoute(cfg,&hRoute);//添加iCAN网络
if(Mgr_StartSys()!=ICANOK)//调用Mgr_StartSys()函数对CAN网络是否启动进行判断,返回为ICANOK
{
} } else { } MessageBox(”系统启动失败“);MessageBox(”CAN网络已启动“);void CSample4017::OnButtonLink4017(){
// TODO: Add your control notification handler code here if(Mgr_IsStarted()!=1){
MessageBox(”系统未启动或启动失败,请先启动CAN网络“);
} else { // TODO: Add your control notification handler code here Route_AddSlave(hRoute,3,&hSlave4017);if(Slave_Connect(hSlave4017)!=ICANOK){ } MessageBox(”4017连接失败“);
else
{ }
SetTimer(1,1000,NULL);} MessageBox(”4017连接成功");} void CSample4017::OnTimer(UINT nIDEvent){
// TODO: Add your message handler code here and/or call default if(nIDEvent==1){
Slave_GetAIData(hSlave4017,recbuf,&len);
m_valuech0=((double)(recbuf[0]*16*16+recbuf[1])-0x8000)*10/(double)0x8000;
m_valuech1=((double)(recbuf[2]*16*16+recbuf[3])-0x8000)*10/(double)0x8000;
m_valuech2=((double)(recbuf[4]*16*16+recbuf[5])-0x8000)*10/(double)0x8000;
m_valuech3=((double)(recbuf[6]*16*16+recbuf[7])-0x8000)*10/(double)0x8000;
}
m_counter=count;UpdateData(false);count=count+1;CDialog::OnTimer(nIDEvent);}
第二篇:北邮数据库实验报告
数据库实验报告
(三)姓名:学号:班级:
1.用Transact-SQL语句、数据导入、SQL Server Management Studio(企业管理器)输入的方法对所给定的8张表的数据输入到数据库中。自行决定每张表的数据导入办法,但每种方法各针对二或三张表。
Transact-SQL语句: 导入department,student, student_course表。
insertinto department select*from openrowset
('microsoft.jep.oledb.4.0','excel 5.0;hdr=yes;database=D:课件数据库database2.xls',department$);
insertinto student select*from openrowset
('microsoft.jep.oledb.4.0','excel 5.0;hdr=yes;database=D:课件数据库database2.xls',student$);
insertinto student_course select*from openrowset
('microsoft.jep.oledb.4.0','excel 5.0;hdr=yes;database=D:课件数据库database2.xls',student_course$);
数据导入:
操作:选中数据库studentsdb,右键-任务-导入数据。导入book, class, course表。
SQL Server Management Studio: 操作:右键需要编辑的表,选择编辑前200行。
Teacher:
Teacher_course_class:
导入结果: Book:
Class:
Course:
Department:
Student:
Student_course:
Teacher:
Teacher_course_class:
2.用Transact-SQL向Course表中插入一条记录,course_name为空,看运行的结果。
SQL语句:
INSERTINTO course VALUES('dep02_s002', null,'dep02_s002', '72', '5', '4');运行结果:
分析:course_name有not null的约束,因此这条语句不能执行。
3.用Transact-SQL修改Course表中credit为5的记录,将其credit改为7, credit小于4的改为2,看运行的结果。
SQL语句:
update course set credit=7 where credit=5;执行结果:
分析:约束C1指定了credit的范围为1至6.SQL语句:
update course set credit=2 where credit<4;执行结果:
4.删除一条学生记录,看运行结果,对运行结果进行分析。SQL语句:
deletefrom student where student_id='g9940201';执行结果:
分析:因为有参照完整性约束,不能删除。
5.用Transact-SQL完成将编号为dep04_b001的课程的选修信息插入到一个新的选课信息表中。
SQL语句:
Creattablestudent_course2(course_idchar(20), student_idchar(20)gradeint, creditint, semesterint,school_yearchar(20),primarykey(course_id,student_id));
insertintostudent_course2 select*fromstudent_course wherecourse_id='dep04_b001';执行结果:
6.用Transact-SQL完成删除单片机原理课程的选课信息,分析运行结果。
SQL语句:
deletefrom student_course where course_id in(select course_id from course
where course_name='单片机原理')执行结果: 分析:所有课程号为dep04_s003的课程被删除。
本实验中遇到的问题和解决方法:
本实验的顺利完成需要预先作很多准备工作。以下就是我在遇到缺少组件accessdatabaseengine时的解决过程的记录。
AccessDatabaseEngine的安装
accessdatabaseengine用于和office连接,导入导出数据,本实验中需要导入excel文件。安装配合office的版本,我安装的是accessdatabaseengine2017(English)版本。安装32位版本,因office2016是32位。之前误操作安装了不能使用的老旧版本accessdatabaseengine2007,通过控制面板-应用程序卸载将其卸载了。安装accessdatabaseengine依然报错,是因为microsoftofficeclicktorun阻碍sqlserver的一些功能,需要将其卸载。这是微软推出的用于减少office打开速度的应用程序,安装office2016时会自动安装上,原理是开机时将一部分内容放到内存中,因此打开文件时会更快一些。检测自己的office是通过clickto run 还是MSI安装的,可以在word中点击文件-账户,查看产品信息,如果有下图中“office更新”这个选项,则说明安装过click to run。这个程序在控制面板-应用程序中找不到,因此用删除注册表的方式卸载。快捷键“win+R”输入“regedit”打开注册表编辑器,左边HKEY_CLASSES_ROOT-Installer-Product-00006开头的选项,有四个。单击这几个选项,在右侧查看详细信息,可以看到ProductNam是Microsoft Access database engine 2007(我原来误安装的老版本)。删除之前先备份注册表。方法一:选中要删除的文件,右键-导出,保存。只保存了要删除的文件。方法二:注册表编辑器,文件-导出,保存。保存了注册表所有信息。这是因为如果误删了重要文件会导致严重后果,可能需要重装系统,留此备份是为了可以恢复系统。
备份完之后,选中要删除的文件(00006开头的四个),右键-删除即可。回到Access database engine 32位的程序安装包,安装。我无法安装64位,可能是因为office是32位。安装成功之后就可以在sqlserver中导入excel文件了。
第三篇:北邮嵌入式实验报告
北京邮电大学
嵌入式系统开发实验报告
学院:
班级: 姓名: 学号:
序号:
目录
一、实验目的..............................................................................................1
二、实验设备..............................................................................................1
三、基础实验(实验一~实验七)............................................................1
1.实验五..................................................................................................1 2.实验六..................................................................................................1 3.实验七..................................................................................................1
四、驱动程序..............................................................................................5
1.设备驱动程序的概念..........................................................................5 2.驱动程序结构......................................................................................6 3.设备注册和初始化..............................................................................7 4.设备驱动程序的开发过程..................................................................8
五、基本接口实验......................................................................................8
1.实验十二简单设备驱动程序..............................................................9 2.实验十三 CPU GPIO驱动程序设计...................................................9 3.实验十四中断实验...........................................................................10 4.实验十五数码管显示实验................................................................12 5.实验十六 LED点阵驱动程序设计...................................................19 6.实验十七 AD驱动实验....................................................................23 7.实验十八 DA驱动实验....................................................................26
六、实验中遇到的问题及解决方法........................................................30
七、实验总结及心得................................................................................31
一、实验目的
通过实验熟悉Linux环境,并掌握一些基本接口驱动的写法和用C语言编写简单的实验程序。学习LINUX开发环境的搭建,通讯配置等。并熟练掌握LINUX驱动程序的编写及开发流程。对嵌入式系统有进一步的了解。
二、实验设备
1.一套PXA270EP嵌入式实验箱
2.安装Redhat9的宿主PC机,并且配置好ARM Linux的开发环境
三、基础实验(实验一~实验七)
实验一~七为基础实验,目的是为后续实验搭建好软、硬件环境,配置好相关的协议、服务,并通过编写最简单的HelloWorld程序进行测试。由于后面的实验都要依靠前面实验的配置,故本段只着重叙述实验七的具体实现。
1.实验五
实验五为宿主PC机配置了TFTP服务。TFTP(Trivial File Transfer Protocol)是简单文件传输协议,由于特定开发环境的制约,这一服务是必须的。在配置完成后,每次重启宿主PC机时,都须先输入命令:service xinetd restart,以启动TFTP服务。
2.实验六
实验六为宿主PC机配置了NFS服务。NFS(Network File System)指网络文件系统,它实现了文件在不同的系统间使用。当我们想用远端档案时,只需调用“mount”就可以远端系统挂接在自己的档案系统之下。每次重启宿主PC机时,都须先输入命令:service nfs restart,以启动nfs服务。
3.实验七
实验七通过用c语言编写的简单程序HelloWorld,测试前面几个实验是否成功配置好环境,从超级终端可以看到HelloWorld程序的运行结果。
实验步骤如下: 1)硬件连接:
连接宿主 PC 机和一台 PXA270-RP目标板。2)打开宿主PC 机电源,进入 Linux操作系统。
3)启动RedHat 9.0 的图形界面,如下图,若您是以 root 身份登陆在文本模式下,则输入命令startx启动图形界面。进入RedHat 9.0 图形界面后,打开一个终端窗(Terminal)。
4)输入minicom然后回车,minicim设置为115200 8NI无流控。
5)打开PXA270_RP目标板电源,按目标板上的BOOT键,在minicom中应该会看到如下图:
6)在minicom终端窗口中,如图,输入下列四条命令 root ifconfig eth 192.168.0.50 up mount-o nolock 192.168.0.100:/ /mnt cd /mnt 此时,先将该窗口最小化,在后面的第 10 操作步骤中还将会回到该窗口中进行操作。
7)宿主机上打开一个终端窗口(Terminal),点击【红帽/System Tools/Terminal】启动终端窗口,输入下列 4 条命令: ① cd /home
②mkdir HW
③ cd HW
④ vi
HelloWorld.c
/*请您输入程序 7.1 程序清单*/
此时会显示一个空白的屏幕,这条命令的含义是,使用 Vi 编辑器,对一个名叫HelloWorld.c的文件进行编辑,我们看到的空白窗口是对文件进行编辑的窗口,如下图。就像在 Windows系统下面使用写字板等一样道理。
在 vi 里面先单击键盘 A 键,然后左下角会变成—INSER。输入程序的时候和其他编辑器是一样的,如下图。
当输入程序完毕后,单击键盘 Esc 键,然后按“:”(冒号)此时左下角会出现冒号然后输入“wq”最后按“Enter”确认存盘退出 vi 编辑器,如下图。
8)在上面同一个终端窗口中,输入下列 2 条命令交叉编译HelloWorld.c源程序,并查看生成的.o 目标文件,如图 7-10,图7-11: ①
arm-linux-gcc–oHelloWorldHelloWorld.c ②ls 等到再次出现提示符,代表程序已经正确编译。如果此步出现错误信息,请查看错误信息,并且重新编辑原来的 C文件,修改错误。直到正确编译。
9)重新打开第 7 步最小化的开有minicom的终端窗口,即到 PXA270-RP 目标板的mnt目录下,请您输入下列 3 条命令,运行HelloWorld编译成功的HelloWorld目标程序:
① cd home/HW
/*回到minicom中目标板的/mnt/home/HW目录下*/ ②ls ③./ HelloWorld
/*此时会看到如下图*/
四、驱动程序
1.设备驱动程序的概念
设备驱动程序实际是处理和操作硬件控制器的软件,从本质上讲,是内核中具有最高特权级的、驻留内存的、可共享的底层硬件处理例程。驱动程序是内核的一部分,是操作系统内核与硬件设备的直接接口,驱动程序屏蔽了硬件的细节,完成以下功能:
对设备初始化和释放;
对设备进行管理,包括实时参数设置,以及提供对设备的操作接口; 读取应用程序传送给设备文件的数据或者回送应用程序请求的数据; 检测和处理设备出现的错误。
Linux操作系统将所有的设备全部看成文件,并通过文件的操作界面进行操作。对用户程序而言,设备驱动程序隐藏了设备的具体细节,对各种不同设备提供了一致的接口,一般来说,是把设备映射为一个特殊的设备文件,用户程序可以像对其他文件一样对此设备文件进行操作。这意味着:
由于每一个设备至少由文件系统的一个文件代表,因而都有一个“文件名”。应用程序通常可以通过系统调用open()打开设备文件,建立起与目标设备的连接。
打开了代表着目标设备的文件,即建立起与设备的连接后,可以通过read()、write()、ioctl()等常规的文件操作对目标设备进行操作。
设备文件的属性由三部分信息组成:第一部分是文件的类型,第二部分是一个主设备号,第三部分是一个次设备号。其中类型和主设备号结合在一起惟一地确定了设备文件驱动程序及其界面,而次设备号则说明目标设备是同类设备中的第几个。
由于Linux 中将设备当做文件处理,所以对设备进行操作的调用格式与对文件的操作类似,主要包括open()、read()、write()、ioctl()、close()等。应用程序发出系统调用命令后,会从用户态转到核心态,通过内核将open()这样的系统调用转换成对物理设备的操作。
2.驱动程序结构
一个设备驱动程序模块的基本框架
在系统内部,I/O设备的存取通过一组固定的入口点来进行,入口点也可以理解为设备的句柄,就是对设备进行操作的基本函数。字符型设备驱动程序提供如下几个入口点:
open入口点。打开设备准备I/O操作。对字符设备文件进行打开操作,都会调用设备的open入口点。open子程序必须对将要进行的I/O操作做好必要的准备工作,如清除缓冲区等。如果设备是独占的,即同一时刻只能有一个程序访问此设备,则open子程序必须设置一些标志以表示设备处于忙状态。
close入口点。关闭一个设备。当最后一次使用设备完成后,调用close子程序。独占设备必须标记设备方可再次使用。
read入口点。从设备上读数据。对于有缓冲区的I/O操作,一般是从缓冲区里读数据。对字符设备文件进行读操作将调用read子程序。
write入口点。往设备上写数据。对于有缓冲区的I/O操作,一般是把数据写入缓冲区里。对字符设备文件进行写操作将调用write子程序。
ioctl入口点。执行读、写之外的操作。
select入口点。检查设备,看数据是否可读或设备是否可用于写数据。select系统调用在检查与设备文件相关的文件描述符时使用select入口点。
3.设备注册和初始化
设备的驱动程序在加载的时候首先需要调用入口函数init_module(),该函数最重要的一个工作就是向内核注册该设备,对于字符设备调用register_chrdev()完成注册。register_chrdev的定义为:intregister_chrdev(unsigned int major, const char *name, struct file_ operations *fops);其中,major是为设备驱动程序向系统申请的主设备号,如果为0,则系统为此驱动程序动态分配一个主设备号。name是设备名,fops是对各个调用的入口点说明。此函数返回0时表示成功;返回-EINVAL,表示申请的主设备号非法,主要原因是主设备号大于系统所允许的最大设备号;返回-EBUSY,表示所申请的主设备号正在被其他设备程序使用。如果动态分配主设备号成功,此函数将返回所分配的主设备号。如果register_chrdev()操作成功,设备名就会出现在/proc/dvices文件中。
Linux在/dev目录中为每个设备建立一个文件,用ls–l命令列出函数返回值,若小于0,则表示注册失败;返回0或者大于0的值表示注册成功。注册以后,Linux将设备名与主、次设备号联系起来。当有对此设备名的访问时,Linux通过请求访问的设备名得到主、次设备号,然后把此访问分发到对应的设备驱动,设备驱动再根据次设备号调用不同的函数。
当设备驱动模块从Linux内核中卸载,对应的主设备号必须被释放。字符设备在cleanup_ module()函数中调用unregister_chrdev()来完成设备的注销。unregister_chrdev()的定义为:intunregister_chrdev(unsigned int major, const char *name);包括设备注册在内,设备驱动的初始化函数主要完成的功能是有以下5项。(1)对驱动程序管理的硬件进行必要的初始化。
对硬件寄存器进行设置。比如,设置中断掩码,设置串口的工作方式、并口的数据方向等。
(2)初始化设备驱动相关的参数。
一般说来,每个设备都要定义一个设备变量,用以保存设备相关的参数。在这一步骤里对设备变量中的项进行初始化。
(3)在内核注册设备。
调用register_chrdev()函数来注册设备。(4)注册中断。
如果设备需要IRQ支持,则要使用request_irq()函数注册中断。(5)其他初始化工作。
初始化部分一般还负责给设备驱动程序申请包括内存、时钟、I/O端口等在内的系统资源,这些资源也可以在open子程序或者其他地方申请。这些资源不用时,应该释放,以利于资源的共享。
若驱动程序是内核的一部分,初始化函数则要按如下方式声明: int __initchr_driver_init(void);其中__init是必不可少的,在系统启动时会由内核调用chr_driver_init,完成驱动程序的初始化。
当驱动程序是以模块的形式编写时,则要按照如下方式声明: intinit_module(void)当运行后面介绍的insmod命令插入模块时,会调用init_module函数完成初始化工作。
4.设备驱动程序的开发过程
由于嵌入式设备由于硬件种类非常丰富,在默认的内核发布版中不一定包括所有驱动程序。所以进行嵌入式Linux系统的开发,很大的工作量是为各种设备编写驱动程序。除非系统不使用操作系统,程序直接操纵硬件。嵌入式Linux系统驱动程序开发与普通Linux开发没有区别。可以在硬件生产厂家或者Internet上寻找驱动程序,也可以根据相近的硬件驱动程序来改写,这样可以加快开发速度。实现一个嵌入式Linux设备驱动的大致流程如下。
(1)查看原理图,理解设备的工作原理。一般嵌入式处理器的生产商提供参考电路,也可以根据需要自行设计。
(2)定义设备号。设备由一个主设备号和一个次设备号来标识。主设备号惟一标识了设备类型,即设备驱动程序类型,它是块设备表或字符设备表中设备表项的索引。次设备号仅由设备驱动程序解释,区分被一个设备驱动控制下的某个独立的设备。
(3)实现初始化函数。在驱动程序中实现驱动的注册和卸载。(4)设计所要实现的文件操作,定义file_operations结构。(5)实现所需的文件操作调用,如read、write等。
(6)实现中断服务,并用request_irq向内核注册,中断并不是每个设备驱动所必需的。
(7)编译该驱动程序到内核中,或者用insmod命令加载模块。(8)测试该设备,编写应用程序,对驱动程序进行测试。
五、基本接口实验
在完成了基本实验后,我们开始着手基本接口实验。在这些实验中,我们学习如何编写设备驱动程序,及如何用测试程序检验驱动程序是否正确,并通过改写测试程序正常地对驱动程序进行相关操作。
1.实验十二 简单设备驱动程序
本次实验的任务是编写一个字符型设备驱动程序,并学习在应用程序中调用驱动。考虑到我们初次接触驱动程序的编写,对此还十分陌生,因此指导书中提供了本次实验所要用到的程序源代码。虽然这样一个字符型设备驱动程序并没有任何实际作用,但是它让我们轻松掌握了嵌入式驱动的编写过程,因为复杂繁琐的驱动,其骨架都是相同的。因此,看懂本实验的源代码,学习并模仿其编写方法,对于后续实验有着非常重要的意义。
2.实验十三 CPU GPIO驱动程序设计
在本实验中,我们要编写第一个针对实际硬件的驱动程序。我们知道,凡是操作系统控制外部设备,即使是最简单的硬件电路,也是需要驱动的。本实验涉及的外部硬件只有电阻和发光二极管。我们使用自己编写的驱动程序与应用程序控制 GPIO96的电平,通过 LED 的亮灭来判断,是否 CPU 做出了正确的响应。
补充代码(1)
//-------------------WRITE-----------------------ssize_tSIMPLE_GPIO_LED_write(struct file * file ,const char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_write [--kernel--]n”);
#endif
return count;}
补充代码(2)
//-------------------OPEN------------------------ssize_tSIMPLE_GPIO_LED_open(structinode * inode ,struct file * file){ #ifdef OURS_GPIO_LED_DEBUG printk(“SIMPLE_GPIO_LED_open [--kernel--]n”);
#endif
MOD_INC_USE_COUNT;
return 0;}
补充代码(3)
//------------------structfile_operationsGPIO_LED_ctl_ops ={ 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, };实验作业
要求在目标板上LED闪烁产生亮7秒,灭2秒的效果 在测试程序中有这样一段代码: while(1){ ioctl(fd,LED_OFF);sleep(1);
sleep(1);while(1){ ioctl(fd,LED_OFF);sleep(2);
sleep(7);} 3.实验十四
中断实验
// 灭2秒 // 亮7秒 ioctl(fd,LED_ON);}
// 休眠1秒
ioctl(fd,LED_ON);只需将上面的代码改为如下代码即可:
在理论课中,我们学习了许多中断方面的知识,包括中断向量、中断优先级、中断过程等。在PXA270系统里,中断控制器分外部设备和 PXA270X 处理器设备产生的两个层次的中断,前者是初级的中断源,后者是次级中断源,大量的次级中断源通常被映射为一个初级中断源。
补充代码1 voidshowversion(void){ printk(“*********************************************n”);
printk(“t %s tn”, VERSION);
printk(“*********************************************nn”);
} static intSimpleINT_temp_count = 0;补充代码2 //-------------------READ------------------------ssize_tSIMPLE_INT_read(struct file * file ,char * buf, size_t count, loff_t * f_ops){
#ifdef OURS_INT_DEBUG
#endif return count;printk(“SIMPLE_INT_read [--kernel--]n”);} 补充代码3 //-------------------WRITE-----------------------ssize_tSIMPLE_INT_write(struct file * file ,const char * buf, size_t count, loff_t * f_ops){
#ifdef OURS_INT_DEBUG
} 补充代码4 //------------------structfile_operationsINT_ctl_ops ={ open: SIMPLE_INT_open, read: SIMPLE_INT_read, #endif return count;printk(“SIMPL_INT_write [--kernel--]n”);write:SIMPLE_INT_write, ioctl:SIMPLE_INT_ioctl, release:SIMPLE_INT_release, };
通过此实验,我了解了硬件中断管脚与中断号的对应关系,以及中断号与中断处理程序的对应关系,对于今后编写更为复杂的中断程序打下基础。
4.实验十五
数码管显示实验
在此实验中,我们要编写针对 74LV164 的驱动程序,并用其串并转换功能来控制八段LED数码管的显示。
补充代码1 voidshowversion(void){ printk(“*********************************************n”);
printk(“t %s tn”, VERSION);
printk(“*********************************************nn”);
} 补充代码2 //-------------------READ------------------------ssize_tSERIAL_LED_read(struct file * file ,char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_HELLO_DEBUG
} 补充代码3 //-------------------WRITE-----------------------ssize_tSERIAL_LED_write(struct file * file ,const char * buf, size_t count, loff_t * f_ops)return count;printk(“SERIAL_LED_read [--kernel--]n”);#endif { #ifdef OURS_HELLO_DEBUG
} 补充代码4 //-------------------IOCTL-----------------------ssize_tSERIAL_LED_ioctl(structinode * inode ,struct file * file, unsigned intcmd, long data){ #ifdef OURS_HELLO_DEBUG
#endif
} 补充代码5 //-------------------OPEN------------------------ssize_tSERIAL_LED_open(structinode * inode ,struct file * file){ #ifdef OURS_HELLO_DEBUG
#endif
return 0;} MOD_INC_USE_COUNT;printk(“SERIAL_LED_open [--kernel--]n”);return 0;printk(“SERIAL_LED_ioctl [--kernel--]n”);return count;#endif write_byte(* buf);printk(“SERIAL_LED_write [--kernel--]n”);补充代码6 //-------------------RELEASE/CLOSE---------------ssize_tSERIAL_LED_release(structinode *inode ,struct file * file){ #ifdef OURS_HELLO_DEBUG
printk(“SERIAL_LED_release [--kernel--]n”);
#endif MOD_DEC_USE_COUNT;return 0;} 补充代码7 //------------------structfile_operationsSERIAL_LED_ops ={ open: SERIAL_LED_open,read: SERIAL_LED_read,write:SERIAL_LED_write,ioctl:SERIAL_LED_ioctl,release:SERIAL_LED_release, };补充代码8 staticint __initHW_SERIAL_LED_init(void){ int ret =-ENODEV;
ret =
devfs_register_chrdev(SERIAL_LED_MAJOR, &SERIAL_LED_ops);
showversion();if(ret < 0)“serial_led_ctl”,} {
} else { } return ret;printk(“ pxa270 serial_led_driver register success!![--kernel--]n”);printk(“ pxa270 init_module failed with %dn [--kernel--]”, ret);return ret;补充代码9 staticint __init pxa270_SERIAL_LED_init(void){ int ret =-ENODEV;
printk(“pxa270_SERIAL_LED_init [--kernel--]n”);
#endif
ret = HW_SERIAL_LED_init();if(ret)return ret;return 0;} 补充代码10 static void __exit cleanup_SERIAL_LED(void){ #ifdef OURS_HELLO_DEBUG #ifdef OURS_HELLO_DEBUG
#endif }
补充代码11 MODULE_DESCRIPTION(“serial_led driver module”);
MODULE_AUTHOR(“liduo”);
MODULE_LICENSE(“GPL”);
module_init(pxa270_SERIAL_LED_init);module_exit(cleanup_SERIAL_LED);使用测试程序看到的测试结果是数码管按0-9显示输出。实验作业要求在上述基础上,分别实现一下两个功能:
①要求您再编写一个测试程序,实现 PXA270-EP 目标板上的 LED 数码管循环显示的数字9-0。
②要求您再编写一个测试程序,实现 PXA270-EP 目标板上的 LED 数码管循环显示的数字02468。
由于在测试程序中定义了数组buf[10]分别存储了0-9是个数,因此上述功能的实现方法是,分别对测试程序做如下修改:
原测试程序: while(1){ for(count=0;count<10;count++){ data[0] = buf[count];ret=write(fd,data,1);sleep(1);} } 实现功能①: while(1){ for(count=9;count>=0;count--)} } 结果显示
// 倒序显示数字
{ data[0] = buf[count];ret=write(fd,data,1);sleep(1);devfs_unregister_chrdev(SERIAL_LED_MAJOR, “serial_led”);printk(“cleanup_SERIAL_LED [--kernel--]n”);实现功能②: while(1){ for(count=0;count<9;count=count+2)} } 结果显示
// 更改显数顺序
{ data[0] = buf[count];ret=write(fd,data,1);sleep(1);
通过更改显数的顺序,很容易实现实验作业里要求的功能。
5.实验十六 LED点阵驱动程序设计
通过本实验的操作,我们将 8X8 的点阵 LED 驱动起来并通过编写测试程序,使其能够按照您的意图进行显示。要求您还编写更多的测试程序
补充代码1 voidshowversion(void){ printk(“*********************************************n”);printk(“t %s tn”, VERSION);printk(“*********************************************nn”);
} 补充代码2 //-------------------READ------------------------ssize_tSIMPLE_LED_read(struct file * file ,char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_LED_DEBUG
#endif return count;printk(“SIMPLE_LED_read [--kernel--]n”);} 补充代码3 //-------------------IOCTL-----------------------ssize_tSIMPLE_LED_ioctl(structinode * inode ,struct file * file, unsigned intcmd, long data){
#endif
} 补充代码4 //------------------structfile_operationsLED_ctl_ops ={ open: SIMPLE_LED_open, read:
SIMPLE_LED_read, write: SIMPLE_LED_write, ioctl: SIMPLE_LED_ioctl, release:SIMPLE_LED_release, };补充代码5 staticint __init pxa270_LED_CTL_init(void){ int ret =-ENODEV;
printk(“pxa270_LED_CTL_init [--kernel--]n”);
#endif
ret = HW_LED_CTL_init();if(ret)
return ret;#ifdef OURS_LED_DEBUG return 0;printk(“SIMPLE_LED_ioctl [--kernel--]n”);#ifdef OURS_LED_DEBUG return 0;} 补充代码6 static void __exit cleanup_LED_ctl(void){
#ifdef OURS_LED_DEBUG
#endif
} ①要求您再编写一个测试程序,实现按横的方向隔行顺序扫描 LED 点阵数码管。
②要求您再编写一个测试程序,实现按竖的方向顺序扫描 LED 点阵数码管。作业一,隔行扫描:
printk(“cleanup_LED_ctl [--kernel--]n”);outw(0x0000,ioremap_addr);
devfs_unregister_chrdev(SIMPLE_LED_MAJOR, “led_ary_ctl”);for(i=1;i<=8;i2++){
buf[0]=c;buf[1]=~r;// row for(j=1;j<=8;j++){
} r = 1;c = c<<1;
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;
buf[1]=~r;// column
结果显示
作业二,竖向扫描:
for(i=1;i<=8;i++){
buf[0]=c;buf[1]=~r;// row for(j=1;j<=8;j++){
} r = 1;c = c<<1;
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;
buf[1]=~r;// column
结果显示
6.实验十七 AD驱动实验
通过本实验的操作,我们将 AD 转换器驱动起来并通过编写测试程序,使其能够将模拟信号量按照我们的要求转换成数字信号量。为了更加清楚地理解 AD 转换器的工作过程,请您再编写一个测试程序,将 UCB_ADC_INP_AD0 换成其他通道,来观察其他 AD 通道情况。
补充代码1 voidshowversion(void){ printk(“%sn”,VERSION);} struct ucb1x00 *ad_ucb;
补充代码2 //-------------------READ------------------------staticssize_tadctl_read(struct file * file ,char *buf, size_t count, loff_t *offset){
} 补充代码3 //-------------------WRITE-----------------------ssize_tadctl_write(struct file * file ,const char *buf, size_t count, loff_t *offset){
#ifdef OURS_HELLO_DEBUG printk(“writen”);
#endif
} 补充代码4 //-------------------OPEN------------------------ssize_tadctl_open(structinode * inode ,struct file * file){
#ifdef OURS_HELLO_DEBUG printk(“openn”);
#endif
}
补充代码5 //-------------------RELEASE/CLOSE---------------ssize_tadctl_release(structinode *inode ,struct file * file){
#ifdef OURS_HELLO_DEBUG printk(“releasen”);
#endif return 0;return 0;return count;#ifdef OURS_HELLO_DEBUG printk(“readn”);#endif return count;} 补充代码6 staticstructfile_operationsadctl_ops = {
};补充代码7 //-------------------INIT------------------------staticint __initHW_AD_CTL_init(void){
return ret;}
补充代码8 staticint __init pxa270_AD_CTL_init(void){ int ret =-ENODEV;#ifdef OURS_HELLO_DEBUG int ret =-ENODEV;ret = devfs_register_chrdev(ADCTL_MAJOR, “adctl”, &adctl_ops);showversion();ad_ucb=ucb1x00_get();if(ret < 0){
} else { } adctl_dev_handle = devfs_register(NULL, “ad_ctl”, DEVFS_FL_DEFAULT, printk(“adctl driver register success!n”);printk(“fail %dn”,ret);return 0;read: ioctl: adctl_read, adctl_ioctl, write: adctl_write, open: adctl_open, release:adctl_release,ADCTL_MAJOR, 0, S_IFCHR, &adctl_ops, NULL);printk(“initn”);#endif ret=HW_AD_CTL_init();if(ret)}
补充代码9 static void __exit cleanup_AD_ctl(void){
}
7.实验十八 DA驱动实验
通过本实验的操作,我们使用示波器看到了通过DA转换而输出的波形。在此基础上,要求试写一个实现输出三角波的测试程序。
补充代码1 #include
} printk(“t %st n”,VERSION);printk(“*****************************n”);static long ioremap_addr;补充代码3 //-------------------READ------------------------ssize_tSIMPLE_DA_read(struct file * file ,char * buf, size_t count, loff_t * f_ops){ #ifdef OURS_DA_DEBUG
} 补充代码4 //-------------------WRITE-----------------------ssize_tSIMPLE_DA_write(struct file * file ,const char * buf, size_t count, loff_t * f_ops){
printk(“SIMPLE_DA_write[--kernel--]n”);
#endif
return count;} 补充代码5 //-------------------IOCTL-----------------------ssize_tSIMPLE_DA_ioctl(structinode * inode ,struct file * file, unsigned intcmd, outb(buf[0],ioremap_addr);#ifdef OURS_DA_DEBUG return count;#endif printk(“SIMPLE_DA_read[--kernel--]n”);long data){ #ifdef OURS_DA_DEBUG
printk(“SIMPLE_DA_ioctl[--kernel--]n”);
#endif return 0;} 补充代码6 //-------------------OPEN------------------------ssize_tSIMPLE_DA_open(structinode * inode ,struct file * file){
#ifdef OURS_DA_DEBUG printk(“SIMPLE_DA_open [--kernel--]n”);
MOD_INC_USE_COUNT;return 0;
#endif } 补充代码7 /------------------structfile_operationsDA_ctl_ops ={
read: SIMPLE_DA_read,};
补充代码8 release:
SIMPLE_DA_release, ioctl:
SIMPLE_DA_ioctl, write:
SIMPLE_DA_write, //-------------------INIT------------------------staticint __initHW_DA_CTL_init(void){ int ret =-ENODEV;
}
补充代码9 staticint __init pxa270_DA_CTL_init(void){ int ret =-ENODEV;
printk(“pxa270_DA_CTL_init [--kernel--]n”);
#endif #ifdef OURS_DA_DEBUG } printk(“ pxa270 led_driver register success!![--kernel--]n”);{ else } return ret;printk(“ pxa270: init_module failed with %dn [--kernel--]”, ret);{ if(ret < 0)showversion();ret = devfs_register_chrdev(SIMPLE_DA_MAJOR, “da_ctl”, &DA_ctl_ops);
ret = HW_DA_CTL_init();if(ret)
return ret;return 0;} 补充代码10 static void __exit cleanup_DA_ctl(void){
#endif } 补充代码11 MODULE_DESCRIPTION(“DA_ctl driver module”);MODULE_AUTHOR(“liduo”);MODULE_LICENSE(“GPL”);module_init(pxa270_DA_CTL_init);module_exit(cleanup_DA_ctl);printk(“cleanup_DA_ctl [--kernel--]n”);#ifdef OURS_DA_DEBUG
六、实验中遇到的问题及解决方法
每一次上课重新启动后,当需要将宿主PC机的根目录挂在到PXA270-EP目标板的mnt目录下(即在超级终端中输入命令“mount –o soft,timeo=100,rsize=1024 192.168.0.100:/ /mnt”)时,常显示无法挂载。
解决方法:在超级终端下的挂载命令应该用”mount –o nolock 192.168.0.100:/ /mnt”,如果依然不能挂载需要重启NFS服务,即在PC机终端中输入命令”service nfs restart”两遍后就可以挂载,当然有时候也可能是因为网线没插好。
在每次重启机器之后都需要将PC机终端的IP地址和开发板中的系统的IP地址设定正确,不然也无法挂载。
七、实验总结及心得
本学期的所有实验均在宿主PC机与PXA270-EP目标板上进行。在实验中,我们先建立硬件实验平台,又建立主机软件开发环境,接着为实验进行各项配置,最后完成了各个实验中的多种功能。值得注意的是,前期的硬件、软件准备必须完整无误地实现,后续的实验才能顺利进行。所以,打基础的工作一定要仔细谨慎。后续实验中虽然给出了驱动程序的框架,仍需要我们自己补充完整,并开动脑筋举一反三,在原代码的基础上进行一定修改以实现新的功能。
通过这学期的实验,我逐步完成了建立实验软件开发平台,搭建实验编译软件环境,在PC上编辑、编译一个应用程序,并且在嵌入式系统上运行和调试它的过程。在实验中,不难发现,编译驱动程序大体框架都是一样的,比如里面的读函数、写函数、ioctl函数、打开、关闭以及函数模块的初始化并且在超级终端上显示出等。但所不同的是,要根据不同的实验要求修改名称,并且对其中必要的部分进行修改。
除此之外,我认为很多基础知识对实验的进行也起着非常大的作用,例如数码管的显示原理。在掌握了基础知识之后,上机的过程会显得相对简单,尤其是代码框架已经给出,我们所以需要做的就是根据需要稍作改动来得到我们想要的结果。
在实验过程中常常会遇到各种各样的问题,刚开始时我不知如何是好,只能求助于老师和同学,后来随着实验的进行,我对实验的内容和虚拟机都有了一定的了解,遇到问题时也可以静下心来思考其原因,自己尝试各种方法去解决问题。整个实验让我了解了一套完整的嵌入式系统驱动程序开发的全过程,学到的内容非常丰富,相信在学习了这些内容后,在今后的学习工作中接触到类似内容,我不会感到无从下手,而是能够有条不紊。
感谢老师的辛勤指导!
第四篇:北邮数据库实验报告[最终版]
数据库实验报告
(四)姓名:学号:班级:
1.简单查询:
SQL语句:
select credit from course where course_name='SQL Server数据库开发技术';(1)查询“数据库开发技术”课程的学分;
或者模糊查询:
select credit from course where course_name like'%数据库开发技术';执行结果:
(2)查询选修了课程编号为“dep04_s004”的学生的学号和成绩,并将成绩按降序输出;
SQL语句:
select student_id,grade from student_course where course_id='dep04_s003' orderby grade desc;执行结果:
SQL语句:
select course_id,grade from student_course where student_id='g9940205';(3)查询学号为“g9940205”的学生选修的课程编号和成绩;
执行结果:
(4)查询选修了课程编号为“dep04_s001”且成绩高于85分的学生的学号和成绩。
SQL语句:
select student_id,grade from student_course where course_id='dep04_s001'and grade>'85';执行结果:
2.在多表连接的查询实验中,用Transact SQL语句完成以下查询操作:(1)查询选修了课程编号为“dep04_s002”且成绩高于85分的学生的学号、姓名和成绩;
SQL语句:
select student.student_id,student_name,grade from student,student_course where student.student_id=student_course.student_id and student_course.course_id='dep04_s002' and student_course.grade>'85';执行结果:
SQL语句:
select student.student_id,student_name,course_name,grade from student,course,student_course where student.student_id=student_course.student_id and student_course.course_id=course.course_id;(2)查询所有学生的学号、姓名、选修的课程名称和成绩;
执行结果:
(3)查询林红同学选修的课程名称、学分和成绩。(考试成绩>=60 否则无学分。)
SQL语句:
select course_name,student_course.credit,grade from student,student_course,course where student_name='林红'
and student.student_id=student_course.student_id and student_course.course_id=course.course_id;
有学分,3.在复杂查询实验中,用Transact SQL语句完成以下查询操作:
SQL语句:
select student.student_id,student_name from student,student_course where student.student_id=student_course.student_id groupby student.student_id,student_name havingcount(student_course.course_id)>=3;(1)查询至少选修了三门课程的学生的学号和姓名;
执行结果:
SQL语句:
selectavg(grade)from student_course where course_id='dep04_b001';(2)查询选修课程号为“dep04_b001”的学生的平均成绩; 执行结果:
(3)查询所有学生的学号和他选修课程的最高成绩,要求他的选修课程中没有成绩为空的。
SQL语句:
select student_id,max(grade)from student_course whereexists(select grade from student_course)groupby student_id;执行结果:
(4)查询严为老师2001/2002学年教的软件开发技术课程的最高成绩及此学生的学号、姓名、班级。
SQL语句:
select student.student_id,student_name,student.class_id,grade from teacher_course_class,teacher,course,student,student_course where teacher_course_class.teacher_id = teacher.teacher_id and teacher.teacher_name ='严为'and teacher_course_class.course_id = course.course_id and course.course_name ='软件开发技术'and
teacher_course_class.course_id = student_course.course_id and student_course.student_id = student.student_id and teacher_course_class.school_year ='2001/2002'and student_course.grade>=all(select grade from student_course,course where student_course.course_id = course.course_id and
course.course_name ='软件开发技术');执行结果:
(5)查询数据库开发技术课程用过的教材名称,作者和出版社。
SQL语句:
select book_name,author,publish_company from book,course where course.book_id=book.book_id and course_name='SQL SERVER数据库开发技术';执行结果:
(6)查询计算机科学系讲授过数据库开发技术的老师姓名和职称。
SQL语句:
select teacher_name,profession from teacher,course,teacher_course_class,department where teacher.teacher_id = teacher_course_class.teacher_id and course.course_id = teacher_course_class.course_id and department.department_id = teacher.department_id and department.department_name ='计算机科学'and
course.course_name ='SQL Server数据库开发技术';执行结果:
4.在嵌套查询实验中,用Transact SQL语句完成以下查询操作,要求写嵌套查询语句:
SQL语句:
select student_id,student_name from student where student_id in(select student_id from student_course where course_id in(select course_id from course where course_name ='软件开发技术'));(1)查询选修了软件开发技术的学生的学号和姓名;
执行结果:
SQL语句:
select student_id,student_name from student wherenotexists(select student_id from student_course(2)查询没有选修软件开发技术的学生的学号和姓名; where course_id in(select course_id from course where course_name ='软件开发技术'));执行结果:
(3)查询至少选修了学号为“g9940201”的学生所选修的所有课程的学生的学号和姓名。
SQL语句:
select student_id,student_name from student wherenotexists(select*
from student_course student_course1 where student_course1.student_id ='g9940201' andnotexists(select*
from student_course student_course2 where student.student_id=student_course2.student_id and student_course2.course_id = student_course1.course_id));执行结果:
5.建立如下视图:
学生选修课程信息视图,包括以下内容:
对(1)(2)内容用企业管理器和SQL语句方式分别完成。1)学生学号、姓名、所在系、授课老师姓名、课程名称、课程教材名称、出版社、学分、选课成绩
SQL语句:
Createview
view1(student_id,student_name,department_name,teacher_name,course_name, book_name,publish_name,credit,grade)asselectdistinct
student.student_id,student.student_name,department_name,teacher_name,course_name,book_name,publish_company,student_course.credit,student_course.grade from
student,course,department,student_course,teacher,teacher_course_class,book,class where
student.student_id=student_course.student_id and student.class_id=class.class_id and class.department_id=department.department_id and student_course.course_id=course.course_id and course.book_id=book.book_id and teacher.teacher_id=teacher_course_class.teacher_id and teacher_course_class.course_id=course.course_id
企业管理器:
Step1:右键视图,选择新建视图。
Step2:添加涉及到的表。
Step3:选择需要显示的列。
Step4:右键视图view1,选择查看前1000行。
执行结果:
SQL语句:
alterview
view1(student_id,student_name,department_name,teacher_name,course_name,book_name,publish_name,credit,grade,class_id)ASSELECT DISTINCT
student.student_id,student_name,department_name,teacher_name,course_name,book_name,publish_company,student_course.credit,student_course.grade,student.class_id FROM
student,student_course,course,teacher,teacher_course_class,book,department,class WHERE student.student_id=student_course.student_id and student.class_id=class.class_id and class.department_id=department.department_id and student_course.course_id=course.course_id and course.book_id=book.book_id and teacher.teacher_id=teacher_course_class.teacher_id and teacher_course_class.course_id=course.course_id 2)修改以上视图,增加学生所在班级信息。
企业管理器:
勾选class表中的“所有列”。
执行结果:
SQL语句:
select student_id,grade from view1 where course_name ='计算机基础';3)对以上视图进行相关的查询操作:(1)查询选修了计算机基础的学生的学号和成绩;
执行结果:
SQL语句:
select student_id,student_name,course_name,grade from view1(2)查询所有学生的学号、姓名、选修的课程名称和成绩;
执行结果:
SQL语句:
select student_id,student_name,course_name from view1 where teacher_name ='章红';(3)查询选修了章红老师课程的学生的学号和姓名、课程名称。
执行结果:
第五篇:北邮日历java实验报告
Java日历实验报告
信息工程27班项明钧
一、实验要求
写一个建议日历图形用户界面
二、设计思路
此次作业主要用到了窗口布局设计及各个组件的功能显示,事件处理机制。首先需要建立一个frame框架,然后进行布局设计。需要用到p0,p1,p2,p3,p4面板,其中p0,p1,p2,p4为正常静态面板,p3位自己定义的JScrollPane滚动面板,内容从p0获取,可以通过滑动滚动条来达到显示超出界面显示范围的内容。接着定义若干button,label,TextField通过add函数添加到对应的面板中。通过将主日历显示界面设置成GridLayout来达到网格式显示,当有文本输入和按钮按下,事件处理机制将会判断输入的年和月份是否符合正确格式。是的话将通过getMonthDay和getStartDay得到的所查询月份的日历一个个插入网格中,完成日历显示。
在p3面板中我还借用了 new JLabel(new ImageIcon函数插入本地图片,使界面更加美观。界面最下一栏放入了关于日历由来的简介,由于字数较多在界面范围内不能全部显示,我使用了JScrollPane滚动面板,这样就可以左右移动条来翻阅日历简介了。
三、实验结果
四、心得体会
这次实验我选了java日历软件。在学习了图形界面(GUI)设计后,我知道了窗口里面板,标签,文本框的基本设置和代码应用。但是就单单简单地添加几个组件画面难免显得简单,因此我在网上查询代码分别给面板增添了背景色,给我的信息字体设置了字体,大小,还给最下一栏日理由来增加了滚动条。通过这次学习,我发现书上很多知识只有在实际编写代码运用到时才能有更好的理解,而且我未知的函数好还有很多,需要我去主动探索学习。
五、源代码及注释
import java.awt.*;import java.awt.event.*;import javax.swing.*;public class Calendar extends JFrame implements ActionListener { static int year,month;
//设置静态变量 private String [] ast = {“
星期日”,“
星期一”, “
星期二”, “
星期三”, “
星期四”, “
星期五”, “
星期六”};private JLabel [] ai = new JLabel[49];private JLabel label0,label1,label2,label00,label4,label5;
//定义标签
private JTextField t0,t1;
//定义文本输入框
private JButton btn1;
//定义按钮
private JPanel p0,p1,p2,p4;
//定义静态面板
private JScrollPane p3;
//定义滚动面板
public Calendar(){
super(“简易日历”);//窗口名字
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//窗口关闭函数
this.setBounds(100,100,800,600);//窗口尺寸 和位置
Container c=getContentPane();
p1 = new JPanel();//建立新面板
p0 = new JPanel();
p2 = new JPanel(new GridLayout(7,7,10,1));//设置网格布局
p4 = new JPanel(new GridLayout(7,20,10,1));
final JScrollPane p3 = new JScrollPane(p0);//将面板p0导入滚动面板p3
this.add(p3);
p3.setPreferredSize(new Dimension(100, 50));设置p3大小
label0=new JLabel(“
年份(如:2016)”);//标签赋值
label1=new JLabel(“
月份(如: 3)”);
label2=new JLabel(“");
label00=new JLabel(”
我国始有历法大约在四千多年以前。根据甲骨文中的一 页甲骨历,证明殷代的历法已具有相当的水平,这一页甲骨。历是全人类最古老的历书实物,这页甲骨历也就叫日历。但真正的日历产生,大约在一千一百多年前的唐顺宗永贞元年,皇宫中就已经使用皇历。最初一天一页,记载国家、宫廷大事和皇帝的言行。皇历分为十二册,每册的页数和每月的天数一样,每一页都注明了天数和日期。发展到后来,就把月日、于支、节令等内容事先写在上面,下部空白处留待记事,和现在的“台历”相似。那时,服侍皇帝的太监在日历空白处记下皇帝的言行,到了月终,皇帝审查证明无误后,送交史官存档,这在当时叫日历,这些日.历以后就作为史官编写《国史》的依据。后来,朝廷大臣们纷纷仿效,编制自家使用的日历。至于月历以后又发展成挂历、台历等各种形式,只是近一个世纪的事。随着时代的发展,·尽管日历的品种增多、花样也不断翻新,但仍旧保持着古老日历的格局。“);
label4=new JLabel(”
信息工程27班项明钧“);
JLabel label5 = new JLabel(new ImageIcon(”E:/timg.jpg“));
//从本地文件夹导入图片
label4.setFont(new Font(”宋体“, Font.BOLD, 20));
//设置字体大小
t0=new JTextField(5);//文本框
t1=new JTextField(3);
btn1=new JButton(”search“);//按钮
int i;
//日历面板分块函数
for(i=0;i<7;i++)
p2.add(ai[i]=new JLabel(ast[i]));
//将星期日到星期六赋给第一行
for(i= 7;i < 49;i++)
p2.add(ai[i]=new JLabel(”“));
//定义为空,为填入日期做准备
p1.add(label0);
p1.add(t0);
p1.add(label1);
//将标签导入面板
p1.add(t1);
p1.add(btn1);
p1.add(label2);
p0.add(label00);
p4.add(label5);
p4.add(label4);
c.add(p1,BorderLayout.NORTH);
//设置面板位置
c.add(p2,BorderLayout.CENTER);
c.add(p3,BorderLayout.SOUTH);
c.add(p4,BorderLayout.EAST);
btn1.addActionListener(this);
//注册监视器
t0.addActionListener(this);
t1.addActionListener(this);
p2.setBackground(Color.LIGHT_GRAY);
//设置面板背景颜色
p1.setBackground(Color.red);
p3.setBackground(Color.green);
p4.setBackground(Color.magenta);
this.setVisible(true);
//显示窗口
}
public static void main(String[] args)
//主函数
{
Calendar a=new Calendar();
a.showCalendar(2016,1);
//初始化日期2016年1月
}
//事件处理方法
public void actionPerformed(ActionEvent e){
if(e.getSource()== t0 || e.getSource()== t1 || e.getSource()== btn1)
{
Try
//控制输入的年份正确,异常控制
{
if(t0.getText().length()!= 4)
throw new NumberFormatException();
}
catch(NumberFormatException ex)
{
return;
}
String s1=t0.getText();
//获取输入年份
year=Integer.parseInt(s1);
//将输入年的字符串转换为int类型
String s2=t1.getText();
//将输入月 的字符串转换为int类型
month=Integer.parseInt(s2);
showCalendar(year,month);
//调用网格日历显示函数
} }
public void showCalendar(int year,int month)
//定义网格日历显示函数
{
int monthDay=getMonthDay(year,month);
//获取一个月几天
int startDay=getStartDay(year,month);
//获取一个月开始星期几
//显示当前窗口中显示日历的年月
String rr=”
当前日历“+”(“+Integer.toString(year)+”-“+Integer.toString(month)+”)“;
label2.setText(rr);
//控制各月日历的正确显示
int i;
} for(i= 7;i < startDay+7;i++)ai[i].setText(”“);for(i =startDay+7;i String bb;//存在意义:便于实现setText函数的带格式输入 if(i-startDay-6<10) bb=” “+Integer.toString(i-startDay-6);//将int型转换为String型 else bb=” “+Integer.toString(i-startDay-6); ai[i].setText(bb);} for(i=startDay + monthDay + 7;i<49;i++)ai[i].setText(”"); //leapYear:判断闰年 public static boolean leapYear(int year){ if((year % 400 == 0)||((year % 4 == 0)&&(year % 100!= 0))) return true;return false;} //getMonthDay获取每月总天数 public static int getMonthDay(int year, int month) { if(month == 1 || month==3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) return 31; if(month == 4 || month == 6 || month == 9 || month == 11) return 30; if(month == 2) if(leapYear(year)) //闰年二月29天 return 29; else return 28; return 0;//if month is incorrect.//如果月份输入错误返回0.} //getStartDay:返回每月第一天是周几 public static int getStartDay(int year,int month){ //从1800年1月1日开始 int startDay1800 = 3; long totalDays = getTotalDays(year, month); return(int)((totalDays + startDay1800)% 7);} //从1800年1月1日到所查月份的总天数 public static long getTotalDays(int year, int month){ long total = 0; for(int i = 1800;i < year;i++) if(leapYear(i)) total = total + 366; else total = total + 365; for(int i = 1;i < month;i++) total = total + getMonthDay(year, i); return total;} }