第一篇:北郵現場總線實驗報告
現場總線實驗報告
實驗名稱:
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;} }