第一篇:北郵數據結構實驗報告-排序
北京郵電大學 數據結構試驗報告
實驗名稱: 實驗四
排序 學生姓名:
班
級:
班內序號:
學
號:
日
期: 2014年1月4日
實驗目的
學習、實現、對比各種排序算法,掌握各種排序算法的優劣,以及各種算法使用的情況。實驗內容
2.1 題目1 使用簡單數組實現下面各種排序算法,并進行比較。排序算法:
1、插入排序
2、希爾排序
3、冒泡排序
4、快速排序
5、簡單選擇排序
6、堆排序(選作)
7、歸并排序(選作)
8、基數排序(選作)
9、其他
要求:
1、測試數據分成三類:正序、逆序、隨機數據
2、對于這三類數據,比較上述排序算法中關鍵字的比較次數和移動次數(其中關鍵字交換計為3次移動)。
3、對于這三類數據,比較上述排序算法中不同算法的執行時間,精確到微秒(選作)
4、對2和3的結果進行分析,驗證上述各種算法的時間復雜度
編寫測試main()函數測試線性表的正確性。程序分析
3.1 存儲結構
順序存儲結構——數組
3.2 關鍵算法分析
1.插入排序:依次將待排序的序列中的每一個記錄插入到先前排序好的序列中,直到全部記錄排序完畢
void Insertsort(int r[],int n,int* compare,int* move)//插入排序 {
*compare=0;*move=0;int i;int j;for(i=1;i
(*compare)++;
(*move)++;
r[j+1]=r[j];} if(j>=0)(*compare)++;r[j+1]=x;} } 2.希爾排序:先將整個序列分割成若干個子列,分別在各個子列中運用直接插入排序,待整個序列基本有序時,再對全體記錄進行一次直接插入排序 void ShellInsert(int r[],int n,int* compare,int* move)//希爾排序 {
*compare=0;*move=0;int j;10 9 12 12 20 20 31 for(int d=n/2;d>=1;d=d/2)//間距越來越小 { for(int i=d;i<=n-1;i++)//從a[d]往后逐個元素確定是否需要前移 { if(r[i] { int x=r[i]; for(j=i-d;(j>=0)&&(x { (*compare)++; (*move)++; r[j+d]=r[j]; } if(j>=0)(*compare)++; r[j+d]=x;} else(*compare)++;} } } 3.冒泡排序:兩兩比較相鄰記錄的關鍵碼,如果反序則交換,直到沒有反序記錄為止 void Bubblesort(int r[],int n,int* compare,int* move)//交換(冒泡)排序 { *compare=0;*move=0;int x;for(int j=0;j for(int i=n-1;i>j;i--) { if(r[i] { (*compare)++; (*move)+=3; x=r[i]; r[i]=r[i-1]; r[i-1]=x; } else(*compare)++; } } } 4.快速排序:首先選擇一個基準,將記錄分割為兩部分,左支小于或等于基準,右支則大于基準,然后對兩部分重復上述過程,直至整個序列排序完成 int Partion(int r[],int first,int end,int* compare,int* move)//快速排序中的軸定位 { int i=first;int j=end;int zhou=r[i];//默認第一個元素為軸 while(i { (*compare)++; j--;} if(i r[i]=r[j];//發現軸右側的某數比軸值小,將其前置 } while((i (*compare)++; (*move)++; r[j]=r[i];//發現軸左側的某數比軸值小,將其后置 } } r[i]=zhou;//最后確定軸的位置 return i;} void Qsort(int r[],int i,int j,int* compare,int* move)//快速排序 { if(i int min=i; for(int j=i+1;j { (*compare)++; if(r[j] min=j;//記錄下當前找到的最小值的位置 } if(min!=i) {(*move)+=3; int Min; Min=r[min]; r[min]=r[i]; r[i]=Min; } } } 程序運行結果 4.1主函數流程圖 4.2程序運行框圖 實驗心得 1.調試時出現的問題及解決的方法 在初期構思代碼的時候,首先構造了各種算法的基本實現代碼,封裝成類,已經能夠實現七種排序的基本功能,并且測試無誤。 之后考慮如何能簡化代碼以實現多達七種排序算法的簡單調用、亂序和順序以及逆序數據的分別排序和性能指標統計(算法移動次數和比較次數的精確統計)。2.心得體會 程序的優化是一個艱辛的過程,如果只是實現一般的功能,將變得容易很多,當加上優化,不論是效率還是結構優化,都需要精心設計。3.改進 本程序代碼設計時運用了遞歸的調用方式,效率還可以通過將其轉換為棧模擬的方式得以提高。另外還可以進一步考慮算法時間的精確統計,以便從時間角度比較這幾種排序算法的優劣。 完整源代碼 #include void Insertsort(int r[],int n,int* compare,int* move);void ShellInsert(int r[],int n,int* compare,int* move);void Bubblesort(int r[],int n,int* compare,int* move);int Partion(int r[],int first,int end,int* compare,int* move);void Qsort(int r[],int i,int j,int* compare,int* move);void Selectsort(int r[],int n,int* compare,int* move); void Insertsort(int r[],int n,int* compare,int* move)//插入排序 { *compare=0; { } } void ShellInsert(int r[],int n,int* compare,int* move)//希爾排序 { int x=r[i];for(j=i-1;x } if(j>=0)(*compare)++;r[j+1]=x;(*move)++;r[j+1]=r[j];*move=0;int i;int j;for(i=1;i (*compare)++; *compare=0; { for(int i=d;i<=n-1;i++)//從a[d]往后逐個元素確定是否需要前移 { } } } void Bubblesort(int r[],int n,int* compare,int* move)//交換(冒泡)排序 { { for(int i=n-1;i>j;i--) { if(r[i] { (*compare)++; (*move)+=3;*compare=0;*move=0;int x;if(r[i] int x=r[i]; for(j=i-d;(j>=0)&&(x }(*compare)++;(*compare)++;(*move)++;r[j+d]=r[j];*move=0;int j;for(int d=n/2;d>=1;d=d/2)//間距越來越小 if(j>=0) r[j+d]=x;} else(*compare)++;for(int j=0;j x=r[i]; r[i]=r[i-1]; r[i-1]=x; } } else(*compare)++; } } int Partion(int r[],int first,int end,int* compare,int* move)//快速排序中的軸定位 { int i=first;int j=end;int zhou=r[i];//默認第一個元素為軸 while(i { } if(i } if(i r[i]=r[j];//發現軸右側的某數比軸值小,將其前置 (*move)++; r[j]=r[i];//發現軸左側的某數比軸值小,將其后置 } } r[i]=zhou;//最后確定軸的位置 return i;} void Qsort(int r[],int i,int j,int* compare,int* move)//快速排序 { if(i void Selectsort(int r[],int n,int* compare,int* move)//選擇排序 { { int min=i; for(int j=i+1;j { (*compare)++; if(r[j] min=j;//記錄下當前找到的最小值的位置 } if(min!=i) {(*move)+=3; int Min; Min=r[min]; r[min]=r[i]; r[i]=Min; } } } void main(){ int i;int compare=0;int move=0;cout<<“請您先輸入一個正序數組哦”< cout<<“再輸入一個逆序數組~~~”< cout<<“最后輸入一個亂序數組~~~”< 北京郵電大學 數據結構試驗報告 實驗名稱: 實驗一 線性表 學生姓名: 班 級: 班內序號: 學 號: 日 期: 2014年1月3日 實驗目的 ? 熟悉C++語言的基本編程方法,掌握集成編譯環境的調試方法 ? 學習指針、模板類、異常處理的使用 ? 掌握線性表的操作的實現方法 ? 學習使用線性表解決實際問題的能力 實驗內容 2.1題目1 根據線性表的抽象數據類型的定義,選擇下面任一種鏈式結構實現線性表,并完成線性表的基本功能。 線性表存儲結構(五選一): 1、帶頭結點的單鏈表 2、不帶頭結點的單鏈表 3、循環鏈表 4、雙鏈表 5、靜態鏈表 線性表的基本功能: 1、構造:使用頭插法、尾插法兩種方法 2、插入:要求建立的鏈表按照關鍵字從小到大有序 3、刪除 4、查找 5、獲取鏈表長度 6、銷毀 7、其他:可自行定義 編寫測試main()函數測試線性表的正確性。程序分析 3.1 存儲結構 單鏈表的存儲結構: 3.2 關鍵算法分析 一、關鍵算法 1.頭插法 自然語言描述:a.在堆中建立新結點 b.將a[i]寫入到新結點的數據域 c.修改新結點的指針域 d.修改頭結點的指針域,將新結點加入鏈表中 代碼描述: template front = new Node } } s->next = front->next;front->next = s;時間復雜度:O(n) 2.尾插法 自然語言描述:a.在堆中建立新結點 b.將a[i]寫入到新結點的數據域 c.將新結點加入到鏈表中 d.修改修改尾指針 代碼描述: template front = new Node } } s->data = a[i];s->next = r->next;r->next= s;r=s;時間復雜度:O(n) 3.析構函數 自然語言描述:a.新建立一個指針,指向頭結點 b.移動a中建立的指針 c.逐個釋放指針 代碼描述: template Node } } delete front;4.按位查找函數 自然語言描述: a.初始化工作指針p和計數器j,p指向第一個結點,j=1 b.循環以下操作,直到p為空或者j等于1 b1:p指向下一個結點 b2:j加1 c.若p為空,說明第i個元素不存在,拋出異常 d.否則,說明p指向的元素就是所查找的元素,返回元素地址 代碼描述: template Node if(j } else break;p = p->next;j++; } if(!p)throw“查找位置非法”;else return p;} 時間復雜度:O(n) 5.按值查找函數 自然語言描述:a.初始化工作指針p和計數器j,p指向第一個結點,j=1 b.循環以下操作,找到這個元素或者p指向最后一個結點 b1.判斷p指向的結點是不是要查找的值,如果是,返回j; b2.否則p指向下一個結點,并且j的值加一 c.如果找到最后一個結點還沒有找到要查找的元素,返回查找失敗信息 代碼描述: template Node } return-1;if(p->data == x)return j;else { p = p->next; j++;} } 時間復雜度:O(n)6.插入函數 自然語言描述: a.在堆中建立新結點 b.將要插入的結點的數據寫入到新結點的數據域 c.修改新結點的指針域 d.修改前一個指針的指針域,使其指向新插入的結點的位置 代碼描述: template Node } else throw“插入位置非法”;Node 自然語言描述:a.從第一個結點開始,查找要刪除的位數i前一個位置i-1的結點 b.設q指向第i個元素 c.將q元素從鏈表中刪除 d.保存q元素的數據 e.釋放q元素 代碼描述: template T x=q->data; } p->next = q->next;delete q;return x; 8.遍歷打印函數 自然語言描述: a.判斷該鏈表是否為空鏈表,如果是,報錯 b.如果不是空鏈表,新建立一個temp指針 c.將temp指針指向頭結點 d.打印temp指針的data域 e.逐個往后移動temp指針,直到temp指針的指向的指針的next域為空 代碼描述: template } Node } cout< 自然語言描述: a.判斷該鏈表是否為空鏈表,如果是,輸出長度0 b.如果不是空鏈表,新建立一個temp指針,初始化整形數n為0 c.將temp指針指向頭結點 d.判斷temp指針指向的結點的next域是否為空,如果不是,n加一,否則return n e.使temp指針逐個后移,重復d操作,直到temp指針指向的結點的next域為0,返回n 代碼描述: template } Node } return i-1;p = p->next;i++;4 程序運行結果 4.1主函數流程圖 4.2程序運行框圖 實驗心得 1.調試時出現的問題及解決的方法 在編寫按值查找函數時,由于沒有處理好指針類型的原因,導致指針無法正常返回,屢屢報錯。最后意識到c++沒有指針強制類型的轉換機制,經過細致檢查后才改正錯誤使得程序正常運行。2.心得體會 了解了單鏈表的基本的操作函數實現,對鏈式存儲結構有了較好的認識 3.下一步的改進 可以增加完善報錯機制,增強程序的健壯性 完整源代碼 #include template }; template }; //template Node template } template } template } front = p;p = p->next;delete front;front = new Node } Node } Node } Node } cout< template } template } Node } return-1;if(p->data == x)return j;else { } p = p->next; j++;Node } if(!p)throw“查找位置非法”;else return p;if(j } else break;p = p->next;j++; template } template } template } void main(){ Node } return i-1;p = p->next;i++;Node } else throw“插入位置非法”;Node T x=q->data; } int n;cout<<“將要輸入的鏈表長度為:”;cin>>n;int *b=new int[n];cout<<“輸入鏈表中的元素:”;for(int k=0;k 《數據結構》實驗報告 排序 實驗題目: 輸入十個數,從插入排序,快速排序,選擇排序三類算法中各選一種編程實現。 實驗所使用的數據結構內容及編程思路: 1.插入排序:直接插入排序的基本操作是,將一個記錄到已排好序的有序表中,從而得到一個新的,記錄增一得有序表。 一般情況下,第i趟直接插入排序的操作為:在含有i-1個記錄的有序子序列r[1..i-1]中插入一個記錄r[i]后,變成含有i個記錄的有序子序列r[1..i];并且,和順序查找類似,為了在查找插入位置的過程中避免數組下標出界,在 r[0]處設置哨兵。在自i-1起往前搜索的過程中,可以同時后移記錄。整個排序過程為進行n-1趟插入,即:先將序列中的第一個記錄看成是一個有序的子序列,然后從第2個記錄起逐個進行插入,直至整個序列變成按關鍵字非遞減有序序列為止。 2.快速排序:基本思想是,通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。 假設待排序的序列為{L.r[s],L.r[s+1],?L.r[t]},首先任意選取一個記錄(通常可選第一個記錄L.r[s])作為樞軸(或支點)(pivot),然后按下述原則重新排列其余記錄:將所有關鍵字較它小的記錄都安置在它的位置之前,將所有關鍵字較大的記錄都安置在它的位置之后。由此可以該“樞軸”記錄最后所羅的位置i作為界線,將序列{L.r[s],?,L.r[t]}分割成兩個子序列{L.r[i+1],L.[i+2],?,L.r[t]}。這個過程稱為一趟快速排序,或一次劃分。 一趟快速排序的具體做法是:附設兩個指針low和high,他們的初值分別為low和high,設樞軸記錄的關鍵字為pivotkey,則首先從high所指位置起向前搜索找到第一個關鍵字小于pivotkey的記錄和樞軸記錄互相交換,然后從low所指位置起向后搜索,找到第一個關鍵字大于pivotkey的記錄和樞軸記錄互相 1 交換,重復這兩不直至low=high為止。 具體實現上述算法是,每交換一對記錄需進行3次記錄移動(賦值)的操作。而實際上,在排列過程中對樞軸記錄的賦值是多余的,因為只有在一趟排序結束時,即low=high的位置才是樞軸記錄的最后位置。由此可以先將樞軸記錄暫存在r[0]的位置上,排序過程中只作r[low]或r[high]的單向移動,直至一趟排序結束后再將樞軸記錄移至正確位置上。 整個快速排序的過程可遞歸進行。若待排序列中只有一個記錄,顯然已有序,否則進行一趟快速排序后再分別對分割所得的兩個子序列進行快速排序。 3.簡單選擇排序:其操作為,通過n-i次關鍵字間的比較,從n-i+1個記錄中選出關鍵字最小的記錄,并和第i(1≤i≤n)個記錄交換之。 顯然,對L.r[1?n]中的記錄進行簡單選擇排序的算法為:令i從1至n-1,進行n-1趟選擇操作。可以看出,簡單選擇排序過程中,所需進行記錄移動的操作次數較少,其最小值為“0”,最大值為3(n-1)。然后,無論記錄的初始排列如何,所需進行的關鍵字之間的比較次數相同,均為n(n-1)/2。 程序清單: 1.插入排序: #include for(i=1;i<=num.length;i++)printf(“%d ”,num.key[i]);} 測試用例: 輸入:23 34 12 98 56 45 67 8 9 37 輸出:charu:8 9 12 23 34 37 45 56 67 98 2快速排序: #include for(i=1;i<=num.length;i++)printf(“%d ”,num.key[i]);} 測試用例: 輸入:23 34 12 98 56 45 67 8 9 37 輸出:charu:8 9 12 23 34 37 45 56 67 98 3選擇排序: #include intselectminkey(structsqlist *l,int a){ inti,j=a;for(i=a;i<=l->length;i++)if(l->key[i] for(i=1;i<=num.length;i++)printf(“%d ”,num.key[i]);} 測試用例: 輸入:23 34 12 98 56 45 67 8 9 37 輸出:charu:8 9 12 23 34 37 45 56 67 98 編程感想: 本次編程總共使用了三種排序方法,而這三種編程方法放在一起進行編寫時,很容易就讓我們對齊難易程度有了更深刻的了解。 首先,三種排序中,我們都像查表那樣,設置了哨兵,而哨兵的使用可以減少對整個表的驗空操作,使程序更加節省空間。 其次,對于插入排序,每次都要對一段序列進行檢索,每排一次所要檢索的序列長度減一,其時間發雜度為O(n^2)。 接著,對于快速排序,這個程序是比較復雜的,總共是3個函數,并且使用了遞歸的方法,這是但是,這種算法卻是最優越的,平均性能也是最好的,我在編這個程序時,對其排序的思想有了進一步的了解,并努力拿他與冒泡排序進行比較,看出了些許其優越性。 還有,就是選擇排序,簡單選擇排序思路簡單,易于進行,但其時間發雜度與簡單插入排序方法一樣,都是O(n^2),性能不如快速排序。 最后,本次試驗是數據結構課的最后一次實驗,經過數據結構試驗課的鍛煉,使我對數據結構有了更深刻的理解,對我對其知識起到了重要的影響,增加了我編程的實踐活動,為我將來進一步學習打下了基礎。 一、實驗目的 1、了解內排序都是在內存中進行的。 2、為了提高數據的查找速度,需要對數據進行排序。 3、掌握內排序的方法。 二、實驗內容 1、設計一個程序exp10—1.cpp實現直接插入排序算法,并輸出{9,8,7,6,5,4,3,2,1,0}的排序過程。 (1)源程序如下所示: //文件名:exp10-1.cpp #include //線性表中最多元素個數 typedef int KeyType;typedef char InfoType[10];typedef struct //記錄類型 { KeyType key; //關鍵字項 InfoType data;//其他數據項,類型為InfoType } RecType;void InsertSort(RecType R[],int n)//對R[0..n-1]按遞增有序進行直接插入排序 { int i,j,k;RecType temp;for(i=1;i { temp=R[i]; j=i-1; //從右向左在有序區R[0..i-1]中找R[i]的插入位置 while(j>=0 && temp.key { R[j+1]=R[j];//將關鍵字大于R[i].key的記錄后移 j--; } R[j+1]=temp; //在j+1處插入R[i] printf(“i=%d,”,i);//輸出每一趟的排序結果 printf(“插入%d,結果為: ”,temp); for(k=0;k printf(“%3d”,R[k].key); printf(“n”);} } void main(){ int i,k,n=10; KeyType a[]={9,8,7,6,5,4,3,2,1,0};RecType R[MAXE];for(i=0;i R[i].key=a[i];printf(“初始關鍵字: ”);//輸出初始關鍵字序列 for(k=0;k printf(“%3d”,R[k].key);printf(“n”);InsertSort(R,n);printf(“最后結果: ”);//輸出初始關鍵字序列 for(k=0;k printf(“%3d”,R[k].key);printf(“n”);}(2)運行的結果如下圖所示: 2、設計一個程序exp10—2.cpp實現希爾插入排序算法,并輸出{9,8,7,6,5,4,3,2,1,0}的排序過程。 (1)源程序如下所示: //文件名:exp10-2.cpp #include //線性表中最多元素個數 typedef int KeyType;typedef char InfoType[10];typedef struct //記錄類型 { KeyType key;//關鍵字項 InfoType data;//其他數據項,類型為InfoType } RecType;void ShellSort(RecType R[],int n)//希爾排序算法 { int i,j,d,k;RecType temp;d=n/2; //d取初值n/2 while(d>0) { for(i=d;i { j=i-d; while(j>=0 && R[j].key>R[j+d].key) { temp=R[j]; //R[j]與R[j+d]交換 R[j]=R[j+d]; R[j+d]=temp; j=j-d; } } printf(“d=%d: ”,d);//輸出每一趟的排序結果 for(k=0;k printf(“%3d”,R[k].key); printf(“n”); d=d/2; //遞減增量d } } void main(){ int i,k,n=10;KeyType a[]={9,8,7,6,5,4,3,2,1,0};RecType R[MAXE];for(i=0;i R[i].key=a[i];printf(“初始關鍵字: ”);//輸出初始關鍵字序列 for(k=0;k printf(“%3d”,R[k].key);printf(“n”);ShellSort(R,n);printf(“最后結果: ”); //輸出初始關鍵字序列 for(k=0;k printf(“%3d”,R[k].key);printf(“nn”);}(2)結果如下圖所示: 3、設計一個程序exp10—3.cpp實現冒泡排序算法,并輸出{9,8,7,6,5,4,3,2,1,0}的排序過程。 (1)源程序如下所示: //文件名:exp10-3.cpp #include //線性表中最多元素個數 typedef int KeyType;typedef char InfoType[10];typedef struct //記錄類型 { KeyType key; //關鍵字項 InfoType data; //其他數據項,類型為InfoType } RecType;void BubbleSort(RecType R[],int n)//冒泡排序算法 { int i,j,k;RecType temp;for(i=0;i { for(j=n-1;j>i;j--)//比較,找出本趟最小關鍵字的記錄 if(R[j].key { temp=R[j];//R[j]與R[j-1]進行交換,將最小關鍵字記錄前移 R[j]=R[j-1]; R[j-1]=temp; } printf(“i=%d,冒出的最小關鍵字:%d,結果為: ”,i,R[i].key);//輸出每一趟的排序結果 for(k=0;k printf(“%2d”,R[k].key); printf(“n”);} } void main(){ int i,k,n=10;KeyType a[]={9,8,7,6,5,4,3,2,1,0};RecType R[MAXE];for(i=0;i R[i].key=a[i];printf(“初始關鍵字: ”);//輸出初始關鍵字序列 for(k=0;k printf(“%2d”,R[k].key);printf(“n”);BubbleSort(R,n);printf(“最后結果: ”);//輸出初始關鍵字序列 for(k=0;k printf(“%2d”,R[k].key);printf(“n”);}(2)結果如下圖所示: 北京郵電大學 嵌入式系統開發實驗報告 學院: 班級: 姓名: 學號: 序號: 目錄 一、實驗目的..............................................................................................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函數、打開、關閉以及函數模塊的初始化并且在超級終端上顯示出等。但所不同的是,要根據不同的實驗要求修改名稱,并且對其中必要的部分進行修改。 除此之外,我認為很多基礎知識對實驗的進行也起著非常大的作用,例如數碼管的顯示原理。在掌握了基礎知識之后,上機的過程會顯得相對簡單,尤其是代碼框架已經給出,我們所以需要做的就是根據需要稍作改動來得到我們想要的結果。 在實驗過程中常常會遇到各種各樣的問題,剛開始時我不知如何是好,只能求助于老師和同學,后來隨著實驗的進行,我對實驗的內容和虛擬機都有了一定的了解,遇到問題時也可以靜下心來思考其原因,自己嘗試各種方法去解決問題。整個實驗讓我了解了一套完整的嵌入式系統驅動程序開發的全過程,學到的內容非常豐富,相信在學習了這些內容后,在今后的學習工作中接觸到類似內容,我不會感到無從下手,而是能夠有條不紊。 感謝老師的辛勤指導!第二篇:北郵數據結構實驗報告 單鏈表
第三篇:《數據結構》實驗報告——排序
第四篇:數據結構內排序實驗報告
第五篇:北郵嵌入式實驗報告